162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// core.c -- Voltage/Current Regulator framework. 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright 2007, 2008 Wolfson Microelectronics PLC. 662306a36Sopenharmony_ci// Copyright 2008 SlimLogic Ltd. 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Author: Liam Girdwood <lrg@slimlogic.co.uk> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/debugfs.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/async.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/mutex.h> 1862306a36Sopenharmony_ci#include <linux/suspend.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 2162306a36Sopenharmony_ci#include <linux/of.h> 2262306a36Sopenharmony_ci#include <linux/regmap.h> 2362306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 2462306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2562306a36Sopenharmony_ci#include <linux/regulator/coupler.h> 2662306a36Sopenharmony_ci#include <linux/regulator/driver.h> 2762306a36Sopenharmony_ci#include <linux/regulator/machine.h> 2862306a36Sopenharmony_ci#include <linux/module.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 3162306a36Sopenharmony_ci#include <trace/events/regulator.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "dummy.h" 3462306a36Sopenharmony_ci#include "internal.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic DEFINE_WW_CLASS(regulator_ww_class); 3762306a36Sopenharmony_cistatic DEFINE_MUTEX(regulator_nesting_mutex); 3862306a36Sopenharmony_cistatic DEFINE_MUTEX(regulator_list_mutex); 3962306a36Sopenharmony_cistatic LIST_HEAD(regulator_map_list); 4062306a36Sopenharmony_cistatic LIST_HEAD(regulator_ena_gpio_list); 4162306a36Sopenharmony_cistatic LIST_HEAD(regulator_supply_alias_list); 4262306a36Sopenharmony_cistatic LIST_HEAD(regulator_coupler_list); 4362306a36Sopenharmony_cistatic bool has_full_constraints; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct dentry *debugfs_root; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * struct regulator_map 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Used to provide symbolic supply names to devices. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_cistruct regulator_map { 5362306a36Sopenharmony_ci struct list_head list; 5462306a36Sopenharmony_ci const char *dev_name; /* The dev_name() for the consumer */ 5562306a36Sopenharmony_ci const char *supply; 5662306a36Sopenharmony_ci struct regulator_dev *regulator; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* 6062306a36Sopenharmony_ci * struct regulator_enable_gpio 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * Management for shared enable GPIO pin 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistruct regulator_enable_gpio { 6562306a36Sopenharmony_ci struct list_head list; 6662306a36Sopenharmony_ci struct gpio_desc *gpiod; 6762306a36Sopenharmony_ci u32 enable_count; /* a number of enabled shared GPIO */ 6862306a36Sopenharmony_ci u32 request_count; /* a number of requested shared GPIO */ 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * struct regulator_supply_alias 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * Used to map lookups for a supply onto an alternative device. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_cistruct regulator_supply_alias { 7762306a36Sopenharmony_ci struct list_head list; 7862306a36Sopenharmony_ci struct device *src_dev; 7962306a36Sopenharmony_ci const char *src_supply; 8062306a36Sopenharmony_ci struct device *alias_dev; 8162306a36Sopenharmony_ci const char *alias_supply; 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int _regulator_is_enabled(struct regulator_dev *rdev); 8562306a36Sopenharmony_cistatic int _regulator_disable(struct regulator *regulator); 8662306a36Sopenharmony_cistatic int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags); 8762306a36Sopenharmony_cistatic int _regulator_get_current_limit(struct regulator_dev *rdev); 8862306a36Sopenharmony_cistatic unsigned int _regulator_get_mode(struct regulator_dev *rdev); 8962306a36Sopenharmony_cistatic int _notifier_call_chain(struct regulator_dev *rdev, 9062306a36Sopenharmony_ci unsigned long event, void *data); 9162306a36Sopenharmony_cistatic int _regulator_do_set_voltage(struct regulator_dev *rdev, 9262306a36Sopenharmony_ci int min_uV, int max_uV); 9362306a36Sopenharmony_cistatic int regulator_balance_voltage(struct regulator_dev *rdev, 9462306a36Sopenharmony_ci suspend_state_t state); 9562306a36Sopenharmony_cistatic struct regulator *create_regulator(struct regulator_dev *rdev, 9662306a36Sopenharmony_ci struct device *dev, 9762306a36Sopenharmony_ci const char *supply_name); 9862306a36Sopenharmony_cistatic void destroy_regulator(struct regulator *regulator); 9962306a36Sopenharmony_cistatic void _regulator_put(struct regulator *regulator); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciconst char *rdev_get_name(struct regulator_dev *rdev) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci if (rdev->constraints && rdev->constraints->name) 10462306a36Sopenharmony_ci return rdev->constraints->name; 10562306a36Sopenharmony_ci else if (rdev->desc->name) 10662306a36Sopenharmony_ci return rdev->desc->name; 10762306a36Sopenharmony_ci else 10862306a36Sopenharmony_ci return ""; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_name); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic bool have_full_constraints(void) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci return has_full_constraints || of_have_populated_dt(); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci if (!rdev->constraints) { 12062306a36Sopenharmony_ci rdev_err(rdev, "no constraints\n"); 12162306a36Sopenharmony_ci return false; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (rdev->constraints->valid_ops_mask & ops) 12562306a36Sopenharmony_ci return true; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return false; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/** 13162306a36Sopenharmony_ci * regulator_lock_nested - lock a single regulator 13262306a36Sopenharmony_ci * @rdev: regulator source 13362306a36Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * This function can be called many times by one task on 13662306a36Sopenharmony_ci * a single regulator and its mutex will be locked only 13762306a36Sopenharmony_ci * once. If a task, which is calling this function is other 13862306a36Sopenharmony_ci * than the one, which initially locked the mutex, it will 13962306a36Sopenharmony_ci * wait on mutex. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_cistatic inline int regulator_lock_nested(struct regulator_dev *rdev, 14262306a36Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci bool lock = false; 14562306a36Sopenharmony_ci int ret = 0; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci mutex_lock(®ulator_nesting_mutex); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (!ww_mutex_trylock(&rdev->mutex, ww_ctx)) { 15062306a36Sopenharmony_ci if (rdev->mutex_owner == current) 15162306a36Sopenharmony_ci rdev->ref_cnt++; 15262306a36Sopenharmony_ci else 15362306a36Sopenharmony_ci lock = true; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (lock) { 15662306a36Sopenharmony_ci mutex_unlock(®ulator_nesting_mutex); 15762306a36Sopenharmony_ci ret = ww_mutex_lock(&rdev->mutex, ww_ctx); 15862306a36Sopenharmony_ci mutex_lock(®ulator_nesting_mutex); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci } else { 16162306a36Sopenharmony_ci lock = true; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (lock && ret != -EDEADLK) { 16562306a36Sopenharmony_ci rdev->ref_cnt++; 16662306a36Sopenharmony_ci rdev->mutex_owner = current; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci mutex_unlock(®ulator_nesting_mutex); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return ret; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/** 17562306a36Sopenharmony_ci * regulator_lock - lock a single regulator 17662306a36Sopenharmony_ci * @rdev: regulator source 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * This function can be called many times by one task on 17962306a36Sopenharmony_ci * a single regulator and its mutex will be locked only 18062306a36Sopenharmony_ci * once. If a task, which is calling this function is other 18162306a36Sopenharmony_ci * than the one, which initially locked the mutex, it will 18262306a36Sopenharmony_ci * wait on mutex. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_cistatic void regulator_lock(struct regulator_dev *rdev) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci regulator_lock_nested(rdev, NULL); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * regulator_unlock - unlock a single regulator 19162306a36Sopenharmony_ci * @rdev: regulator_source 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * This function unlocks the mutex when the 19462306a36Sopenharmony_ci * reference counter reaches 0. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_cistatic void regulator_unlock(struct regulator_dev *rdev) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci mutex_lock(®ulator_nesting_mutex); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (--rdev->ref_cnt == 0) { 20162306a36Sopenharmony_ci rdev->mutex_owner = NULL; 20262306a36Sopenharmony_ci ww_mutex_unlock(&rdev->mutex); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci WARN_ON_ONCE(rdev->ref_cnt < 0); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci mutex_unlock(®ulator_nesting_mutex); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/** 21162306a36Sopenharmony_ci * regulator_lock_two - lock two regulators 21262306a36Sopenharmony_ci * @rdev1: first regulator 21362306a36Sopenharmony_ci * @rdev2: second regulator 21462306a36Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * Locks both rdevs using the regulator_ww_class. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_cistatic void regulator_lock_two(struct regulator_dev *rdev1, 21962306a36Sopenharmony_ci struct regulator_dev *rdev2, 22062306a36Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct regulator_dev *held, *contended; 22362306a36Sopenharmony_ci int ret; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ww_acquire_init(ww_ctx, ®ulator_ww_class); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Try to just grab both of them */ 22862306a36Sopenharmony_ci ret = regulator_lock_nested(rdev1, ww_ctx); 22962306a36Sopenharmony_ci WARN_ON(ret); 23062306a36Sopenharmony_ci ret = regulator_lock_nested(rdev2, ww_ctx); 23162306a36Sopenharmony_ci if (ret != -EDEADLOCK) { 23262306a36Sopenharmony_ci WARN_ON(ret); 23362306a36Sopenharmony_ci goto exit; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci held = rdev1; 23762306a36Sopenharmony_ci contended = rdev2; 23862306a36Sopenharmony_ci while (true) { 23962306a36Sopenharmony_ci regulator_unlock(held); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ww_mutex_lock_slow(&contended->mutex, ww_ctx); 24262306a36Sopenharmony_ci contended->ref_cnt++; 24362306a36Sopenharmony_ci contended->mutex_owner = current; 24462306a36Sopenharmony_ci swap(held, contended); 24562306a36Sopenharmony_ci ret = regulator_lock_nested(contended, ww_ctx); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (ret != -EDEADLOCK) { 24862306a36Sopenharmony_ci WARN_ON(ret); 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciexit: 25462306a36Sopenharmony_ci ww_acquire_done(ww_ctx); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * regulator_unlock_two - unlock two regulators 25962306a36Sopenharmony_ci * @rdev1: first regulator 26062306a36Sopenharmony_ci * @rdev2: second regulator 26162306a36Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * The inverse of regulator_lock_two(). 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic void regulator_unlock_two(struct regulator_dev *rdev1, 26762306a36Sopenharmony_ci struct regulator_dev *rdev2, 26862306a36Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci regulator_unlock(rdev2); 27162306a36Sopenharmony_ci regulator_unlock(rdev1); 27262306a36Sopenharmony_ci ww_acquire_fini(ww_ctx); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic bool regulator_supply_is_couple(struct regulator_dev *rdev) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct regulator_dev *c_rdev; 27862306a36Sopenharmony_ci int i; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci for (i = 1; i < rdev->coupling_desc.n_coupled; i++) { 28162306a36Sopenharmony_ci c_rdev = rdev->coupling_desc.coupled_rdevs[i]; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (rdev->supply->rdev == c_rdev) 28462306a36Sopenharmony_ci return true; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return false; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void regulator_unlock_recursive(struct regulator_dev *rdev, 29162306a36Sopenharmony_ci unsigned int n_coupled) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct regulator_dev *c_rdev, *supply_rdev; 29462306a36Sopenharmony_ci int i, supply_n_coupled; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci for (i = n_coupled; i > 0; i--) { 29762306a36Sopenharmony_ci c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1]; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (!c_rdev) 30062306a36Sopenharmony_ci continue; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) { 30362306a36Sopenharmony_ci supply_rdev = c_rdev->supply->rdev; 30462306a36Sopenharmony_ci supply_n_coupled = supply_rdev->coupling_desc.n_coupled; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci regulator_unlock_recursive(supply_rdev, 30762306a36Sopenharmony_ci supply_n_coupled); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci regulator_unlock(c_rdev); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int regulator_lock_recursive(struct regulator_dev *rdev, 31562306a36Sopenharmony_ci struct regulator_dev **new_contended_rdev, 31662306a36Sopenharmony_ci struct regulator_dev **old_contended_rdev, 31762306a36Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct regulator_dev *c_rdev; 32062306a36Sopenharmony_ci int i, err; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for (i = 0; i < rdev->coupling_desc.n_coupled; i++) { 32362306a36Sopenharmony_ci c_rdev = rdev->coupling_desc.coupled_rdevs[i]; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (!c_rdev) 32662306a36Sopenharmony_ci continue; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (c_rdev != *old_contended_rdev) { 32962306a36Sopenharmony_ci err = regulator_lock_nested(c_rdev, ww_ctx); 33062306a36Sopenharmony_ci if (err) { 33162306a36Sopenharmony_ci if (err == -EDEADLK) { 33262306a36Sopenharmony_ci *new_contended_rdev = c_rdev; 33362306a36Sopenharmony_ci goto err_unlock; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* shouldn't happen */ 33762306a36Sopenharmony_ci WARN_ON_ONCE(err != -EALREADY); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci *old_contended_rdev = NULL; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) { 34462306a36Sopenharmony_ci err = regulator_lock_recursive(c_rdev->supply->rdev, 34562306a36Sopenharmony_ci new_contended_rdev, 34662306a36Sopenharmony_ci old_contended_rdev, 34762306a36Sopenharmony_ci ww_ctx); 34862306a36Sopenharmony_ci if (err) { 34962306a36Sopenharmony_ci regulator_unlock(c_rdev); 35062306a36Sopenharmony_ci goto err_unlock; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cierr_unlock: 35862306a36Sopenharmony_ci regulator_unlock_recursive(rdev, i); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return err; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci/** 36462306a36Sopenharmony_ci * regulator_unlock_dependent - unlock regulator's suppliers and coupled 36562306a36Sopenharmony_ci * regulators 36662306a36Sopenharmony_ci * @rdev: regulator source 36762306a36Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * Unlock all regulators related with rdev by coupling or supplying. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_cistatic void regulator_unlock_dependent(struct regulator_dev *rdev, 37262306a36Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci regulator_unlock_recursive(rdev, rdev->coupling_desc.n_coupled); 37562306a36Sopenharmony_ci ww_acquire_fini(ww_ctx); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/** 37962306a36Sopenharmony_ci * regulator_lock_dependent - lock regulator's suppliers and coupled regulators 38062306a36Sopenharmony_ci * @rdev: regulator source 38162306a36Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 38262306a36Sopenharmony_ci * 38362306a36Sopenharmony_ci * This function as a wrapper on regulator_lock_recursive(), which locks 38462306a36Sopenharmony_ci * all regulators related with rdev by coupling or supplying. 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_cistatic void regulator_lock_dependent(struct regulator_dev *rdev, 38762306a36Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct regulator_dev *new_contended_rdev = NULL; 39062306a36Sopenharmony_ci struct regulator_dev *old_contended_rdev = NULL; 39162306a36Sopenharmony_ci int err; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci ww_acquire_init(ww_ctx, ®ulator_ww_class); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci do { 39862306a36Sopenharmony_ci if (new_contended_rdev) { 39962306a36Sopenharmony_ci ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx); 40062306a36Sopenharmony_ci old_contended_rdev = new_contended_rdev; 40162306a36Sopenharmony_ci old_contended_rdev->ref_cnt++; 40262306a36Sopenharmony_ci old_contended_rdev->mutex_owner = current; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci err = regulator_lock_recursive(rdev, 40662306a36Sopenharmony_ci &new_contended_rdev, 40762306a36Sopenharmony_ci &old_contended_rdev, 40862306a36Sopenharmony_ci ww_ctx); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (old_contended_rdev) 41162306a36Sopenharmony_ci regulator_unlock(old_contended_rdev); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci } while (err == -EDEADLK); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci ww_acquire_done(ww_ctx); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/** 42162306a36Sopenharmony_ci * of_get_child_regulator - get a child regulator device node 42262306a36Sopenharmony_ci * based on supply name 42362306a36Sopenharmony_ci * @parent: Parent device node 42462306a36Sopenharmony_ci * @prop_name: Combination regulator supply name and "-supply" 42562306a36Sopenharmony_ci * 42662306a36Sopenharmony_ci * Traverse all child nodes. 42762306a36Sopenharmony_ci * Extract the child regulator device node corresponding to the supply name. 42862306a36Sopenharmony_ci * returns the device node corresponding to the regulator if found, else 42962306a36Sopenharmony_ci * returns NULL. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_cistatic struct device_node *of_get_child_regulator(struct device_node *parent, 43262306a36Sopenharmony_ci const char *prop_name) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct device_node *regnode = NULL; 43562306a36Sopenharmony_ci struct device_node *child = NULL; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci for_each_child_of_node(parent, child) { 43862306a36Sopenharmony_ci regnode = of_parse_phandle(child, prop_name, 0); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (!regnode) { 44162306a36Sopenharmony_ci regnode = of_get_child_regulator(child, prop_name); 44262306a36Sopenharmony_ci if (regnode) 44362306a36Sopenharmony_ci goto err_node_put; 44462306a36Sopenharmony_ci } else { 44562306a36Sopenharmony_ci goto err_node_put; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci return NULL; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cierr_node_put: 45162306a36Sopenharmony_ci of_node_put(child); 45262306a36Sopenharmony_ci return regnode; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci/** 45662306a36Sopenharmony_ci * of_get_regulator - get a regulator device node based on supply name 45762306a36Sopenharmony_ci * @dev: Device pointer for the consumer (of regulator) device 45862306a36Sopenharmony_ci * @supply: regulator supply name 45962306a36Sopenharmony_ci * 46062306a36Sopenharmony_ci * Extract the regulator device node corresponding to the supply name. 46162306a36Sopenharmony_ci * returns the device node corresponding to the regulator if found, else 46262306a36Sopenharmony_ci * returns NULL. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_cistatic struct device_node *of_get_regulator(struct device *dev, const char *supply) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct device_node *regnode = NULL; 46762306a36Sopenharmony_ci char prop_name[64]; /* 64 is max size of property name */ 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci dev_dbg(dev, "Looking up %s-supply from device tree\n", supply); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci snprintf(prop_name, 64, "%s-supply", supply); 47262306a36Sopenharmony_ci regnode = of_parse_phandle(dev->of_node, prop_name, 0); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!regnode) { 47562306a36Sopenharmony_ci regnode = of_get_child_regulator(dev->of_node, prop_name); 47662306a36Sopenharmony_ci if (regnode) 47762306a36Sopenharmony_ci return regnode; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci dev_dbg(dev, "Looking up %s property in node %pOF failed\n", 48062306a36Sopenharmony_ci prop_name, dev->of_node); 48162306a36Sopenharmony_ci return NULL; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci return regnode; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/* Platform voltage constraint check */ 48762306a36Sopenharmony_ciint regulator_check_voltage(struct regulator_dev *rdev, 48862306a36Sopenharmony_ci int *min_uV, int *max_uV) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci BUG_ON(*min_uV > *max_uV); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 49362306a36Sopenharmony_ci rdev_err(rdev, "voltage operation not allowed\n"); 49462306a36Sopenharmony_ci return -EPERM; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (*max_uV > rdev->constraints->max_uV) 49862306a36Sopenharmony_ci *max_uV = rdev->constraints->max_uV; 49962306a36Sopenharmony_ci if (*min_uV < rdev->constraints->min_uV) 50062306a36Sopenharmony_ci *min_uV = rdev->constraints->min_uV; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (*min_uV > *max_uV) { 50362306a36Sopenharmony_ci rdev_err(rdev, "unsupportable voltage range: %d-%duV\n", 50462306a36Sopenharmony_ci *min_uV, *max_uV); 50562306a36Sopenharmony_ci return -EINVAL; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return 0; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/* return 0 if the state is valid */ 51262306a36Sopenharmony_cistatic int regulator_check_states(suspend_state_t state) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci return (state > PM_SUSPEND_MAX || state == PM_SUSPEND_TO_IDLE); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/* Make sure we select a voltage that suits the needs of all 51862306a36Sopenharmony_ci * regulator consumers 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_ciint regulator_check_consumers(struct regulator_dev *rdev, 52162306a36Sopenharmony_ci int *min_uV, int *max_uV, 52262306a36Sopenharmony_ci suspend_state_t state) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct regulator *regulator; 52562306a36Sopenharmony_ci struct regulator_voltage *voltage; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci list_for_each_entry(regulator, &rdev->consumer_list, list) { 52862306a36Sopenharmony_ci voltage = ®ulator->voltage[state]; 52962306a36Sopenharmony_ci /* 53062306a36Sopenharmony_ci * Assume consumers that didn't say anything are OK 53162306a36Sopenharmony_ci * with anything in the constraint range. 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_ci if (!voltage->min_uV && !voltage->max_uV) 53462306a36Sopenharmony_ci continue; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (*max_uV > voltage->max_uV) 53762306a36Sopenharmony_ci *max_uV = voltage->max_uV; 53862306a36Sopenharmony_ci if (*min_uV < voltage->min_uV) 53962306a36Sopenharmony_ci *min_uV = voltage->min_uV; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (*min_uV > *max_uV) { 54362306a36Sopenharmony_ci rdev_err(rdev, "Restricting voltage, %u-%uuV\n", 54462306a36Sopenharmony_ci *min_uV, *max_uV); 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci/* current constraint check */ 55262306a36Sopenharmony_cistatic int regulator_check_current_limit(struct regulator_dev *rdev, 55362306a36Sopenharmony_ci int *min_uA, int *max_uA) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci BUG_ON(*min_uA > *max_uA); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_CURRENT)) { 55862306a36Sopenharmony_ci rdev_err(rdev, "current operation not allowed\n"); 55962306a36Sopenharmony_ci return -EPERM; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (*max_uA > rdev->constraints->max_uA) 56362306a36Sopenharmony_ci *max_uA = rdev->constraints->max_uA; 56462306a36Sopenharmony_ci if (*min_uA < rdev->constraints->min_uA) 56562306a36Sopenharmony_ci *min_uA = rdev->constraints->min_uA; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (*min_uA > *max_uA) { 56862306a36Sopenharmony_ci rdev_err(rdev, "unsupportable current range: %d-%duA\n", 56962306a36Sopenharmony_ci *min_uA, *max_uA); 57062306a36Sopenharmony_ci return -EINVAL; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return 0; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* operating mode constraint check */ 57762306a36Sopenharmony_cistatic int regulator_mode_constrain(struct regulator_dev *rdev, 57862306a36Sopenharmony_ci unsigned int *mode) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci switch (*mode) { 58162306a36Sopenharmony_ci case REGULATOR_MODE_FAST: 58262306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 58362306a36Sopenharmony_ci case REGULATOR_MODE_IDLE: 58462306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci default: 58762306a36Sopenharmony_ci rdev_err(rdev, "invalid mode %x specified\n", *mode); 58862306a36Sopenharmony_ci return -EINVAL; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_MODE)) { 59262306a36Sopenharmony_ci rdev_err(rdev, "mode operation not allowed\n"); 59362306a36Sopenharmony_ci return -EPERM; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* The modes are bitmasks, the most power hungry modes having 59762306a36Sopenharmony_ci * the lowest values. If the requested mode isn't supported 59862306a36Sopenharmony_ci * try higher modes. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci while (*mode) { 60162306a36Sopenharmony_ci if (rdev->constraints->valid_modes_mask & *mode) 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci *mode /= 2; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci return -EINVAL; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic inline struct regulator_state * 61062306a36Sopenharmony_ciregulator_get_suspend_state(struct regulator_dev *rdev, suspend_state_t state) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci if (rdev->constraints == NULL) 61362306a36Sopenharmony_ci return NULL; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci switch (state) { 61662306a36Sopenharmony_ci case PM_SUSPEND_STANDBY: 61762306a36Sopenharmony_ci return &rdev->constraints->state_standby; 61862306a36Sopenharmony_ci case PM_SUSPEND_MEM: 61962306a36Sopenharmony_ci return &rdev->constraints->state_mem; 62062306a36Sopenharmony_ci case PM_SUSPEND_MAX: 62162306a36Sopenharmony_ci return &rdev->constraints->state_disk; 62262306a36Sopenharmony_ci default: 62362306a36Sopenharmony_ci return NULL; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic const struct regulator_state * 62862306a36Sopenharmony_ciregulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t state) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci const struct regulator_state *rstate; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 63362306a36Sopenharmony_ci if (rstate == NULL) 63462306a36Sopenharmony_ci return NULL; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* If we have no suspend mode configuration don't set anything; 63762306a36Sopenharmony_ci * only warn if the driver implements set_suspend_voltage or 63862306a36Sopenharmony_ci * set_suspend_mode callback. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_ci if (rstate->enabled != ENABLE_IN_SUSPEND && 64162306a36Sopenharmony_ci rstate->enabled != DISABLE_IN_SUSPEND) { 64262306a36Sopenharmony_ci if (rdev->desc->ops->set_suspend_voltage || 64362306a36Sopenharmony_ci rdev->desc->ops->set_suspend_mode) 64462306a36Sopenharmony_ci rdev_warn(rdev, "No configuration\n"); 64562306a36Sopenharmony_ci return NULL; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return rstate; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic ssize_t microvolts_show(struct device *dev, 65262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 65562306a36Sopenharmony_ci int uV; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci regulator_lock(rdev); 65862306a36Sopenharmony_ci uV = regulator_get_voltage_rdev(rdev); 65962306a36Sopenharmony_ci regulator_unlock(rdev); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (uV < 0) 66262306a36Sopenharmony_ci return uV; 66362306a36Sopenharmony_ci return sprintf(buf, "%d\n", uV); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(microvolts); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic ssize_t microamps_show(struct device *dev, 66862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev)); 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(microamps); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic ssize_t name_show(struct device *dev, struct device_attribute *attr, 67762306a36Sopenharmony_ci char *buf) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci return sprintf(buf, "%s\n", rdev_get_name(rdev)); 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic const char *regulator_opmode_to_str(int mode) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci switch (mode) { 68862306a36Sopenharmony_ci case REGULATOR_MODE_FAST: 68962306a36Sopenharmony_ci return "fast"; 69062306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 69162306a36Sopenharmony_ci return "normal"; 69262306a36Sopenharmony_ci case REGULATOR_MODE_IDLE: 69362306a36Sopenharmony_ci return "idle"; 69462306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 69562306a36Sopenharmony_ci return "standby"; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci return "unknown"; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic ssize_t regulator_print_opmode(char *buf, int mode) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci return sprintf(buf, "%s\n", regulator_opmode_to_str(mode)); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic ssize_t opmode_show(struct device *dev, 70662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci return regulator_print_opmode(buf, _regulator_get_mode(rdev)); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(opmode); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic ssize_t regulator_print_state(char *buf, int state) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci if (state > 0) 71762306a36Sopenharmony_ci return sprintf(buf, "enabled\n"); 71862306a36Sopenharmony_ci else if (state == 0) 71962306a36Sopenharmony_ci return sprintf(buf, "disabled\n"); 72062306a36Sopenharmony_ci else 72162306a36Sopenharmony_ci return sprintf(buf, "unknown\n"); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic ssize_t state_show(struct device *dev, 72562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 72862306a36Sopenharmony_ci ssize_t ret; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci regulator_lock(rdev); 73162306a36Sopenharmony_ci ret = regulator_print_state(buf, _regulator_is_enabled(rdev)); 73262306a36Sopenharmony_ci regulator_unlock(rdev); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return ret; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(state); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic ssize_t status_show(struct device *dev, 73962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 74262306a36Sopenharmony_ci int status; 74362306a36Sopenharmony_ci char *label; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci status = rdev->desc->ops->get_status(rdev); 74662306a36Sopenharmony_ci if (status < 0) 74762306a36Sopenharmony_ci return status; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci switch (status) { 75062306a36Sopenharmony_ci case REGULATOR_STATUS_OFF: 75162306a36Sopenharmony_ci label = "off"; 75262306a36Sopenharmony_ci break; 75362306a36Sopenharmony_ci case REGULATOR_STATUS_ON: 75462306a36Sopenharmony_ci label = "on"; 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci case REGULATOR_STATUS_ERROR: 75762306a36Sopenharmony_ci label = "error"; 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci case REGULATOR_STATUS_FAST: 76062306a36Sopenharmony_ci label = "fast"; 76162306a36Sopenharmony_ci break; 76262306a36Sopenharmony_ci case REGULATOR_STATUS_NORMAL: 76362306a36Sopenharmony_ci label = "normal"; 76462306a36Sopenharmony_ci break; 76562306a36Sopenharmony_ci case REGULATOR_STATUS_IDLE: 76662306a36Sopenharmony_ci label = "idle"; 76762306a36Sopenharmony_ci break; 76862306a36Sopenharmony_ci case REGULATOR_STATUS_STANDBY: 76962306a36Sopenharmony_ci label = "standby"; 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci case REGULATOR_STATUS_BYPASS: 77262306a36Sopenharmony_ci label = "bypass"; 77362306a36Sopenharmony_ci break; 77462306a36Sopenharmony_ci case REGULATOR_STATUS_UNDEFINED: 77562306a36Sopenharmony_ci label = "undefined"; 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci default: 77862306a36Sopenharmony_ci return -ERANGE; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return sprintf(buf, "%s\n", label); 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(status); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic ssize_t min_microamps_show(struct device *dev, 78662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (!rdev->constraints) 79162306a36Sopenharmony_ci return sprintf(buf, "constraint not defined\n"); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->min_uA); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(min_microamps); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic ssize_t max_microamps_show(struct device *dev, 79862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (!rdev->constraints) 80362306a36Sopenharmony_ci return sprintf(buf, "constraint not defined\n"); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->max_uA); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(max_microamps); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic ssize_t min_microvolts_show(struct device *dev, 81062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (!rdev->constraints) 81562306a36Sopenharmony_ci return sprintf(buf, "constraint not defined\n"); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->min_uV); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(min_microvolts); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic ssize_t max_microvolts_show(struct device *dev, 82262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (!rdev->constraints) 82762306a36Sopenharmony_ci return sprintf(buf, "constraint not defined\n"); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->max_uV); 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(max_microvolts); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic ssize_t requested_microamps_show(struct device *dev, 83462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 83762306a36Sopenharmony_ci struct regulator *regulator; 83862306a36Sopenharmony_ci int uA = 0; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci regulator_lock(rdev); 84162306a36Sopenharmony_ci list_for_each_entry(regulator, &rdev->consumer_list, list) { 84262306a36Sopenharmony_ci if (regulator->enable_count) 84362306a36Sopenharmony_ci uA += regulator->uA_load; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci regulator_unlock(rdev); 84662306a36Sopenharmony_ci return sprintf(buf, "%d\n", uA); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(requested_microamps); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic ssize_t num_users_show(struct device *dev, struct device_attribute *attr, 85162306a36Sopenharmony_ci char *buf) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 85462306a36Sopenharmony_ci return sprintf(buf, "%d\n", rdev->use_count); 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(num_users); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic ssize_t type_show(struct device *dev, struct device_attribute *attr, 85962306a36Sopenharmony_ci char *buf) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci switch (rdev->desc->type) { 86462306a36Sopenharmony_ci case REGULATOR_VOLTAGE: 86562306a36Sopenharmony_ci return sprintf(buf, "voltage\n"); 86662306a36Sopenharmony_ci case REGULATOR_CURRENT: 86762306a36Sopenharmony_ci return sprintf(buf, "current\n"); 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci return sprintf(buf, "unknown\n"); 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(type); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic ssize_t suspend_mem_microvolts_show(struct device *dev, 87462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV); 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_mem_microvolts); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic ssize_t suspend_disk_microvolts_show(struct device *dev, 88362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_disk_microvolts); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic ssize_t suspend_standby_microvolts_show(struct device *dev, 89262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_standby_microvolts); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistatic ssize_t suspend_mem_mode_show(struct device *dev, 90162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci return regulator_print_opmode(buf, 90662306a36Sopenharmony_ci rdev->constraints->state_mem.mode); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_mem_mode); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic ssize_t suspend_disk_mode_show(struct device *dev, 91162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return regulator_print_opmode(buf, 91662306a36Sopenharmony_ci rdev->constraints->state_disk.mode); 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_disk_mode); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic ssize_t suspend_standby_mode_show(struct device *dev, 92162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci return regulator_print_opmode(buf, 92662306a36Sopenharmony_ci rdev->constraints->state_standby.mode); 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_standby_mode); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic ssize_t suspend_mem_state_show(struct device *dev, 93162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci return regulator_print_state(buf, 93662306a36Sopenharmony_ci rdev->constraints->state_mem.enabled); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_mem_state); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic ssize_t suspend_disk_state_show(struct device *dev, 94162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return regulator_print_state(buf, 94662306a36Sopenharmony_ci rdev->constraints->state_disk.enabled); 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_disk_state); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic ssize_t suspend_standby_state_show(struct device *dev, 95162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci return regulator_print_state(buf, 95662306a36Sopenharmony_ci rdev->constraints->state_standby.enabled); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(suspend_standby_state); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic ssize_t bypass_show(struct device *dev, 96162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 96462306a36Sopenharmony_ci const char *report; 96562306a36Sopenharmony_ci bool bypass; 96662306a36Sopenharmony_ci int ret; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci ret = rdev->desc->ops->get_bypass(rdev, &bypass); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (ret != 0) 97162306a36Sopenharmony_ci report = "unknown"; 97262306a36Sopenharmony_ci else if (bypass) 97362306a36Sopenharmony_ci report = "enabled"; 97462306a36Sopenharmony_ci else 97562306a36Sopenharmony_ci report = "disabled"; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return sprintf(buf, "%s\n", report); 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(bypass); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci#define REGULATOR_ERROR_ATTR(name, bit) \ 98262306a36Sopenharmony_ci static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ 98362306a36Sopenharmony_ci char *buf) \ 98462306a36Sopenharmony_ci { \ 98562306a36Sopenharmony_ci int ret; \ 98662306a36Sopenharmony_ci unsigned int flags; \ 98762306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); \ 98862306a36Sopenharmony_ci ret = _regulator_get_error_flags(rdev, &flags); \ 98962306a36Sopenharmony_ci if (ret) \ 99062306a36Sopenharmony_ci return ret; \ 99162306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", !!(flags & (bit))); \ 99262306a36Sopenharmony_ci } \ 99362306a36Sopenharmony_ci static DEVICE_ATTR_RO(name) 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(under_voltage, REGULATOR_ERROR_UNDER_VOLTAGE); 99662306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(over_current, REGULATOR_ERROR_OVER_CURRENT); 99762306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(regulation_out, REGULATOR_ERROR_REGULATION_OUT); 99862306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(fail, REGULATOR_ERROR_FAIL); 99962306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(over_temp, REGULATOR_ERROR_OVER_TEMP); 100062306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(under_voltage_warn, REGULATOR_ERROR_UNDER_VOLTAGE_WARN); 100162306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(over_current_warn, REGULATOR_ERROR_OVER_CURRENT_WARN); 100262306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(over_voltage_warn, REGULATOR_ERROR_OVER_VOLTAGE_WARN); 100362306a36Sopenharmony_ciREGULATOR_ERROR_ATTR(over_temp_warn, REGULATOR_ERROR_OVER_TEMP_WARN); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci/* Calculate the new optimum regulator operating mode based on the new total 100662306a36Sopenharmony_ci * consumer load. All locks held by caller 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_cistatic int drms_uA_update(struct regulator_dev *rdev) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci struct regulator *sibling; 101162306a36Sopenharmony_ci int current_uA = 0, output_uV, input_uV, err; 101262306a36Sopenharmony_ci unsigned int mode; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci /* 101562306a36Sopenharmony_ci * first check to see if we can set modes at all, otherwise just 101662306a36Sopenharmony_ci * tell the consumer everything is OK. 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) { 101962306a36Sopenharmony_ci rdev_dbg(rdev, "DRMS operation not allowed\n"); 102062306a36Sopenharmony_ci return 0; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (!rdev->desc->ops->get_optimum_mode && 102462306a36Sopenharmony_ci !rdev->desc->ops->set_load) 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (!rdev->desc->ops->set_mode && 102862306a36Sopenharmony_ci !rdev->desc->ops->set_load) 102962306a36Sopenharmony_ci return -EINVAL; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* calc total requested load */ 103262306a36Sopenharmony_ci list_for_each_entry(sibling, &rdev->consumer_list, list) { 103362306a36Sopenharmony_ci if (sibling->enable_count) 103462306a36Sopenharmony_ci current_uA += sibling->uA_load; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci current_uA += rdev->constraints->system_load; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (rdev->desc->ops->set_load) { 104062306a36Sopenharmony_ci /* set the optimum mode for our new total regulator load */ 104162306a36Sopenharmony_ci err = rdev->desc->ops->set_load(rdev, current_uA); 104262306a36Sopenharmony_ci if (err < 0) 104362306a36Sopenharmony_ci rdev_err(rdev, "failed to set load %d: %pe\n", 104462306a36Sopenharmony_ci current_uA, ERR_PTR(err)); 104562306a36Sopenharmony_ci } else { 104662306a36Sopenharmony_ci /* 104762306a36Sopenharmony_ci * Unfortunately in some cases the constraints->valid_ops has 104862306a36Sopenharmony_ci * REGULATOR_CHANGE_DRMS but there are no valid modes listed. 104962306a36Sopenharmony_ci * That's not really legit but we won't consider it a fatal 105062306a36Sopenharmony_ci * error here. We'll treat it as if REGULATOR_CHANGE_DRMS 105162306a36Sopenharmony_ci * wasn't set. 105262306a36Sopenharmony_ci */ 105362306a36Sopenharmony_ci if (!rdev->constraints->valid_modes_mask) { 105462306a36Sopenharmony_ci rdev_dbg(rdev, "Can change modes; but no valid mode\n"); 105562306a36Sopenharmony_ci return 0; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* get output voltage */ 105962306a36Sopenharmony_ci output_uV = regulator_get_voltage_rdev(rdev); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* 106262306a36Sopenharmony_ci * Don't return an error; if regulator driver cares about 106362306a36Sopenharmony_ci * output_uV then it's up to the driver to validate. 106462306a36Sopenharmony_ci */ 106562306a36Sopenharmony_ci if (output_uV <= 0) 106662306a36Sopenharmony_ci rdev_dbg(rdev, "invalid output voltage found\n"); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* get input voltage */ 106962306a36Sopenharmony_ci input_uV = 0; 107062306a36Sopenharmony_ci if (rdev->supply) 107162306a36Sopenharmony_ci input_uV = regulator_get_voltage_rdev(rdev->supply->rdev); 107262306a36Sopenharmony_ci if (input_uV <= 0) 107362306a36Sopenharmony_ci input_uV = rdev->constraints->input_uV; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* 107662306a36Sopenharmony_ci * Don't return an error; if regulator driver cares about 107762306a36Sopenharmony_ci * input_uV then it's up to the driver to validate. 107862306a36Sopenharmony_ci */ 107962306a36Sopenharmony_ci if (input_uV <= 0) 108062306a36Sopenharmony_ci rdev_dbg(rdev, "invalid input voltage found\n"); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci /* now get the optimum mode for our new total regulator load */ 108362306a36Sopenharmony_ci mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, 108462306a36Sopenharmony_ci output_uV, current_uA); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci /* check the new mode is allowed */ 108762306a36Sopenharmony_ci err = regulator_mode_constrain(rdev, &mode); 108862306a36Sopenharmony_ci if (err < 0) { 108962306a36Sopenharmony_ci rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV: %pe\n", 109062306a36Sopenharmony_ci current_uA, input_uV, output_uV, ERR_PTR(err)); 109162306a36Sopenharmony_ci return err; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci err = rdev->desc->ops->set_mode(rdev, mode); 109562306a36Sopenharmony_ci if (err < 0) 109662306a36Sopenharmony_ci rdev_err(rdev, "failed to set optimum mode %x: %pe\n", 109762306a36Sopenharmony_ci mode, ERR_PTR(err)); 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci return err; 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic int __suspend_set_state(struct regulator_dev *rdev, 110462306a36Sopenharmony_ci const struct regulator_state *rstate) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci int ret = 0; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (rstate->enabled == ENABLE_IN_SUSPEND && 110962306a36Sopenharmony_ci rdev->desc->ops->set_suspend_enable) 111062306a36Sopenharmony_ci ret = rdev->desc->ops->set_suspend_enable(rdev); 111162306a36Sopenharmony_ci else if (rstate->enabled == DISABLE_IN_SUSPEND && 111262306a36Sopenharmony_ci rdev->desc->ops->set_suspend_disable) 111362306a36Sopenharmony_ci ret = rdev->desc->ops->set_suspend_disable(rdev); 111462306a36Sopenharmony_ci else /* OK if set_suspend_enable or set_suspend_disable is NULL */ 111562306a36Sopenharmony_ci ret = 0; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (ret < 0) { 111862306a36Sopenharmony_ci rdev_err(rdev, "failed to enabled/disable: %pe\n", ERR_PTR(ret)); 111962306a36Sopenharmony_ci return ret; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { 112362306a36Sopenharmony_ci ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); 112462306a36Sopenharmony_ci if (ret < 0) { 112562306a36Sopenharmony_ci rdev_err(rdev, "failed to set voltage: %pe\n", ERR_PTR(ret)); 112662306a36Sopenharmony_ci return ret; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { 113162306a36Sopenharmony_ci ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); 113262306a36Sopenharmony_ci if (ret < 0) { 113362306a36Sopenharmony_ci rdev_err(rdev, "failed to set mode: %pe\n", ERR_PTR(ret)); 113462306a36Sopenharmony_ci return ret; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci return ret; 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic int suspend_set_initial_state(struct regulator_dev *rdev) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci const struct regulator_state *rstate; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci rstate = regulator_get_suspend_state_check(rdev, 114662306a36Sopenharmony_ci rdev->constraints->initial_state); 114762306a36Sopenharmony_ci if (!rstate) 114862306a36Sopenharmony_ci return 0; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci return __suspend_set_state(rdev, rstate); 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) 115462306a36Sopenharmony_cistatic void print_constraints_debug(struct regulator_dev *rdev) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 115762306a36Sopenharmony_ci char buf[160] = ""; 115862306a36Sopenharmony_ci size_t len = sizeof(buf) - 1; 115962306a36Sopenharmony_ci int count = 0; 116062306a36Sopenharmony_ci int ret; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (constraints->min_uV && constraints->max_uV) { 116362306a36Sopenharmony_ci if (constraints->min_uV == constraints->max_uV) 116462306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, "%d mV ", 116562306a36Sopenharmony_ci constraints->min_uV / 1000); 116662306a36Sopenharmony_ci else 116762306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, 116862306a36Sopenharmony_ci "%d <--> %d mV ", 116962306a36Sopenharmony_ci constraints->min_uV / 1000, 117062306a36Sopenharmony_ci constraints->max_uV / 1000); 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (!constraints->min_uV || 117462306a36Sopenharmony_ci constraints->min_uV != constraints->max_uV) { 117562306a36Sopenharmony_ci ret = regulator_get_voltage_rdev(rdev); 117662306a36Sopenharmony_ci if (ret > 0) 117762306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, 117862306a36Sopenharmony_ci "at %d mV ", ret / 1000); 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (constraints->uV_offset) 118262306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, "%dmV offset ", 118362306a36Sopenharmony_ci constraints->uV_offset / 1000); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (constraints->min_uA && constraints->max_uA) { 118662306a36Sopenharmony_ci if (constraints->min_uA == constraints->max_uA) 118762306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, "%d mA ", 118862306a36Sopenharmony_ci constraints->min_uA / 1000); 118962306a36Sopenharmony_ci else 119062306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, 119162306a36Sopenharmony_ci "%d <--> %d mA ", 119262306a36Sopenharmony_ci constraints->min_uA / 1000, 119362306a36Sopenharmony_ci constraints->max_uA / 1000); 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (!constraints->min_uA || 119762306a36Sopenharmony_ci constraints->min_uA != constraints->max_uA) { 119862306a36Sopenharmony_ci ret = _regulator_get_current_limit(rdev); 119962306a36Sopenharmony_ci if (ret > 0) 120062306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, 120162306a36Sopenharmony_ci "at %d mA ", ret / 1000); 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci if (constraints->valid_modes_mask & REGULATOR_MODE_FAST) 120562306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, "fast "); 120662306a36Sopenharmony_ci if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL) 120762306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, "normal "); 120862306a36Sopenharmony_ci if (constraints->valid_modes_mask & REGULATOR_MODE_IDLE) 120962306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, "idle "); 121062306a36Sopenharmony_ci if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) 121162306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, "standby "); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (!count) 121462306a36Sopenharmony_ci count = scnprintf(buf, len, "no parameters"); 121562306a36Sopenharmony_ci else 121662306a36Sopenharmony_ci --count; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci count += scnprintf(buf + count, len - count, ", %s", 121962306a36Sopenharmony_ci _regulator_is_enabled(rdev) ? "enabled" : "disabled"); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci rdev_dbg(rdev, "%s\n", buf); 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci#else /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */ 122462306a36Sopenharmony_cistatic inline void print_constraints_debug(struct regulator_dev *rdev) {} 122562306a36Sopenharmony_ci#endif /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */ 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_cistatic void print_constraints(struct regulator_dev *rdev) 122862306a36Sopenharmony_ci{ 122962306a36Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci print_constraints_debug(rdev); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if ((constraints->min_uV != constraints->max_uV) && 123462306a36Sopenharmony_ci !regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) 123562306a36Sopenharmony_ci rdev_warn(rdev, 123662306a36Sopenharmony_ci "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic int machine_constraints_voltage(struct regulator_dev *rdev, 124062306a36Sopenharmony_ci struct regulation_constraints *constraints) 124162306a36Sopenharmony_ci{ 124262306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 124362306a36Sopenharmony_ci int ret; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* do we need to apply the constraint voltage */ 124662306a36Sopenharmony_ci if (rdev->constraints->apply_uV && 124762306a36Sopenharmony_ci rdev->constraints->min_uV && rdev->constraints->max_uV) { 124862306a36Sopenharmony_ci int target_min, target_max; 124962306a36Sopenharmony_ci int current_uV = regulator_get_voltage_rdev(rdev); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (current_uV == -ENOTRECOVERABLE) { 125262306a36Sopenharmony_ci /* This regulator can't be read and must be initialized */ 125362306a36Sopenharmony_ci rdev_info(rdev, "Setting %d-%duV\n", 125462306a36Sopenharmony_ci rdev->constraints->min_uV, 125562306a36Sopenharmony_ci rdev->constraints->max_uV); 125662306a36Sopenharmony_ci _regulator_do_set_voltage(rdev, 125762306a36Sopenharmony_ci rdev->constraints->min_uV, 125862306a36Sopenharmony_ci rdev->constraints->max_uV); 125962306a36Sopenharmony_ci current_uV = regulator_get_voltage_rdev(rdev); 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (current_uV < 0) { 126362306a36Sopenharmony_ci if (current_uV != -EPROBE_DEFER) 126462306a36Sopenharmony_ci rdev_err(rdev, 126562306a36Sopenharmony_ci "failed to get the current voltage: %pe\n", 126662306a36Sopenharmony_ci ERR_PTR(current_uV)); 126762306a36Sopenharmony_ci return current_uV; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci /* 127162306a36Sopenharmony_ci * If we're below the minimum voltage move up to the 127262306a36Sopenharmony_ci * minimum voltage, if we're above the maximum voltage 127362306a36Sopenharmony_ci * then move down to the maximum. 127462306a36Sopenharmony_ci */ 127562306a36Sopenharmony_ci target_min = current_uV; 127662306a36Sopenharmony_ci target_max = current_uV; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (current_uV < rdev->constraints->min_uV) { 127962306a36Sopenharmony_ci target_min = rdev->constraints->min_uV; 128062306a36Sopenharmony_ci target_max = rdev->constraints->min_uV; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (current_uV > rdev->constraints->max_uV) { 128462306a36Sopenharmony_ci target_min = rdev->constraints->max_uV; 128562306a36Sopenharmony_ci target_max = rdev->constraints->max_uV; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (target_min != current_uV || target_max != current_uV) { 128962306a36Sopenharmony_ci rdev_info(rdev, "Bringing %duV into %d-%duV\n", 129062306a36Sopenharmony_ci current_uV, target_min, target_max); 129162306a36Sopenharmony_ci ret = _regulator_do_set_voltage( 129262306a36Sopenharmony_ci rdev, target_min, target_max); 129362306a36Sopenharmony_ci if (ret < 0) { 129462306a36Sopenharmony_ci rdev_err(rdev, 129562306a36Sopenharmony_ci "failed to apply %d-%duV constraint: %pe\n", 129662306a36Sopenharmony_ci target_min, target_max, ERR_PTR(ret)); 129762306a36Sopenharmony_ci return ret; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci /* constrain machine-level voltage specs to fit 130362306a36Sopenharmony_ci * the actual range supported by this regulator. 130462306a36Sopenharmony_ci */ 130562306a36Sopenharmony_ci if (ops->list_voltage && rdev->desc->n_voltages) { 130662306a36Sopenharmony_ci int count = rdev->desc->n_voltages; 130762306a36Sopenharmony_ci int i; 130862306a36Sopenharmony_ci int min_uV = INT_MAX; 130962306a36Sopenharmony_ci int max_uV = INT_MIN; 131062306a36Sopenharmony_ci int cmin = constraints->min_uV; 131162306a36Sopenharmony_ci int cmax = constraints->max_uV; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci /* it's safe to autoconfigure fixed-voltage supplies 131462306a36Sopenharmony_ci * and the constraints are used by list_voltage. 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_ci if (count == 1 && !cmin) { 131762306a36Sopenharmony_ci cmin = 1; 131862306a36Sopenharmony_ci cmax = INT_MAX; 131962306a36Sopenharmony_ci constraints->min_uV = cmin; 132062306a36Sopenharmony_ci constraints->max_uV = cmax; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci /* voltage constraints are optional */ 132462306a36Sopenharmony_ci if ((cmin == 0) && (cmax == 0)) 132562306a36Sopenharmony_ci return 0; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci /* else require explicit machine-level constraints */ 132862306a36Sopenharmony_ci if (cmin <= 0 || cmax <= 0 || cmax < cmin) { 132962306a36Sopenharmony_ci rdev_err(rdev, "invalid voltage constraints\n"); 133062306a36Sopenharmony_ci return -EINVAL; 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci /* no need to loop voltages if range is continuous */ 133462306a36Sopenharmony_ci if (rdev->desc->continuous_voltage_range) 133562306a36Sopenharmony_ci return 0; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci /* initial: [cmin..cmax] valid, [min_uV..max_uV] not */ 133862306a36Sopenharmony_ci for (i = 0; i < count; i++) { 133962306a36Sopenharmony_ci int value; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci value = ops->list_voltage(rdev, i); 134262306a36Sopenharmony_ci if (value <= 0) 134362306a36Sopenharmony_ci continue; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci /* maybe adjust [min_uV..max_uV] */ 134662306a36Sopenharmony_ci if (value >= cmin && value < min_uV) 134762306a36Sopenharmony_ci min_uV = value; 134862306a36Sopenharmony_ci if (value <= cmax && value > max_uV) 134962306a36Sopenharmony_ci max_uV = value; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* final: [min_uV..max_uV] valid iff constraints valid */ 135362306a36Sopenharmony_ci if (max_uV < min_uV) { 135462306a36Sopenharmony_ci rdev_err(rdev, 135562306a36Sopenharmony_ci "unsupportable voltage constraints %u-%uuV\n", 135662306a36Sopenharmony_ci min_uV, max_uV); 135762306a36Sopenharmony_ci return -EINVAL; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci /* use regulator's subset of machine constraints */ 136162306a36Sopenharmony_ci if (constraints->min_uV < min_uV) { 136262306a36Sopenharmony_ci rdev_dbg(rdev, "override min_uV, %d -> %d\n", 136362306a36Sopenharmony_ci constraints->min_uV, min_uV); 136462306a36Sopenharmony_ci constraints->min_uV = min_uV; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci if (constraints->max_uV > max_uV) { 136762306a36Sopenharmony_ci rdev_dbg(rdev, "override max_uV, %d -> %d\n", 136862306a36Sopenharmony_ci constraints->max_uV, max_uV); 136962306a36Sopenharmony_ci constraints->max_uV = max_uV; 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci return 0; 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic int machine_constraints_current(struct regulator_dev *rdev, 137762306a36Sopenharmony_ci struct regulation_constraints *constraints) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 138062306a36Sopenharmony_ci int ret; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (!constraints->min_uA && !constraints->max_uA) 138362306a36Sopenharmony_ci return 0; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci if (constraints->min_uA > constraints->max_uA) { 138662306a36Sopenharmony_ci rdev_err(rdev, "Invalid current constraints\n"); 138762306a36Sopenharmony_ci return -EINVAL; 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (!ops->set_current_limit || !ops->get_current_limit) { 139162306a36Sopenharmony_ci rdev_warn(rdev, "Operation of current configuration missing\n"); 139262306a36Sopenharmony_ci return 0; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci /* Set regulator current in constraints range */ 139662306a36Sopenharmony_ci ret = ops->set_current_limit(rdev, constraints->min_uA, 139762306a36Sopenharmony_ci constraints->max_uA); 139862306a36Sopenharmony_ci if (ret < 0) { 139962306a36Sopenharmony_ci rdev_err(rdev, "Failed to set current constraint, %d\n", ret); 140062306a36Sopenharmony_ci return ret; 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci return 0; 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_cistatic int _regulator_do_enable(struct regulator_dev *rdev); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic int notif_set_limit(struct regulator_dev *rdev, 140962306a36Sopenharmony_ci int (*set)(struct regulator_dev *, int, int, bool), 141062306a36Sopenharmony_ci int limit, int severity) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci bool enable; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) { 141562306a36Sopenharmony_ci enable = false; 141662306a36Sopenharmony_ci limit = 0; 141762306a36Sopenharmony_ci } else { 141862306a36Sopenharmony_ci enable = true; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (limit == REGULATOR_NOTIF_LIMIT_ENABLE) 142262306a36Sopenharmony_ci limit = 0; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return set(rdev, limit, severity, enable); 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_cistatic int handle_notify_limits(struct regulator_dev *rdev, 142862306a36Sopenharmony_ci int (*set)(struct regulator_dev *, int, int, bool), 142962306a36Sopenharmony_ci struct notification_limit *limits) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci int ret = 0; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (!set) 143462306a36Sopenharmony_ci return -EOPNOTSUPP; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci if (limits->prot) 143762306a36Sopenharmony_ci ret = notif_set_limit(rdev, set, limits->prot, 143862306a36Sopenharmony_ci REGULATOR_SEVERITY_PROT); 143962306a36Sopenharmony_ci if (ret) 144062306a36Sopenharmony_ci return ret; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (limits->err) 144362306a36Sopenharmony_ci ret = notif_set_limit(rdev, set, limits->err, 144462306a36Sopenharmony_ci REGULATOR_SEVERITY_ERR); 144562306a36Sopenharmony_ci if (ret) 144662306a36Sopenharmony_ci return ret; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (limits->warn) 144962306a36Sopenharmony_ci ret = notif_set_limit(rdev, set, limits->warn, 145062306a36Sopenharmony_ci REGULATOR_SEVERITY_WARN); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci return ret; 145362306a36Sopenharmony_ci} 145462306a36Sopenharmony_ci/** 145562306a36Sopenharmony_ci * set_machine_constraints - sets regulator constraints 145662306a36Sopenharmony_ci * @rdev: regulator source 145762306a36Sopenharmony_ci * 145862306a36Sopenharmony_ci * Allows platform initialisation code to define and constrain 145962306a36Sopenharmony_ci * regulator circuits e.g. valid voltage/current ranges, etc. NOTE: 146062306a36Sopenharmony_ci * Constraints *must* be set by platform code in order for some 146162306a36Sopenharmony_ci * regulator operations to proceed i.e. set_voltage, set_current_limit, 146262306a36Sopenharmony_ci * set_mode. 146362306a36Sopenharmony_ci */ 146462306a36Sopenharmony_cistatic int set_machine_constraints(struct regulator_dev *rdev) 146562306a36Sopenharmony_ci{ 146662306a36Sopenharmony_ci int ret = 0; 146762306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci ret = machine_constraints_voltage(rdev, rdev->constraints); 147062306a36Sopenharmony_ci if (ret != 0) 147162306a36Sopenharmony_ci return ret; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci ret = machine_constraints_current(rdev, rdev->constraints); 147462306a36Sopenharmony_ci if (ret != 0) 147562306a36Sopenharmony_ci return ret; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci if (rdev->constraints->ilim_uA && ops->set_input_current_limit) { 147862306a36Sopenharmony_ci ret = ops->set_input_current_limit(rdev, 147962306a36Sopenharmony_ci rdev->constraints->ilim_uA); 148062306a36Sopenharmony_ci if (ret < 0) { 148162306a36Sopenharmony_ci rdev_err(rdev, "failed to set input limit: %pe\n", ERR_PTR(ret)); 148262306a36Sopenharmony_ci return ret; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci /* do we need to setup our suspend state */ 148762306a36Sopenharmony_ci if (rdev->constraints->initial_state) { 148862306a36Sopenharmony_ci ret = suspend_set_initial_state(rdev); 148962306a36Sopenharmony_ci if (ret < 0) { 149062306a36Sopenharmony_ci rdev_err(rdev, "failed to set suspend state: %pe\n", ERR_PTR(ret)); 149162306a36Sopenharmony_ci return ret; 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci if (rdev->constraints->initial_mode) { 149662306a36Sopenharmony_ci if (!ops->set_mode) { 149762306a36Sopenharmony_ci rdev_err(rdev, "no set_mode operation\n"); 149862306a36Sopenharmony_ci return -EINVAL; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci ret = ops->set_mode(rdev, rdev->constraints->initial_mode); 150262306a36Sopenharmony_ci if (ret < 0) { 150362306a36Sopenharmony_ci rdev_err(rdev, "failed to set initial mode: %pe\n", ERR_PTR(ret)); 150462306a36Sopenharmony_ci return ret; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci } else if (rdev->constraints->system_load) { 150762306a36Sopenharmony_ci /* 150862306a36Sopenharmony_ci * We'll only apply the initial system load if an 150962306a36Sopenharmony_ci * initial mode wasn't specified. 151062306a36Sopenharmony_ci */ 151162306a36Sopenharmony_ci drms_uA_update(rdev); 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable) 151562306a36Sopenharmony_ci && ops->set_ramp_delay) { 151662306a36Sopenharmony_ci ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay); 151762306a36Sopenharmony_ci if (ret < 0) { 151862306a36Sopenharmony_ci rdev_err(rdev, "failed to set ramp_delay: %pe\n", ERR_PTR(ret)); 151962306a36Sopenharmony_ci return ret; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci if (rdev->constraints->pull_down && ops->set_pull_down) { 152462306a36Sopenharmony_ci ret = ops->set_pull_down(rdev); 152562306a36Sopenharmony_ci if (ret < 0) { 152662306a36Sopenharmony_ci rdev_err(rdev, "failed to set pull down: %pe\n", ERR_PTR(ret)); 152762306a36Sopenharmony_ci return ret; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (rdev->constraints->soft_start && ops->set_soft_start) { 153262306a36Sopenharmony_ci ret = ops->set_soft_start(rdev); 153362306a36Sopenharmony_ci if (ret < 0) { 153462306a36Sopenharmony_ci rdev_err(rdev, "failed to set soft start: %pe\n", ERR_PTR(ret)); 153562306a36Sopenharmony_ci return ret; 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* 154062306a36Sopenharmony_ci * Existing logic does not warn if over_current_protection is given as 154162306a36Sopenharmony_ci * a constraint but driver does not support that. I think we should 154262306a36Sopenharmony_ci * warn about this type of issues as it is possible someone changes 154362306a36Sopenharmony_ci * PMIC on board to another type - and the another PMIC's driver does 154462306a36Sopenharmony_ci * not support setting protection. Board composer may happily believe 154562306a36Sopenharmony_ci * the DT limits are respected - especially if the new PMIC HW also 154662306a36Sopenharmony_ci * supports protection but the driver does not. I won't change the logic 154762306a36Sopenharmony_ci * without hearing more experienced opinion on this though. 154862306a36Sopenharmony_ci * 154962306a36Sopenharmony_ci * If warning is seen as a good idea then we can merge handling the 155062306a36Sopenharmony_ci * over-curret protection and detection and get rid of this special 155162306a36Sopenharmony_ci * handling. 155262306a36Sopenharmony_ci */ 155362306a36Sopenharmony_ci if (rdev->constraints->over_current_protection 155462306a36Sopenharmony_ci && ops->set_over_current_protection) { 155562306a36Sopenharmony_ci int lim = rdev->constraints->over_curr_limits.prot; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci ret = ops->set_over_current_protection(rdev, lim, 155862306a36Sopenharmony_ci REGULATOR_SEVERITY_PROT, 155962306a36Sopenharmony_ci true); 156062306a36Sopenharmony_ci if (ret < 0) { 156162306a36Sopenharmony_ci rdev_err(rdev, "failed to set over current protection: %pe\n", 156262306a36Sopenharmony_ci ERR_PTR(ret)); 156362306a36Sopenharmony_ci return ret; 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (rdev->constraints->over_current_detection) 156862306a36Sopenharmony_ci ret = handle_notify_limits(rdev, 156962306a36Sopenharmony_ci ops->set_over_current_protection, 157062306a36Sopenharmony_ci &rdev->constraints->over_curr_limits); 157162306a36Sopenharmony_ci if (ret) { 157262306a36Sopenharmony_ci if (ret != -EOPNOTSUPP) { 157362306a36Sopenharmony_ci rdev_err(rdev, "failed to set over current limits: %pe\n", 157462306a36Sopenharmony_ci ERR_PTR(ret)); 157562306a36Sopenharmony_ci return ret; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci rdev_warn(rdev, 157862306a36Sopenharmony_ci "IC does not support requested over-current limits\n"); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (rdev->constraints->over_voltage_detection) 158262306a36Sopenharmony_ci ret = handle_notify_limits(rdev, 158362306a36Sopenharmony_ci ops->set_over_voltage_protection, 158462306a36Sopenharmony_ci &rdev->constraints->over_voltage_limits); 158562306a36Sopenharmony_ci if (ret) { 158662306a36Sopenharmony_ci if (ret != -EOPNOTSUPP) { 158762306a36Sopenharmony_ci rdev_err(rdev, "failed to set over voltage limits %pe\n", 158862306a36Sopenharmony_ci ERR_PTR(ret)); 158962306a36Sopenharmony_ci return ret; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci rdev_warn(rdev, 159262306a36Sopenharmony_ci "IC does not support requested over voltage limits\n"); 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (rdev->constraints->under_voltage_detection) 159662306a36Sopenharmony_ci ret = handle_notify_limits(rdev, 159762306a36Sopenharmony_ci ops->set_under_voltage_protection, 159862306a36Sopenharmony_ci &rdev->constraints->under_voltage_limits); 159962306a36Sopenharmony_ci if (ret) { 160062306a36Sopenharmony_ci if (ret != -EOPNOTSUPP) { 160162306a36Sopenharmony_ci rdev_err(rdev, "failed to set under voltage limits %pe\n", 160262306a36Sopenharmony_ci ERR_PTR(ret)); 160362306a36Sopenharmony_ci return ret; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci rdev_warn(rdev, 160662306a36Sopenharmony_ci "IC does not support requested under voltage limits\n"); 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci if (rdev->constraints->over_temp_detection) 161062306a36Sopenharmony_ci ret = handle_notify_limits(rdev, 161162306a36Sopenharmony_ci ops->set_thermal_protection, 161262306a36Sopenharmony_ci &rdev->constraints->temp_limits); 161362306a36Sopenharmony_ci if (ret) { 161462306a36Sopenharmony_ci if (ret != -EOPNOTSUPP) { 161562306a36Sopenharmony_ci rdev_err(rdev, "failed to set temperature limits %pe\n", 161662306a36Sopenharmony_ci ERR_PTR(ret)); 161762306a36Sopenharmony_ci return ret; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci rdev_warn(rdev, 162062306a36Sopenharmony_ci "IC does not support requested temperature limits\n"); 162162306a36Sopenharmony_ci } 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (rdev->constraints->active_discharge && ops->set_active_discharge) { 162462306a36Sopenharmony_ci bool ad_state = (rdev->constraints->active_discharge == 162562306a36Sopenharmony_ci REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci ret = ops->set_active_discharge(rdev, ad_state); 162862306a36Sopenharmony_ci if (ret < 0) { 162962306a36Sopenharmony_ci rdev_err(rdev, "failed to set active discharge: %pe\n", ERR_PTR(ret)); 163062306a36Sopenharmony_ci return ret; 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci /* 163562306a36Sopenharmony_ci * If there is no mechanism for controlling the regulator then 163662306a36Sopenharmony_ci * flag it as always_on so we don't end up duplicating checks 163762306a36Sopenharmony_ci * for this so much. Note that we could control the state of 163862306a36Sopenharmony_ci * a supply to control the output on a regulator that has no 163962306a36Sopenharmony_ci * direct control. 164062306a36Sopenharmony_ci */ 164162306a36Sopenharmony_ci if (!rdev->ena_pin && !ops->enable) { 164262306a36Sopenharmony_ci if (rdev->supply_name && !rdev->supply) 164362306a36Sopenharmony_ci return -EPROBE_DEFER; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci if (rdev->supply) 164662306a36Sopenharmony_ci rdev->constraints->always_on = 164762306a36Sopenharmony_ci rdev->supply->rdev->constraints->always_on; 164862306a36Sopenharmony_ci else 164962306a36Sopenharmony_ci rdev->constraints->always_on = true; 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci /* If the constraints say the regulator should be on at this point 165362306a36Sopenharmony_ci * and we have control then make sure it is enabled. 165462306a36Sopenharmony_ci */ 165562306a36Sopenharmony_ci if (rdev->constraints->always_on || rdev->constraints->boot_on) { 165662306a36Sopenharmony_ci /* If we want to enable this regulator, make sure that we know 165762306a36Sopenharmony_ci * the supplying regulator. 165862306a36Sopenharmony_ci */ 165962306a36Sopenharmony_ci if (rdev->supply_name && !rdev->supply) 166062306a36Sopenharmony_ci return -EPROBE_DEFER; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci /* If supplying regulator has already been enabled, 166362306a36Sopenharmony_ci * it's not intended to have use_count increment 166462306a36Sopenharmony_ci * when rdev is only boot-on. 166562306a36Sopenharmony_ci */ 166662306a36Sopenharmony_ci if (rdev->supply && 166762306a36Sopenharmony_ci (rdev->constraints->always_on || 166862306a36Sopenharmony_ci !regulator_is_enabled(rdev->supply))) { 166962306a36Sopenharmony_ci ret = regulator_enable(rdev->supply); 167062306a36Sopenharmony_ci if (ret < 0) { 167162306a36Sopenharmony_ci _regulator_put(rdev->supply); 167262306a36Sopenharmony_ci rdev->supply = NULL; 167362306a36Sopenharmony_ci return ret; 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci ret = _regulator_do_enable(rdev); 167862306a36Sopenharmony_ci if (ret < 0 && ret != -EINVAL) { 167962306a36Sopenharmony_ci rdev_err(rdev, "failed to enable: %pe\n", ERR_PTR(ret)); 168062306a36Sopenharmony_ci return ret; 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci if (rdev->constraints->always_on) 168462306a36Sopenharmony_ci rdev->use_count++; 168562306a36Sopenharmony_ci } else if (rdev->desc->off_on_delay) { 168662306a36Sopenharmony_ci rdev->last_off = ktime_get(); 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci print_constraints(rdev); 169062306a36Sopenharmony_ci return 0; 169162306a36Sopenharmony_ci} 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci/** 169462306a36Sopenharmony_ci * set_supply - set regulator supply regulator 169562306a36Sopenharmony_ci * @rdev: regulator (locked) 169662306a36Sopenharmony_ci * @supply_rdev: supply regulator (locked)) 169762306a36Sopenharmony_ci * 169862306a36Sopenharmony_ci * Called by platform initialisation code to set the supply regulator for this 169962306a36Sopenharmony_ci * regulator. This ensures that a regulators supply will also be enabled by the 170062306a36Sopenharmony_ci * core if it's child is enabled. 170162306a36Sopenharmony_ci */ 170262306a36Sopenharmony_cistatic int set_supply(struct regulator_dev *rdev, 170362306a36Sopenharmony_ci struct regulator_dev *supply_rdev) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci int err; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci rdev_dbg(rdev, "supplied by %s\n", rdev_get_name(supply_rdev)); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci if (!try_module_get(supply_rdev->owner)) 171062306a36Sopenharmony_ci return -ENODEV; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY"); 171362306a36Sopenharmony_ci if (rdev->supply == NULL) { 171462306a36Sopenharmony_ci module_put(supply_rdev->owner); 171562306a36Sopenharmony_ci err = -ENOMEM; 171662306a36Sopenharmony_ci return err; 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci supply_rdev->open_count++; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci return 0; 172162306a36Sopenharmony_ci} 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci/** 172462306a36Sopenharmony_ci * set_consumer_device_supply - Bind a regulator to a symbolic supply 172562306a36Sopenharmony_ci * @rdev: regulator source 172662306a36Sopenharmony_ci * @consumer_dev_name: dev_name() string for device supply applies to 172762306a36Sopenharmony_ci * @supply: symbolic name for supply 172862306a36Sopenharmony_ci * 172962306a36Sopenharmony_ci * Allows platform initialisation code to map physical regulator 173062306a36Sopenharmony_ci * sources to symbolic names for supplies for use by devices. Devices 173162306a36Sopenharmony_ci * should use these symbolic names to request regulators, avoiding the 173262306a36Sopenharmony_ci * need to provide board-specific regulator names as platform data. 173362306a36Sopenharmony_ci */ 173462306a36Sopenharmony_cistatic int set_consumer_device_supply(struct regulator_dev *rdev, 173562306a36Sopenharmony_ci const char *consumer_dev_name, 173662306a36Sopenharmony_ci const char *supply) 173762306a36Sopenharmony_ci{ 173862306a36Sopenharmony_ci struct regulator_map *node, *new_node; 173962306a36Sopenharmony_ci int has_dev; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci if (supply == NULL) 174262306a36Sopenharmony_ci return -EINVAL; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci if (consumer_dev_name != NULL) 174562306a36Sopenharmony_ci has_dev = 1; 174662306a36Sopenharmony_ci else 174762306a36Sopenharmony_ci has_dev = 0; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci new_node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL); 175062306a36Sopenharmony_ci if (new_node == NULL) 175162306a36Sopenharmony_ci return -ENOMEM; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci new_node->regulator = rdev; 175462306a36Sopenharmony_ci new_node->supply = supply; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci if (has_dev) { 175762306a36Sopenharmony_ci new_node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL); 175862306a36Sopenharmony_ci if (new_node->dev_name == NULL) { 175962306a36Sopenharmony_ci kfree(new_node); 176062306a36Sopenharmony_ci return -ENOMEM; 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 176562306a36Sopenharmony_ci list_for_each_entry(node, ®ulator_map_list, list) { 176662306a36Sopenharmony_ci if (node->dev_name && consumer_dev_name) { 176762306a36Sopenharmony_ci if (strcmp(node->dev_name, consumer_dev_name) != 0) 176862306a36Sopenharmony_ci continue; 176962306a36Sopenharmony_ci } else if (node->dev_name || consumer_dev_name) { 177062306a36Sopenharmony_ci continue; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci if (strcmp(node->supply, supply) != 0) 177462306a36Sopenharmony_ci continue; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci pr_debug("%s: %s/%s is '%s' supply; fail %s/%s\n", 177762306a36Sopenharmony_ci consumer_dev_name, 177862306a36Sopenharmony_ci dev_name(&node->regulator->dev), 177962306a36Sopenharmony_ci node->regulator->desc->name, 178062306a36Sopenharmony_ci supply, 178162306a36Sopenharmony_ci dev_name(&rdev->dev), rdev_get_name(rdev)); 178262306a36Sopenharmony_ci goto fail; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci list_add(&new_node->list, ®ulator_map_list); 178662306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci return 0; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_cifail: 179162306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 179262306a36Sopenharmony_ci kfree(new_node->dev_name); 179362306a36Sopenharmony_ci kfree(new_node); 179462306a36Sopenharmony_ci return -EBUSY; 179562306a36Sopenharmony_ci} 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cistatic void unset_regulator_supplies(struct regulator_dev *rdev) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci struct regulator_map *node, *n; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci list_for_each_entry_safe(node, n, ®ulator_map_list, list) { 180262306a36Sopenharmony_ci if (rdev == node->regulator) { 180362306a36Sopenharmony_ci list_del(&node->list); 180462306a36Sopenharmony_ci kfree(node->dev_name); 180562306a36Sopenharmony_ci kfree(node); 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci} 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 181162306a36Sopenharmony_cistatic ssize_t constraint_flags_read_file(struct file *file, 181262306a36Sopenharmony_ci char __user *user_buf, 181362306a36Sopenharmony_ci size_t count, loff_t *ppos) 181462306a36Sopenharmony_ci{ 181562306a36Sopenharmony_ci const struct regulator *regulator = file->private_data; 181662306a36Sopenharmony_ci const struct regulation_constraints *c = regulator->rdev->constraints; 181762306a36Sopenharmony_ci char *buf; 181862306a36Sopenharmony_ci ssize_t ret; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci if (!c) 182162306a36Sopenharmony_ci return 0; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 182462306a36Sopenharmony_ci if (!buf) 182562306a36Sopenharmony_ci return -ENOMEM; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci ret = snprintf(buf, PAGE_SIZE, 182862306a36Sopenharmony_ci "always_on: %u\n" 182962306a36Sopenharmony_ci "boot_on: %u\n" 183062306a36Sopenharmony_ci "apply_uV: %u\n" 183162306a36Sopenharmony_ci "ramp_disable: %u\n" 183262306a36Sopenharmony_ci "soft_start: %u\n" 183362306a36Sopenharmony_ci "pull_down: %u\n" 183462306a36Sopenharmony_ci "over_current_protection: %u\n", 183562306a36Sopenharmony_ci c->always_on, 183662306a36Sopenharmony_ci c->boot_on, 183762306a36Sopenharmony_ci c->apply_uV, 183862306a36Sopenharmony_ci c->ramp_disable, 183962306a36Sopenharmony_ci c->soft_start, 184062306a36Sopenharmony_ci c->pull_down, 184162306a36Sopenharmony_ci c->over_current_protection); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 184462306a36Sopenharmony_ci kfree(buf); 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci return ret; 184762306a36Sopenharmony_ci} 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci#endif 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_cistatic const struct file_operations constraint_flags_fops = { 185262306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 185362306a36Sopenharmony_ci .open = simple_open, 185462306a36Sopenharmony_ci .read = constraint_flags_read_file, 185562306a36Sopenharmony_ci .llseek = default_llseek, 185662306a36Sopenharmony_ci#endif 185762306a36Sopenharmony_ci}; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci#define REG_STR_SIZE 64 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_cistatic struct regulator *create_regulator(struct regulator_dev *rdev, 186262306a36Sopenharmony_ci struct device *dev, 186362306a36Sopenharmony_ci const char *supply_name) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci struct regulator *regulator; 186662306a36Sopenharmony_ci int err = 0; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (dev) { 187162306a36Sopenharmony_ci char buf[REG_STR_SIZE]; 187262306a36Sopenharmony_ci int size; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci size = snprintf(buf, REG_STR_SIZE, "%s-%s", 187562306a36Sopenharmony_ci dev->kobj.name, supply_name); 187662306a36Sopenharmony_ci if (size >= REG_STR_SIZE) 187762306a36Sopenharmony_ci return NULL; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci supply_name = kstrdup(buf, GFP_KERNEL); 188062306a36Sopenharmony_ci if (supply_name == NULL) 188162306a36Sopenharmony_ci return NULL; 188262306a36Sopenharmony_ci } else { 188362306a36Sopenharmony_ci supply_name = kstrdup_const(supply_name, GFP_KERNEL); 188462306a36Sopenharmony_ci if (supply_name == NULL) 188562306a36Sopenharmony_ci return NULL; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci regulator = kzalloc(sizeof(*regulator), GFP_KERNEL); 188962306a36Sopenharmony_ci if (regulator == NULL) { 189062306a36Sopenharmony_ci kfree_const(supply_name); 189162306a36Sopenharmony_ci return NULL; 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci regulator->rdev = rdev; 189562306a36Sopenharmony_ci regulator->supply_name = supply_name; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci list_add(®ulator->list, &rdev->consumer_list); 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci if (dev) { 190062306a36Sopenharmony_ci regulator->dev = dev; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci /* Add a link to the device sysfs entry */ 190362306a36Sopenharmony_ci err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj, 190462306a36Sopenharmony_ci supply_name); 190562306a36Sopenharmony_ci if (err) { 190662306a36Sopenharmony_ci rdev_dbg(rdev, "could not add device link %s: %pe\n", 190762306a36Sopenharmony_ci dev->kobj.name, ERR_PTR(err)); 190862306a36Sopenharmony_ci /* non-fatal */ 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci if (err != -EEXIST) 191362306a36Sopenharmony_ci regulator->debugfs = debugfs_create_dir(supply_name, rdev->debugfs); 191462306a36Sopenharmony_ci if (IS_ERR(regulator->debugfs)) 191562306a36Sopenharmony_ci rdev_dbg(rdev, "Failed to create debugfs directory\n"); 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci debugfs_create_u32("uA_load", 0444, regulator->debugfs, 191862306a36Sopenharmony_ci ®ulator->uA_load); 191962306a36Sopenharmony_ci debugfs_create_u32("min_uV", 0444, regulator->debugfs, 192062306a36Sopenharmony_ci ®ulator->voltage[PM_SUSPEND_ON].min_uV); 192162306a36Sopenharmony_ci debugfs_create_u32("max_uV", 0444, regulator->debugfs, 192262306a36Sopenharmony_ci ®ulator->voltage[PM_SUSPEND_ON].max_uV); 192362306a36Sopenharmony_ci debugfs_create_file("constraint_flags", 0444, regulator->debugfs, 192462306a36Sopenharmony_ci regulator, &constraint_flags_fops); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci /* 192762306a36Sopenharmony_ci * Check now if the regulator is an always on regulator - if 192862306a36Sopenharmony_ci * it is then we don't need to do nearly so much work for 192962306a36Sopenharmony_ci * enable/disable calls. 193062306a36Sopenharmony_ci */ 193162306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS) && 193262306a36Sopenharmony_ci _regulator_is_enabled(rdev)) 193362306a36Sopenharmony_ci regulator->always_on = true; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci return regulator; 193662306a36Sopenharmony_ci} 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_cistatic int _regulator_get_enable_time(struct regulator_dev *rdev) 193962306a36Sopenharmony_ci{ 194062306a36Sopenharmony_ci if (rdev->constraints && rdev->constraints->enable_time) 194162306a36Sopenharmony_ci return rdev->constraints->enable_time; 194262306a36Sopenharmony_ci if (rdev->desc->ops->enable_time) 194362306a36Sopenharmony_ci return rdev->desc->ops->enable_time(rdev); 194462306a36Sopenharmony_ci return rdev->desc->enable_time; 194562306a36Sopenharmony_ci} 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_cistatic struct regulator_supply_alias *regulator_find_supply_alias( 194862306a36Sopenharmony_ci struct device *dev, const char *supply) 194962306a36Sopenharmony_ci{ 195062306a36Sopenharmony_ci struct regulator_supply_alias *map; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci list_for_each_entry(map, ®ulator_supply_alias_list, list) 195362306a36Sopenharmony_ci if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0) 195462306a36Sopenharmony_ci return map; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci return NULL; 195762306a36Sopenharmony_ci} 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_cistatic void regulator_supply_alias(struct device **dev, const char **supply) 196062306a36Sopenharmony_ci{ 196162306a36Sopenharmony_ci struct regulator_supply_alias *map; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci map = regulator_find_supply_alias(*dev, *supply); 196462306a36Sopenharmony_ci if (map) { 196562306a36Sopenharmony_ci dev_dbg(*dev, "Mapping supply %s to %s,%s\n", 196662306a36Sopenharmony_ci *supply, map->alias_supply, 196762306a36Sopenharmony_ci dev_name(map->alias_dev)); 196862306a36Sopenharmony_ci *dev = map->alias_dev; 196962306a36Sopenharmony_ci *supply = map->alias_supply; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci} 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_cistatic int regulator_match(struct device *dev, const void *data) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci struct regulator_dev *r = dev_to_rdev(dev); 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci return strcmp(rdev_get_name(r), data) == 0; 197862306a36Sopenharmony_ci} 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_cistatic struct regulator_dev *regulator_lookup_by_name(const char *name) 198162306a36Sopenharmony_ci{ 198262306a36Sopenharmony_ci struct device *dev; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci dev = class_find_device(®ulator_class, NULL, name, regulator_match); 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci return dev ? dev_to_rdev(dev) : NULL; 198762306a36Sopenharmony_ci} 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci/** 199062306a36Sopenharmony_ci * regulator_dev_lookup - lookup a regulator device. 199162306a36Sopenharmony_ci * @dev: device for regulator "consumer". 199262306a36Sopenharmony_ci * @supply: Supply name or regulator ID. 199362306a36Sopenharmony_ci * 199462306a36Sopenharmony_ci * If successful, returns a struct regulator_dev that corresponds to the name 199562306a36Sopenharmony_ci * @supply and with the embedded struct device refcount incremented by one. 199662306a36Sopenharmony_ci * The refcount must be dropped by calling put_device(). 199762306a36Sopenharmony_ci * On failure one of the following ERR-PTR-encoded values is returned: 199862306a36Sopenharmony_ci * -ENODEV if lookup fails permanently, -EPROBE_DEFER if lookup could succeed 199962306a36Sopenharmony_ci * in the future. 200062306a36Sopenharmony_ci */ 200162306a36Sopenharmony_cistatic struct regulator_dev *regulator_dev_lookup(struct device *dev, 200262306a36Sopenharmony_ci const char *supply) 200362306a36Sopenharmony_ci{ 200462306a36Sopenharmony_ci struct regulator_dev *r = NULL; 200562306a36Sopenharmony_ci struct device_node *node; 200662306a36Sopenharmony_ci struct regulator_map *map; 200762306a36Sopenharmony_ci const char *devname = NULL; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci regulator_supply_alias(&dev, &supply); 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci /* first do a dt based lookup */ 201262306a36Sopenharmony_ci if (dev && dev->of_node) { 201362306a36Sopenharmony_ci node = of_get_regulator(dev, supply); 201462306a36Sopenharmony_ci if (node) { 201562306a36Sopenharmony_ci r = of_find_regulator_by_node(node); 201662306a36Sopenharmony_ci of_node_put(node); 201762306a36Sopenharmony_ci if (r) 201862306a36Sopenharmony_ci return r; 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci /* 202162306a36Sopenharmony_ci * We have a node, but there is no device. 202262306a36Sopenharmony_ci * assume it has not registered yet. 202362306a36Sopenharmony_ci */ 202462306a36Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci } 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci /* if not found, try doing it non-dt way */ 202962306a36Sopenharmony_ci if (dev) 203062306a36Sopenharmony_ci devname = dev_name(dev); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 203362306a36Sopenharmony_ci list_for_each_entry(map, ®ulator_map_list, list) { 203462306a36Sopenharmony_ci /* If the mapping has a device set up it must match */ 203562306a36Sopenharmony_ci if (map->dev_name && 203662306a36Sopenharmony_ci (!devname || strcmp(map->dev_name, devname))) 203762306a36Sopenharmony_ci continue; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (strcmp(map->supply, supply) == 0 && 204062306a36Sopenharmony_ci get_device(&map->regulator->dev)) { 204162306a36Sopenharmony_ci r = map->regulator; 204262306a36Sopenharmony_ci break; 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci } 204562306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (r) 204862306a36Sopenharmony_ci return r; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci r = regulator_lookup_by_name(supply); 205162306a36Sopenharmony_ci if (r) 205262306a36Sopenharmony_ci return r; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 205562306a36Sopenharmony_ci} 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_cistatic int regulator_resolve_supply(struct regulator_dev *rdev) 205862306a36Sopenharmony_ci{ 205962306a36Sopenharmony_ci struct regulator_dev *r; 206062306a36Sopenharmony_ci struct device *dev = rdev->dev.parent; 206162306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 206262306a36Sopenharmony_ci int ret = 0; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci /* No supply to resolve? */ 206562306a36Sopenharmony_ci if (!rdev->supply_name) 206662306a36Sopenharmony_ci return 0; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci /* Supply already resolved? (fast-path without locking contention) */ 206962306a36Sopenharmony_ci if (rdev->supply) 207062306a36Sopenharmony_ci return 0; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci r = regulator_dev_lookup(dev, rdev->supply_name); 207362306a36Sopenharmony_ci if (IS_ERR(r)) { 207462306a36Sopenharmony_ci ret = PTR_ERR(r); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci /* Did the lookup explicitly defer for us? */ 207762306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 207862306a36Sopenharmony_ci goto out; 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (have_full_constraints()) { 208162306a36Sopenharmony_ci r = dummy_regulator_rdev; 208262306a36Sopenharmony_ci get_device(&r->dev); 208362306a36Sopenharmony_ci } else { 208462306a36Sopenharmony_ci dev_err(dev, "Failed to resolve %s-supply for %s\n", 208562306a36Sopenharmony_ci rdev->supply_name, rdev->desc->name); 208662306a36Sopenharmony_ci ret = -EPROBE_DEFER; 208762306a36Sopenharmony_ci goto out; 208862306a36Sopenharmony_ci } 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci if (r == rdev) { 209262306a36Sopenharmony_ci dev_err(dev, "Supply for %s (%s) resolved to itself\n", 209362306a36Sopenharmony_ci rdev->desc->name, rdev->supply_name); 209462306a36Sopenharmony_ci if (!have_full_constraints()) { 209562306a36Sopenharmony_ci ret = -EINVAL; 209662306a36Sopenharmony_ci goto out; 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci r = dummy_regulator_rdev; 209962306a36Sopenharmony_ci get_device(&r->dev); 210062306a36Sopenharmony_ci } 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* 210362306a36Sopenharmony_ci * If the supply's parent device is not the same as the 210462306a36Sopenharmony_ci * regulator's parent device, then ensure the parent device 210562306a36Sopenharmony_ci * is bound before we resolve the supply, in case the parent 210662306a36Sopenharmony_ci * device get probe deferred and unregisters the supply. 210762306a36Sopenharmony_ci */ 210862306a36Sopenharmony_ci if (r->dev.parent && r->dev.parent != rdev->dev.parent) { 210962306a36Sopenharmony_ci if (!device_is_bound(r->dev.parent)) { 211062306a36Sopenharmony_ci put_device(&r->dev); 211162306a36Sopenharmony_ci ret = -EPROBE_DEFER; 211262306a36Sopenharmony_ci goto out; 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci } 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci /* Recursively resolve the supply of the supply */ 211762306a36Sopenharmony_ci ret = regulator_resolve_supply(r); 211862306a36Sopenharmony_ci if (ret < 0) { 211962306a36Sopenharmony_ci put_device(&r->dev); 212062306a36Sopenharmony_ci goto out; 212162306a36Sopenharmony_ci } 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci /* 212462306a36Sopenharmony_ci * Recheck rdev->supply with rdev->mutex lock held to avoid a race 212562306a36Sopenharmony_ci * between rdev->supply null check and setting rdev->supply in 212662306a36Sopenharmony_ci * set_supply() from concurrent tasks. 212762306a36Sopenharmony_ci */ 212862306a36Sopenharmony_ci regulator_lock_two(rdev, r, &ww_ctx); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci /* Supply just resolved by a concurrent task? */ 213162306a36Sopenharmony_ci if (rdev->supply) { 213262306a36Sopenharmony_ci regulator_unlock_two(rdev, r, &ww_ctx); 213362306a36Sopenharmony_ci put_device(&r->dev); 213462306a36Sopenharmony_ci goto out; 213562306a36Sopenharmony_ci } 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci ret = set_supply(rdev, r); 213862306a36Sopenharmony_ci if (ret < 0) { 213962306a36Sopenharmony_ci regulator_unlock_two(rdev, r, &ww_ctx); 214062306a36Sopenharmony_ci put_device(&r->dev); 214162306a36Sopenharmony_ci goto out; 214262306a36Sopenharmony_ci } 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci regulator_unlock_two(rdev, r, &ww_ctx); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci /* 214762306a36Sopenharmony_ci * In set_machine_constraints() we may have turned this regulator on 214862306a36Sopenharmony_ci * but we couldn't propagate to the supply if it hadn't been resolved 214962306a36Sopenharmony_ci * yet. Do it now. 215062306a36Sopenharmony_ci */ 215162306a36Sopenharmony_ci if (rdev->use_count) { 215262306a36Sopenharmony_ci ret = regulator_enable(rdev->supply); 215362306a36Sopenharmony_ci if (ret < 0) { 215462306a36Sopenharmony_ci _regulator_put(rdev->supply); 215562306a36Sopenharmony_ci rdev->supply = NULL; 215662306a36Sopenharmony_ci goto out; 215762306a36Sopenharmony_ci } 215862306a36Sopenharmony_ci } 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ciout: 216162306a36Sopenharmony_ci return ret; 216262306a36Sopenharmony_ci} 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci/* Internal regulator request function */ 216562306a36Sopenharmony_cistruct regulator *_regulator_get(struct device *dev, const char *id, 216662306a36Sopenharmony_ci enum regulator_get_type get_type) 216762306a36Sopenharmony_ci{ 216862306a36Sopenharmony_ci struct regulator_dev *rdev; 216962306a36Sopenharmony_ci struct regulator *regulator; 217062306a36Sopenharmony_ci struct device_link *link; 217162306a36Sopenharmony_ci int ret; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci if (get_type >= MAX_GET_TYPE) { 217462306a36Sopenharmony_ci dev_err(dev, "invalid type %d in %s\n", get_type, __func__); 217562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 217662306a36Sopenharmony_ci } 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci if (id == NULL) { 217962306a36Sopenharmony_ci pr_err("get() with no identifier\n"); 218062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 218162306a36Sopenharmony_ci } 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci rdev = regulator_dev_lookup(dev, id); 218462306a36Sopenharmony_ci if (IS_ERR(rdev)) { 218562306a36Sopenharmony_ci ret = PTR_ERR(rdev); 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci /* 218862306a36Sopenharmony_ci * If regulator_dev_lookup() fails with error other 218962306a36Sopenharmony_ci * than -ENODEV our job here is done, we simply return it. 219062306a36Sopenharmony_ci */ 219162306a36Sopenharmony_ci if (ret != -ENODEV) 219262306a36Sopenharmony_ci return ERR_PTR(ret); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci if (!have_full_constraints()) { 219562306a36Sopenharmony_ci dev_warn(dev, 219662306a36Sopenharmony_ci "incomplete constraints, dummy supplies not allowed\n"); 219762306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci switch (get_type) { 220162306a36Sopenharmony_ci case NORMAL_GET: 220262306a36Sopenharmony_ci /* 220362306a36Sopenharmony_ci * Assume that a regulator is physically present and 220462306a36Sopenharmony_ci * enabled, even if it isn't hooked up, and just 220562306a36Sopenharmony_ci * provide a dummy. 220662306a36Sopenharmony_ci */ 220762306a36Sopenharmony_ci dev_warn(dev, "supply %s not found, using dummy regulator\n", id); 220862306a36Sopenharmony_ci rdev = dummy_regulator_rdev; 220962306a36Sopenharmony_ci get_device(&rdev->dev); 221062306a36Sopenharmony_ci break; 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci case EXCLUSIVE_GET: 221362306a36Sopenharmony_ci dev_warn(dev, 221462306a36Sopenharmony_ci "dummy supplies not allowed for exclusive requests\n"); 221562306a36Sopenharmony_ci fallthrough; 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci default: 221862306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 221962306a36Sopenharmony_ci } 222062306a36Sopenharmony_ci } 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci if (rdev->exclusive) { 222362306a36Sopenharmony_ci regulator = ERR_PTR(-EPERM); 222462306a36Sopenharmony_ci put_device(&rdev->dev); 222562306a36Sopenharmony_ci return regulator; 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci if (get_type == EXCLUSIVE_GET && rdev->open_count) { 222962306a36Sopenharmony_ci regulator = ERR_PTR(-EBUSY); 223062306a36Sopenharmony_ci put_device(&rdev->dev); 223162306a36Sopenharmony_ci return regulator; 223262306a36Sopenharmony_ci } 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 223562306a36Sopenharmony_ci ret = (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled); 223662306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci if (ret != 0) { 223962306a36Sopenharmony_ci regulator = ERR_PTR(-EPROBE_DEFER); 224062306a36Sopenharmony_ci put_device(&rdev->dev); 224162306a36Sopenharmony_ci return regulator; 224262306a36Sopenharmony_ci } 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci ret = regulator_resolve_supply(rdev); 224562306a36Sopenharmony_ci if (ret < 0) { 224662306a36Sopenharmony_ci regulator = ERR_PTR(ret); 224762306a36Sopenharmony_ci put_device(&rdev->dev); 224862306a36Sopenharmony_ci return regulator; 224962306a36Sopenharmony_ci } 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci if (!try_module_get(rdev->owner)) { 225262306a36Sopenharmony_ci regulator = ERR_PTR(-EPROBE_DEFER); 225362306a36Sopenharmony_ci put_device(&rdev->dev); 225462306a36Sopenharmony_ci return regulator; 225562306a36Sopenharmony_ci } 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci regulator_lock(rdev); 225862306a36Sopenharmony_ci regulator = create_regulator(rdev, dev, id); 225962306a36Sopenharmony_ci regulator_unlock(rdev); 226062306a36Sopenharmony_ci if (regulator == NULL) { 226162306a36Sopenharmony_ci regulator = ERR_PTR(-ENOMEM); 226262306a36Sopenharmony_ci module_put(rdev->owner); 226362306a36Sopenharmony_ci put_device(&rdev->dev); 226462306a36Sopenharmony_ci return regulator; 226562306a36Sopenharmony_ci } 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci rdev->open_count++; 226862306a36Sopenharmony_ci if (get_type == EXCLUSIVE_GET) { 226962306a36Sopenharmony_ci rdev->exclusive = 1; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci ret = _regulator_is_enabled(rdev); 227262306a36Sopenharmony_ci if (ret > 0) { 227362306a36Sopenharmony_ci rdev->use_count = 1; 227462306a36Sopenharmony_ci regulator->enable_count = 1; 227562306a36Sopenharmony_ci } else { 227662306a36Sopenharmony_ci rdev->use_count = 0; 227762306a36Sopenharmony_ci regulator->enable_count = 0; 227862306a36Sopenharmony_ci } 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci link = device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS); 228262306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(link)) 228362306a36Sopenharmony_ci regulator->device_link = true; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci return regulator; 228662306a36Sopenharmony_ci} 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci/** 228962306a36Sopenharmony_ci * regulator_get - lookup and obtain a reference to a regulator. 229062306a36Sopenharmony_ci * @dev: device for regulator "consumer" 229162306a36Sopenharmony_ci * @id: Supply name or regulator ID. 229262306a36Sopenharmony_ci * 229362306a36Sopenharmony_ci * Returns a struct regulator corresponding to the regulator producer, 229462306a36Sopenharmony_ci * or IS_ERR() condition containing errno. 229562306a36Sopenharmony_ci * 229662306a36Sopenharmony_ci * Use of supply names configured via set_consumer_device_supply() is 229762306a36Sopenharmony_ci * strongly encouraged. It is recommended that the supply name used 229862306a36Sopenharmony_ci * should match the name used for the supply and/or the relevant 229962306a36Sopenharmony_ci * device pins in the datasheet. 230062306a36Sopenharmony_ci */ 230162306a36Sopenharmony_cistruct regulator *regulator_get(struct device *dev, const char *id) 230262306a36Sopenharmony_ci{ 230362306a36Sopenharmony_ci return _regulator_get(dev, id, NORMAL_GET); 230462306a36Sopenharmony_ci} 230562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci/** 230862306a36Sopenharmony_ci * regulator_get_exclusive - obtain exclusive access to a regulator. 230962306a36Sopenharmony_ci * @dev: device for regulator "consumer" 231062306a36Sopenharmony_ci * @id: Supply name or regulator ID. 231162306a36Sopenharmony_ci * 231262306a36Sopenharmony_ci * Returns a struct regulator corresponding to the regulator producer, 231362306a36Sopenharmony_ci * or IS_ERR() condition containing errno. Other consumers will be 231462306a36Sopenharmony_ci * unable to obtain this regulator while this reference is held and the 231562306a36Sopenharmony_ci * use count for the regulator will be initialised to reflect the current 231662306a36Sopenharmony_ci * state of the regulator. 231762306a36Sopenharmony_ci * 231862306a36Sopenharmony_ci * This is intended for use by consumers which cannot tolerate shared 231962306a36Sopenharmony_ci * use of the regulator such as those which need to force the 232062306a36Sopenharmony_ci * regulator off for correct operation of the hardware they are 232162306a36Sopenharmony_ci * controlling. 232262306a36Sopenharmony_ci * 232362306a36Sopenharmony_ci * Use of supply names configured via set_consumer_device_supply() is 232462306a36Sopenharmony_ci * strongly encouraged. It is recommended that the supply name used 232562306a36Sopenharmony_ci * should match the name used for the supply and/or the relevant 232662306a36Sopenharmony_ci * device pins in the datasheet. 232762306a36Sopenharmony_ci */ 232862306a36Sopenharmony_cistruct regulator *regulator_get_exclusive(struct device *dev, const char *id) 232962306a36Sopenharmony_ci{ 233062306a36Sopenharmony_ci return _regulator_get(dev, id, EXCLUSIVE_GET); 233162306a36Sopenharmony_ci} 233262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_exclusive); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci/** 233562306a36Sopenharmony_ci * regulator_get_optional - obtain optional access to a regulator. 233662306a36Sopenharmony_ci * @dev: device for regulator "consumer" 233762306a36Sopenharmony_ci * @id: Supply name or regulator ID. 233862306a36Sopenharmony_ci * 233962306a36Sopenharmony_ci * Returns a struct regulator corresponding to the regulator producer, 234062306a36Sopenharmony_ci * or IS_ERR() condition containing errno. 234162306a36Sopenharmony_ci * 234262306a36Sopenharmony_ci * This is intended for use by consumers for devices which can have 234362306a36Sopenharmony_ci * some supplies unconnected in normal use, such as some MMC devices. 234462306a36Sopenharmony_ci * It can allow the regulator core to provide stub supplies for other 234562306a36Sopenharmony_ci * supplies requested using normal regulator_get() calls without 234662306a36Sopenharmony_ci * disrupting the operation of drivers that can handle absent 234762306a36Sopenharmony_ci * supplies. 234862306a36Sopenharmony_ci * 234962306a36Sopenharmony_ci * Use of supply names configured via set_consumer_device_supply() is 235062306a36Sopenharmony_ci * strongly encouraged. It is recommended that the supply name used 235162306a36Sopenharmony_ci * should match the name used for the supply and/or the relevant 235262306a36Sopenharmony_ci * device pins in the datasheet. 235362306a36Sopenharmony_ci */ 235462306a36Sopenharmony_cistruct regulator *regulator_get_optional(struct device *dev, const char *id) 235562306a36Sopenharmony_ci{ 235662306a36Sopenharmony_ci return _regulator_get(dev, id, OPTIONAL_GET); 235762306a36Sopenharmony_ci} 235862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_optional); 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_cistatic void destroy_regulator(struct regulator *regulator) 236162306a36Sopenharmony_ci{ 236262306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci debugfs_remove_recursive(regulator->debugfs); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci if (regulator->dev) { 236762306a36Sopenharmony_ci if (regulator->device_link) 236862306a36Sopenharmony_ci device_link_remove(regulator->dev, &rdev->dev); 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci /* remove any sysfs entries */ 237162306a36Sopenharmony_ci sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci regulator_lock(rdev); 237562306a36Sopenharmony_ci list_del(®ulator->list); 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci rdev->open_count--; 237862306a36Sopenharmony_ci rdev->exclusive = 0; 237962306a36Sopenharmony_ci regulator_unlock(rdev); 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci kfree_const(regulator->supply_name); 238262306a36Sopenharmony_ci kfree(regulator); 238362306a36Sopenharmony_ci} 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci/* regulator_list_mutex lock held by regulator_put() */ 238662306a36Sopenharmony_cistatic void _regulator_put(struct regulator *regulator) 238762306a36Sopenharmony_ci{ 238862306a36Sopenharmony_ci struct regulator_dev *rdev; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci if (IS_ERR_OR_NULL(regulator)) 239162306a36Sopenharmony_ci return; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci lockdep_assert_held_once(®ulator_list_mutex); 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci /* Docs say you must disable before calling regulator_put() */ 239662306a36Sopenharmony_ci WARN_ON(regulator->enable_count); 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci rdev = regulator->rdev; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci destroy_regulator(regulator); 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci module_put(rdev->owner); 240362306a36Sopenharmony_ci put_device(&rdev->dev); 240462306a36Sopenharmony_ci} 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci/** 240762306a36Sopenharmony_ci * regulator_put - "free" the regulator source 240862306a36Sopenharmony_ci * @regulator: regulator source 240962306a36Sopenharmony_ci * 241062306a36Sopenharmony_ci * Note: drivers must ensure that all regulator_enable calls made on this 241162306a36Sopenharmony_ci * regulator source are balanced by regulator_disable calls prior to calling 241262306a36Sopenharmony_ci * this function. 241362306a36Sopenharmony_ci */ 241462306a36Sopenharmony_civoid regulator_put(struct regulator *regulator) 241562306a36Sopenharmony_ci{ 241662306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 241762306a36Sopenharmony_ci _regulator_put(regulator); 241862306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 241962306a36Sopenharmony_ci} 242062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_put); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci/** 242362306a36Sopenharmony_ci * regulator_register_supply_alias - Provide device alias for supply lookup 242462306a36Sopenharmony_ci * 242562306a36Sopenharmony_ci * @dev: device that will be given as the regulator "consumer" 242662306a36Sopenharmony_ci * @id: Supply name or regulator ID 242762306a36Sopenharmony_ci * @alias_dev: device that should be used to lookup the supply 242862306a36Sopenharmony_ci * @alias_id: Supply name or regulator ID that should be used to lookup the 242962306a36Sopenharmony_ci * supply 243062306a36Sopenharmony_ci * 243162306a36Sopenharmony_ci * All lookups for id on dev will instead be conducted for alias_id on 243262306a36Sopenharmony_ci * alias_dev. 243362306a36Sopenharmony_ci */ 243462306a36Sopenharmony_ciint regulator_register_supply_alias(struct device *dev, const char *id, 243562306a36Sopenharmony_ci struct device *alias_dev, 243662306a36Sopenharmony_ci const char *alias_id) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci struct regulator_supply_alias *map; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci map = regulator_find_supply_alias(dev, id); 244162306a36Sopenharmony_ci if (map) 244262306a36Sopenharmony_ci return -EEXIST; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); 244562306a36Sopenharmony_ci if (!map) 244662306a36Sopenharmony_ci return -ENOMEM; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci map->src_dev = dev; 244962306a36Sopenharmony_ci map->src_supply = id; 245062306a36Sopenharmony_ci map->alias_dev = alias_dev; 245162306a36Sopenharmony_ci map->alias_supply = alias_id; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci list_add(&map->list, ®ulator_supply_alias_list); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci pr_info("Adding alias for supply %s,%s -> %s,%s\n", 245662306a36Sopenharmony_ci id, dev_name(dev), alias_id, dev_name(alias_dev)); 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci return 0; 245962306a36Sopenharmony_ci} 246062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_register_supply_alias); 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci/** 246362306a36Sopenharmony_ci * regulator_unregister_supply_alias - Remove device alias 246462306a36Sopenharmony_ci * 246562306a36Sopenharmony_ci * @dev: device that will be given as the regulator "consumer" 246662306a36Sopenharmony_ci * @id: Supply name or regulator ID 246762306a36Sopenharmony_ci * 246862306a36Sopenharmony_ci * Remove a lookup alias if one exists for id on dev. 246962306a36Sopenharmony_ci */ 247062306a36Sopenharmony_civoid regulator_unregister_supply_alias(struct device *dev, const char *id) 247162306a36Sopenharmony_ci{ 247262306a36Sopenharmony_ci struct regulator_supply_alias *map; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci map = regulator_find_supply_alias(dev, id); 247562306a36Sopenharmony_ci if (map) { 247662306a36Sopenharmony_ci list_del(&map->list); 247762306a36Sopenharmony_ci kfree(map); 247862306a36Sopenharmony_ci } 247962306a36Sopenharmony_ci} 248062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci/** 248362306a36Sopenharmony_ci * regulator_bulk_register_supply_alias - register multiple aliases 248462306a36Sopenharmony_ci * 248562306a36Sopenharmony_ci * @dev: device that will be given as the regulator "consumer" 248662306a36Sopenharmony_ci * @id: List of supply names or regulator IDs 248762306a36Sopenharmony_ci * @alias_dev: device that should be used to lookup the supply 248862306a36Sopenharmony_ci * @alias_id: List of supply names or regulator IDs that should be used to 248962306a36Sopenharmony_ci * lookup the supply 249062306a36Sopenharmony_ci * @num_id: Number of aliases to register 249162306a36Sopenharmony_ci * 249262306a36Sopenharmony_ci * @return 0 on success, an errno on failure. 249362306a36Sopenharmony_ci * 249462306a36Sopenharmony_ci * This helper function allows drivers to register several supply 249562306a36Sopenharmony_ci * aliases in one operation. If any of the aliases cannot be 249662306a36Sopenharmony_ci * registered any aliases that were registered will be removed 249762306a36Sopenharmony_ci * before returning to the caller. 249862306a36Sopenharmony_ci */ 249962306a36Sopenharmony_ciint regulator_bulk_register_supply_alias(struct device *dev, 250062306a36Sopenharmony_ci const char *const *id, 250162306a36Sopenharmony_ci struct device *alias_dev, 250262306a36Sopenharmony_ci const char *const *alias_id, 250362306a36Sopenharmony_ci int num_id) 250462306a36Sopenharmony_ci{ 250562306a36Sopenharmony_ci int i; 250662306a36Sopenharmony_ci int ret; 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci for (i = 0; i < num_id; ++i) { 250962306a36Sopenharmony_ci ret = regulator_register_supply_alias(dev, id[i], alias_dev, 251062306a36Sopenharmony_ci alias_id[i]); 251162306a36Sopenharmony_ci if (ret < 0) 251262306a36Sopenharmony_ci goto err; 251362306a36Sopenharmony_ci } 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci return 0; 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_cierr: 251862306a36Sopenharmony_ci dev_err(dev, 251962306a36Sopenharmony_ci "Failed to create supply alias %s,%s -> %s,%s\n", 252062306a36Sopenharmony_ci id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci while (--i >= 0) 252362306a36Sopenharmony_ci regulator_unregister_supply_alias(dev, id[i]); 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci return ret; 252662306a36Sopenharmony_ci} 252762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias); 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci/** 253062306a36Sopenharmony_ci * regulator_bulk_unregister_supply_alias - unregister multiple aliases 253162306a36Sopenharmony_ci * 253262306a36Sopenharmony_ci * @dev: device that will be given as the regulator "consumer" 253362306a36Sopenharmony_ci * @id: List of supply names or regulator IDs 253462306a36Sopenharmony_ci * @num_id: Number of aliases to unregister 253562306a36Sopenharmony_ci * 253662306a36Sopenharmony_ci * This helper function allows drivers to unregister several supply 253762306a36Sopenharmony_ci * aliases in one operation. 253862306a36Sopenharmony_ci */ 253962306a36Sopenharmony_civoid regulator_bulk_unregister_supply_alias(struct device *dev, 254062306a36Sopenharmony_ci const char *const *id, 254162306a36Sopenharmony_ci int num_id) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci int i; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci for (i = 0; i < num_id; ++i) 254662306a36Sopenharmony_ci regulator_unregister_supply_alias(dev, id[i]); 254762306a36Sopenharmony_ci} 254862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias); 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci/* Manage enable GPIO list. Same GPIO pin can be shared among regulators */ 255262306a36Sopenharmony_cistatic int regulator_ena_gpio_request(struct regulator_dev *rdev, 255362306a36Sopenharmony_ci const struct regulator_config *config) 255462306a36Sopenharmony_ci{ 255562306a36Sopenharmony_ci struct regulator_enable_gpio *pin, *new_pin; 255662306a36Sopenharmony_ci struct gpio_desc *gpiod; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci gpiod = config->ena_gpiod; 255962306a36Sopenharmony_ci new_pin = kzalloc(sizeof(*new_pin), GFP_KERNEL); 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { 256462306a36Sopenharmony_ci if (pin->gpiod == gpiod) { 256562306a36Sopenharmony_ci rdev_dbg(rdev, "GPIO is already used\n"); 256662306a36Sopenharmony_ci goto update_ena_gpio_to_rdev; 256762306a36Sopenharmony_ci } 256862306a36Sopenharmony_ci } 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci if (new_pin == NULL) { 257162306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 257262306a36Sopenharmony_ci return -ENOMEM; 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci pin = new_pin; 257662306a36Sopenharmony_ci new_pin = NULL; 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci pin->gpiod = gpiod; 257962306a36Sopenharmony_ci list_add(&pin->list, ®ulator_ena_gpio_list); 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ciupdate_ena_gpio_to_rdev: 258262306a36Sopenharmony_ci pin->request_count++; 258362306a36Sopenharmony_ci rdev->ena_pin = pin; 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 258662306a36Sopenharmony_ci kfree(new_pin); 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci return 0; 258962306a36Sopenharmony_ci} 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_cistatic void regulator_ena_gpio_free(struct regulator_dev *rdev) 259262306a36Sopenharmony_ci{ 259362306a36Sopenharmony_ci struct regulator_enable_gpio *pin, *n; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci if (!rdev->ena_pin) 259662306a36Sopenharmony_ci return; 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci /* Free the GPIO only in case of no use */ 259962306a36Sopenharmony_ci list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { 260062306a36Sopenharmony_ci if (pin != rdev->ena_pin) 260162306a36Sopenharmony_ci continue; 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci if (--pin->request_count) 260462306a36Sopenharmony_ci break; 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci gpiod_put(pin->gpiod); 260762306a36Sopenharmony_ci list_del(&pin->list); 260862306a36Sopenharmony_ci kfree(pin); 260962306a36Sopenharmony_ci break; 261062306a36Sopenharmony_ci } 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci rdev->ena_pin = NULL; 261362306a36Sopenharmony_ci} 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci/** 261662306a36Sopenharmony_ci * regulator_ena_gpio_ctrl - balance enable_count of each GPIO and actual GPIO pin control 261762306a36Sopenharmony_ci * @rdev: regulator_dev structure 261862306a36Sopenharmony_ci * @enable: enable GPIO at initial use? 261962306a36Sopenharmony_ci * 262062306a36Sopenharmony_ci * GPIO is enabled in case of initial use. (enable_count is 0) 262162306a36Sopenharmony_ci * GPIO is disabled when it is not shared any more. (enable_count <= 1) 262262306a36Sopenharmony_ci */ 262362306a36Sopenharmony_cistatic int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) 262462306a36Sopenharmony_ci{ 262562306a36Sopenharmony_ci struct regulator_enable_gpio *pin = rdev->ena_pin; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci if (!pin) 262862306a36Sopenharmony_ci return -EINVAL; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci if (enable) { 263162306a36Sopenharmony_ci /* Enable GPIO at initial use */ 263262306a36Sopenharmony_ci if (pin->enable_count == 0) 263362306a36Sopenharmony_ci gpiod_set_value_cansleep(pin->gpiod, 1); 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci pin->enable_count++; 263662306a36Sopenharmony_ci } else { 263762306a36Sopenharmony_ci if (pin->enable_count > 1) { 263862306a36Sopenharmony_ci pin->enable_count--; 263962306a36Sopenharmony_ci return 0; 264062306a36Sopenharmony_ci } 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci /* Disable GPIO if not used */ 264362306a36Sopenharmony_ci if (pin->enable_count <= 1) { 264462306a36Sopenharmony_ci gpiod_set_value_cansleep(pin->gpiod, 0); 264562306a36Sopenharmony_ci pin->enable_count = 0; 264662306a36Sopenharmony_ci } 264762306a36Sopenharmony_ci } 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci return 0; 265062306a36Sopenharmony_ci} 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci/** 265362306a36Sopenharmony_ci * _regulator_delay_helper - a delay helper function 265462306a36Sopenharmony_ci * @delay: time to delay in microseconds 265562306a36Sopenharmony_ci * 265662306a36Sopenharmony_ci * Delay for the requested amount of time as per the guidelines in: 265762306a36Sopenharmony_ci * 265862306a36Sopenharmony_ci * Documentation/timers/timers-howto.rst 265962306a36Sopenharmony_ci * 266062306a36Sopenharmony_ci * The assumption here is that these regulator operations will never used in 266162306a36Sopenharmony_ci * atomic context and therefore sleeping functions can be used. 266262306a36Sopenharmony_ci */ 266362306a36Sopenharmony_cistatic void _regulator_delay_helper(unsigned int delay) 266462306a36Sopenharmony_ci{ 266562306a36Sopenharmony_ci unsigned int ms = delay / 1000; 266662306a36Sopenharmony_ci unsigned int us = delay % 1000; 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci if (ms > 0) { 266962306a36Sopenharmony_ci /* 267062306a36Sopenharmony_ci * For small enough values, handle super-millisecond 267162306a36Sopenharmony_ci * delays in the usleep_range() call below. 267262306a36Sopenharmony_ci */ 267362306a36Sopenharmony_ci if (ms < 20) 267462306a36Sopenharmony_ci us += ms * 1000; 267562306a36Sopenharmony_ci else 267662306a36Sopenharmony_ci msleep(ms); 267762306a36Sopenharmony_ci } 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci /* 268062306a36Sopenharmony_ci * Give the scheduler some room to coalesce with any other 268162306a36Sopenharmony_ci * wakeup sources. For delays shorter than 10 us, don't even 268262306a36Sopenharmony_ci * bother setting up high-resolution timers and just busy- 268362306a36Sopenharmony_ci * loop. 268462306a36Sopenharmony_ci */ 268562306a36Sopenharmony_ci if (us >= 10) 268662306a36Sopenharmony_ci usleep_range(us, us + 100); 268762306a36Sopenharmony_ci else 268862306a36Sopenharmony_ci udelay(us); 268962306a36Sopenharmony_ci} 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci/** 269262306a36Sopenharmony_ci * _regulator_check_status_enabled 269362306a36Sopenharmony_ci * 269462306a36Sopenharmony_ci * A helper function to check if the regulator status can be interpreted 269562306a36Sopenharmony_ci * as 'regulator is enabled'. 269662306a36Sopenharmony_ci * @rdev: the regulator device to check 269762306a36Sopenharmony_ci * 269862306a36Sopenharmony_ci * Return: 269962306a36Sopenharmony_ci * * 1 - if status shows regulator is in enabled state 270062306a36Sopenharmony_ci * * 0 - if not enabled state 270162306a36Sopenharmony_ci * * Error Value - as received from ops->get_status() 270262306a36Sopenharmony_ci */ 270362306a36Sopenharmony_cistatic inline int _regulator_check_status_enabled(struct regulator_dev *rdev) 270462306a36Sopenharmony_ci{ 270562306a36Sopenharmony_ci int ret = rdev->desc->ops->get_status(rdev); 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci if (ret < 0) { 270862306a36Sopenharmony_ci rdev_info(rdev, "get_status returned error: %d\n", ret); 270962306a36Sopenharmony_ci return ret; 271062306a36Sopenharmony_ci } 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci switch (ret) { 271362306a36Sopenharmony_ci case REGULATOR_STATUS_OFF: 271462306a36Sopenharmony_ci case REGULATOR_STATUS_ERROR: 271562306a36Sopenharmony_ci case REGULATOR_STATUS_UNDEFINED: 271662306a36Sopenharmony_ci return 0; 271762306a36Sopenharmony_ci default: 271862306a36Sopenharmony_ci return 1; 271962306a36Sopenharmony_ci } 272062306a36Sopenharmony_ci} 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_cistatic int _regulator_do_enable(struct regulator_dev *rdev) 272362306a36Sopenharmony_ci{ 272462306a36Sopenharmony_ci int ret, delay; 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci /* Query before enabling in case configuration dependent. */ 272762306a36Sopenharmony_ci ret = _regulator_get_enable_time(rdev); 272862306a36Sopenharmony_ci if (ret >= 0) { 272962306a36Sopenharmony_ci delay = ret; 273062306a36Sopenharmony_ci } else { 273162306a36Sopenharmony_ci rdev_warn(rdev, "enable_time() failed: %pe\n", ERR_PTR(ret)); 273262306a36Sopenharmony_ci delay = 0; 273362306a36Sopenharmony_ci } 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci trace_regulator_enable(rdev_get_name(rdev)); 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci if (rdev->desc->off_on_delay) { 273862306a36Sopenharmony_ci /* if needed, keep a distance of off_on_delay from last time 273962306a36Sopenharmony_ci * this regulator was disabled. 274062306a36Sopenharmony_ci */ 274162306a36Sopenharmony_ci ktime_t end = ktime_add_us(rdev->last_off, rdev->desc->off_on_delay); 274262306a36Sopenharmony_ci s64 remaining = ktime_us_delta(end, ktime_get_boottime()); 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci if (remaining > 0) 274562306a36Sopenharmony_ci _regulator_delay_helper(remaining); 274662306a36Sopenharmony_ci } 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci if (rdev->ena_pin) { 274962306a36Sopenharmony_ci if (!rdev->ena_gpio_state) { 275062306a36Sopenharmony_ci ret = regulator_ena_gpio_ctrl(rdev, true); 275162306a36Sopenharmony_ci if (ret < 0) 275262306a36Sopenharmony_ci return ret; 275362306a36Sopenharmony_ci rdev->ena_gpio_state = 1; 275462306a36Sopenharmony_ci } 275562306a36Sopenharmony_ci } else if (rdev->desc->ops->enable) { 275662306a36Sopenharmony_ci ret = rdev->desc->ops->enable(rdev); 275762306a36Sopenharmony_ci if (ret < 0) 275862306a36Sopenharmony_ci return ret; 275962306a36Sopenharmony_ci } else { 276062306a36Sopenharmony_ci return -EINVAL; 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci /* Allow the regulator to ramp; it would be useful to extend 276462306a36Sopenharmony_ci * this for bulk operations so that the regulators can ramp 276562306a36Sopenharmony_ci * together. 276662306a36Sopenharmony_ci */ 276762306a36Sopenharmony_ci trace_regulator_enable_delay(rdev_get_name(rdev)); 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci /* If poll_enabled_time is set, poll upto the delay calculated 277062306a36Sopenharmony_ci * above, delaying poll_enabled_time uS to check if the regulator 277162306a36Sopenharmony_ci * actually got enabled. 277262306a36Sopenharmony_ci * If the regulator isn't enabled after our delay helper has expired, 277362306a36Sopenharmony_ci * return -ETIMEDOUT. 277462306a36Sopenharmony_ci */ 277562306a36Sopenharmony_ci if (rdev->desc->poll_enabled_time) { 277662306a36Sopenharmony_ci int time_remaining = delay; 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci while (time_remaining > 0) { 277962306a36Sopenharmony_ci _regulator_delay_helper(rdev->desc->poll_enabled_time); 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci if (rdev->desc->ops->get_status) { 278262306a36Sopenharmony_ci ret = _regulator_check_status_enabled(rdev); 278362306a36Sopenharmony_ci if (ret < 0) 278462306a36Sopenharmony_ci return ret; 278562306a36Sopenharmony_ci else if (ret) 278662306a36Sopenharmony_ci break; 278762306a36Sopenharmony_ci } else if (rdev->desc->ops->is_enabled(rdev)) 278862306a36Sopenharmony_ci break; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci time_remaining -= rdev->desc->poll_enabled_time; 279162306a36Sopenharmony_ci } 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci if (time_remaining <= 0) { 279462306a36Sopenharmony_ci rdev_err(rdev, "Enabled check timed out\n"); 279562306a36Sopenharmony_ci return -ETIMEDOUT; 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci } else { 279862306a36Sopenharmony_ci _regulator_delay_helper(delay); 279962306a36Sopenharmony_ci } 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci trace_regulator_enable_complete(rdev_get_name(rdev)); 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci return 0; 280462306a36Sopenharmony_ci} 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci/** 280762306a36Sopenharmony_ci * _regulator_handle_consumer_enable - handle that a consumer enabled 280862306a36Sopenharmony_ci * @regulator: regulator source 280962306a36Sopenharmony_ci * 281062306a36Sopenharmony_ci * Some things on a regulator consumer (like the contribution towards total 281162306a36Sopenharmony_ci * load on the regulator) only have an effect when the consumer wants the 281262306a36Sopenharmony_ci * regulator enabled. Explained in example with two consumers of the same 281362306a36Sopenharmony_ci * regulator: 281462306a36Sopenharmony_ci * consumer A: set_load(100); => total load = 0 281562306a36Sopenharmony_ci * consumer A: regulator_enable(); => total load = 100 281662306a36Sopenharmony_ci * consumer B: set_load(1000); => total load = 100 281762306a36Sopenharmony_ci * consumer B: regulator_enable(); => total load = 1100 281862306a36Sopenharmony_ci * consumer A: regulator_disable(); => total_load = 1000 281962306a36Sopenharmony_ci * 282062306a36Sopenharmony_ci * This function (together with _regulator_handle_consumer_disable) is 282162306a36Sopenharmony_ci * responsible for keeping track of the refcount for a given regulator consumer 282262306a36Sopenharmony_ci * and applying / unapplying these things. 282362306a36Sopenharmony_ci * 282462306a36Sopenharmony_ci * Returns 0 upon no error; -error upon error. 282562306a36Sopenharmony_ci */ 282662306a36Sopenharmony_cistatic int _regulator_handle_consumer_enable(struct regulator *regulator) 282762306a36Sopenharmony_ci{ 282862306a36Sopenharmony_ci int ret; 282962306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci regulator->enable_count++; 283462306a36Sopenharmony_ci if (regulator->uA_load && regulator->enable_count == 1) { 283562306a36Sopenharmony_ci ret = drms_uA_update(rdev); 283662306a36Sopenharmony_ci if (ret) 283762306a36Sopenharmony_ci regulator->enable_count--; 283862306a36Sopenharmony_ci return ret; 283962306a36Sopenharmony_ci } 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci return 0; 284262306a36Sopenharmony_ci} 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci/** 284562306a36Sopenharmony_ci * _regulator_handle_consumer_disable - handle that a consumer disabled 284662306a36Sopenharmony_ci * @regulator: regulator source 284762306a36Sopenharmony_ci * 284862306a36Sopenharmony_ci * The opposite of _regulator_handle_consumer_enable(). 284962306a36Sopenharmony_ci * 285062306a36Sopenharmony_ci * Returns 0 upon no error; -error upon error. 285162306a36Sopenharmony_ci */ 285262306a36Sopenharmony_cistatic int _regulator_handle_consumer_disable(struct regulator *regulator) 285362306a36Sopenharmony_ci{ 285462306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_ci if (!regulator->enable_count) { 285962306a36Sopenharmony_ci rdev_err(rdev, "Underflow of regulator enable count\n"); 286062306a36Sopenharmony_ci return -EINVAL; 286162306a36Sopenharmony_ci } 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci regulator->enable_count--; 286462306a36Sopenharmony_ci if (regulator->uA_load && regulator->enable_count == 0) 286562306a36Sopenharmony_ci return drms_uA_update(rdev); 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci return 0; 286862306a36Sopenharmony_ci} 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci/* locks held by regulator_enable() */ 287162306a36Sopenharmony_cistatic int _regulator_enable(struct regulator *regulator) 287262306a36Sopenharmony_ci{ 287362306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 287462306a36Sopenharmony_ci int ret; 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci if (rdev->use_count == 0 && rdev->supply) { 287962306a36Sopenharmony_ci ret = _regulator_enable(rdev->supply); 288062306a36Sopenharmony_ci if (ret < 0) 288162306a36Sopenharmony_ci return ret; 288262306a36Sopenharmony_ci } 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci /* balance only if there are regulators coupled */ 288562306a36Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 1) { 288662306a36Sopenharmony_ci ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 288762306a36Sopenharmony_ci if (ret < 0) 288862306a36Sopenharmony_ci goto err_disable_supply; 288962306a36Sopenharmony_ci } 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci ret = _regulator_handle_consumer_enable(regulator); 289262306a36Sopenharmony_ci if (ret < 0) 289362306a36Sopenharmony_ci goto err_disable_supply; 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_ci if (rdev->use_count == 0) { 289662306a36Sopenharmony_ci /* 289762306a36Sopenharmony_ci * The regulator may already be enabled if it's not switchable 289862306a36Sopenharmony_ci * or was left on 289962306a36Sopenharmony_ci */ 290062306a36Sopenharmony_ci ret = _regulator_is_enabled(rdev); 290162306a36Sopenharmony_ci if (ret == -EINVAL || ret == 0) { 290262306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, 290362306a36Sopenharmony_ci REGULATOR_CHANGE_STATUS)) { 290462306a36Sopenharmony_ci ret = -EPERM; 290562306a36Sopenharmony_ci goto err_consumer_disable; 290662306a36Sopenharmony_ci } 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci ret = _regulator_do_enable(rdev); 290962306a36Sopenharmony_ci if (ret < 0) 291062306a36Sopenharmony_ci goto err_consumer_disable; 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE, 291362306a36Sopenharmony_ci NULL); 291462306a36Sopenharmony_ci } else if (ret < 0) { 291562306a36Sopenharmony_ci rdev_err(rdev, "is_enabled() failed: %pe\n", ERR_PTR(ret)); 291662306a36Sopenharmony_ci goto err_consumer_disable; 291762306a36Sopenharmony_ci } 291862306a36Sopenharmony_ci /* Fallthrough on positive return values - already enabled */ 291962306a36Sopenharmony_ci } 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci if (regulator->enable_count == 1) 292262306a36Sopenharmony_ci rdev->use_count++; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci return 0; 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_cierr_consumer_disable: 292762306a36Sopenharmony_ci _regulator_handle_consumer_disable(regulator); 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_cierr_disable_supply: 293062306a36Sopenharmony_ci if (rdev->use_count == 0 && rdev->supply) 293162306a36Sopenharmony_ci _regulator_disable(rdev->supply); 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci return ret; 293462306a36Sopenharmony_ci} 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci/** 293762306a36Sopenharmony_ci * regulator_enable - enable regulator output 293862306a36Sopenharmony_ci * @regulator: regulator source 293962306a36Sopenharmony_ci * 294062306a36Sopenharmony_ci * Request that the regulator be enabled with the regulator output at 294162306a36Sopenharmony_ci * the predefined voltage or current value. Calls to regulator_enable() 294262306a36Sopenharmony_ci * must be balanced with calls to regulator_disable(). 294362306a36Sopenharmony_ci * 294462306a36Sopenharmony_ci * NOTE: the output value can be set by other drivers, boot loader or may be 294562306a36Sopenharmony_ci * hardwired in the regulator. 294662306a36Sopenharmony_ci */ 294762306a36Sopenharmony_ciint regulator_enable(struct regulator *regulator) 294862306a36Sopenharmony_ci{ 294962306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 295062306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 295162306a36Sopenharmony_ci int ret; 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci regulator_lock_dependent(rdev, &ww_ctx); 295462306a36Sopenharmony_ci ret = _regulator_enable(regulator); 295562306a36Sopenharmony_ci regulator_unlock_dependent(rdev, &ww_ctx); 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci return ret; 295862306a36Sopenharmony_ci} 295962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_enable); 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_cistatic int _regulator_do_disable(struct regulator_dev *rdev) 296262306a36Sopenharmony_ci{ 296362306a36Sopenharmony_ci int ret; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci trace_regulator_disable(rdev_get_name(rdev)); 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci if (rdev->ena_pin) { 296862306a36Sopenharmony_ci if (rdev->ena_gpio_state) { 296962306a36Sopenharmony_ci ret = regulator_ena_gpio_ctrl(rdev, false); 297062306a36Sopenharmony_ci if (ret < 0) 297162306a36Sopenharmony_ci return ret; 297262306a36Sopenharmony_ci rdev->ena_gpio_state = 0; 297362306a36Sopenharmony_ci } 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci } else if (rdev->desc->ops->disable) { 297662306a36Sopenharmony_ci ret = rdev->desc->ops->disable(rdev); 297762306a36Sopenharmony_ci if (ret != 0) 297862306a36Sopenharmony_ci return ret; 297962306a36Sopenharmony_ci } 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci if (rdev->desc->off_on_delay) 298262306a36Sopenharmony_ci rdev->last_off = ktime_get_boottime(); 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci trace_regulator_disable_complete(rdev_get_name(rdev)); 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci return 0; 298762306a36Sopenharmony_ci} 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci/* locks held by regulator_disable() */ 299062306a36Sopenharmony_cistatic int _regulator_disable(struct regulator *regulator) 299162306a36Sopenharmony_ci{ 299262306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 299362306a36Sopenharmony_ci int ret = 0; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci if (WARN(regulator->enable_count == 0, 299862306a36Sopenharmony_ci "unbalanced disables for %s\n", rdev_get_name(rdev))) 299962306a36Sopenharmony_ci return -EIO; 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci if (regulator->enable_count == 1) { 300262306a36Sopenharmony_ci /* disabling last enable_count from this regulator */ 300362306a36Sopenharmony_ci /* are we the last user and permitted to disable ? */ 300462306a36Sopenharmony_ci if (rdev->use_count == 1 && 300562306a36Sopenharmony_ci (rdev->constraints && !rdev->constraints->always_on)) { 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci /* we are last user */ 300862306a36Sopenharmony_ci if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { 300962306a36Sopenharmony_ci ret = _notifier_call_chain(rdev, 301062306a36Sopenharmony_ci REGULATOR_EVENT_PRE_DISABLE, 301162306a36Sopenharmony_ci NULL); 301262306a36Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 301362306a36Sopenharmony_ci return -EINVAL; 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_ci ret = _regulator_do_disable(rdev); 301662306a36Sopenharmony_ci if (ret < 0) { 301762306a36Sopenharmony_ci rdev_err(rdev, "failed to disable: %pe\n", ERR_PTR(ret)); 301862306a36Sopenharmony_ci _notifier_call_chain(rdev, 301962306a36Sopenharmony_ci REGULATOR_EVENT_ABORT_DISABLE, 302062306a36Sopenharmony_ci NULL); 302162306a36Sopenharmony_ci return ret; 302262306a36Sopenharmony_ci } 302362306a36Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, 302462306a36Sopenharmony_ci NULL); 302562306a36Sopenharmony_ci } 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci rdev->use_count = 0; 302862306a36Sopenharmony_ci } else if (rdev->use_count > 1) { 302962306a36Sopenharmony_ci rdev->use_count--; 303062306a36Sopenharmony_ci } 303162306a36Sopenharmony_ci } 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_ci if (ret == 0) 303462306a36Sopenharmony_ci ret = _regulator_handle_consumer_disable(regulator); 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci if (ret == 0 && rdev->coupling_desc.n_coupled > 1) 303762306a36Sopenharmony_ci ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci if (ret == 0 && rdev->use_count == 0 && rdev->supply) 304062306a36Sopenharmony_ci ret = _regulator_disable(rdev->supply); 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci return ret; 304362306a36Sopenharmony_ci} 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci/** 304662306a36Sopenharmony_ci * regulator_disable - disable regulator output 304762306a36Sopenharmony_ci * @regulator: regulator source 304862306a36Sopenharmony_ci * 304962306a36Sopenharmony_ci * Disable the regulator output voltage or current. Calls to 305062306a36Sopenharmony_ci * regulator_enable() must be balanced with calls to 305162306a36Sopenharmony_ci * regulator_disable(). 305262306a36Sopenharmony_ci * 305362306a36Sopenharmony_ci * NOTE: this will only disable the regulator output if no other consumer 305462306a36Sopenharmony_ci * devices have it enabled, the regulator device supports disabling and 305562306a36Sopenharmony_ci * machine constraints permit this operation. 305662306a36Sopenharmony_ci */ 305762306a36Sopenharmony_ciint regulator_disable(struct regulator *regulator) 305862306a36Sopenharmony_ci{ 305962306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 306062306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 306162306a36Sopenharmony_ci int ret; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci regulator_lock_dependent(rdev, &ww_ctx); 306462306a36Sopenharmony_ci ret = _regulator_disable(regulator); 306562306a36Sopenharmony_ci regulator_unlock_dependent(rdev, &ww_ctx); 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_ci return ret; 306862306a36Sopenharmony_ci} 306962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_disable); 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci/* locks held by regulator_force_disable() */ 307262306a36Sopenharmony_cistatic int _regulator_force_disable(struct regulator_dev *rdev) 307362306a36Sopenharmony_ci{ 307462306a36Sopenharmony_ci int ret = 0; 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 307962306a36Sopenharmony_ci REGULATOR_EVENT_PRE_DISABLE, NULL); 308062306a36Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 308162306a36Sopenharmony_ci return -EINVAL; 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci ret = _regulator_do_disable(rdev); 308462306a36Sopenharmony_ci if (ret < 0) { 308562306a36Sopenharmony_ci rdev_err(rdev, "failed to force disable: %pe\n", ERR_PTR(ret)); 308662306a36Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 308762306a36Sopenharmony_ci REGULATOR_EVENT_ABORT_DISABLE, NULL); 308862306a36Sopenharmony_ci return ret; 308962306a36Sopenharmony_ci } 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 309262306a36Sopenharmony_ci REGULATOR_EVENT_DISABLE, NULL); 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci return 0; 309562306a36Sopenharmony_ci} 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci/** 309862306a36Sopenharmony_ci * regulator_force_disable - force disable regulator output 309962306a36Sopenharmony_ci * @regulator: regulator source 310062306a36Sopenharmony_ci * 310162306a36Sopenharmony_ci * Forcibly disable the regulator output voltage or current. 310262306a36Sopenharmony_ci * NOTE: this *will* disable the regulator output even if other consumer 310362306a36Sopenharmony_ci * devices have it enabled. This should be used for situations when device 310462306a36Sopenharmony_ci * damage will likely occur if the regulator is not disabled (e.g. over temp). 310562306a36Sopenharmony_ci */ 310662306a36Sopenharmony_ciint regulator_force_disable(struct regulator *regulator) 310762306a36Sopenharmony_ci{ 310862306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 310962306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 311062306a36Sopenharmony_ci int ret; 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci regulator_lock_dependent(rdev, &ww_ctx); 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci ret = _regulator_force_disable(regulator->rdev); 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 1) 311762306a36Sopenharmony_ci regulator_balance_voltage(rdev, PM_SUSPEND_ON); 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (regulator->uA_load) { 312062306a36Sopenharmony_ci regulator->uA_load = 0; 312162306a36Sopenharmony_ci ret = drms_uA_update(rdev); 312262306a36Sopenharmony_ci } 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci if (rdev->use_count != 0 && rdev->supply) 312562306a36Sopenharmony_ci _regulator_disable(rdev->supply); 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci regulator_unlock_dependent(rdev, &ww_ctx); 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci return ret; 313062306a36Sopenharmony_ci} 313162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_force_disable); 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_cistatic void regulator_disable_work(struct work_struct *work) 313462306a36Sopenharmony_ci{ 313562306a36Sopenharmony_ci struct regulator_dev *rdev = container_of(work, struct regulator_dev, 313662306a36Sopenharmony_ci disable_work.work); 313762306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 313862306a36Sopenharmony_ci int count, i, ret; 313962306a36Sopenharmony_ci struct regulator *regulator; 314062306a36Sopenharmony_ci int total_count = 0; 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_ci regulator_lock_dependent(rdev, &ww_ctx); 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci /* 314562306a36Sopenharmony_ci * Workqueue functions queue the new work instance while the previous 314662306a36Sopenharmony_ci * work instance is being processed. Cancel the queued work instance 314762306a36Sopenharmony_ci * as the work instance under processing does the job of the queued 314862306a36Sopenharmony_ci * work instance. 314962306a36Sopenharmony_ci */ 315062306a36Sopenharmony_ci cancel_delayed_work(&rdev->disable_work); 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci list_for_each_entry(regulator, &rdev->consumer_list, list) { 315362306a36Sopenharmony_ci count = regulator->deferred_disables; 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci if (!count) 315662306a36Sopenharmony_ci continue; 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci total_count += count; 315962306a36Sopenharmony_ci regulator->deferred_disables = 0; 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_ci for (i = 0; i < count; i++) { 316262306a36Sopenharmony_ci ret = _regulator_disable(regulator); 316362306a36Sopenharmony_ci if (ret != 0) 316462306a36Sopenharmony_ci rdev_err(rdev, "Deferred disable failed: %pe\n", 316562306a36Sopenharmony_ci ERR_PTR(ret)); 316662306a36Sopenharmony_ci } 316762306a36Sopenharmony_ci } 316862306a36Sopenharmony_ci WARN_ON(!total_count); 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 1) 317162306a36Sopenharmony_ci regulator_balance_voltage(rdev, PM_SUSPEND_ON); 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci regulator_unlock_dependent(rdev, &ww_ctx); 317462306a36Sopenharmony_ci} 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci/** 317762306a36Sopenharmony_ci * regulator_disable_deferred - disable regulator output with delay 317862306a36Sopenharmony_ci * @regulator: regulator source 317962306a36Sopenharmony_ci * @ms: milliseconds until the regulator is disabled 318062306a36Sopenharmony_ci * 318162306a36Sopenharmony_ci * Execute regulator_disable() on the regulator after a delay. This 318262306a36Sopenharmony_ci * is intended for use with devices that require some time to quiesce. 318362306a36Sopenharmony_ci * 318462306a36Sopenharmony_ci * NOTE: this will only disable the regulator output if no other consumer 318562306a36Sopenharmony_ci * devices have it enabled, the regulator device supports disabling and 318662306a36Sopenharmony_ci * machine constraints permit this operation. 318762306a36Sopenharmony_ci */ 318862306a36Sopenharmony_ciint regulator_disable_deferred(struct regulator *regulator, int ms) 318962306a36Sopenharmony_ci{ 319062306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci if (!ms) 319362306a36Sopenharmony_ci return regulator_disable(regulator); 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci regulator_lock(rdev); 319662306a36Sopenharmony_ci regulator->deferred_disables++; 319762306a36Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, &rdev->disable_work, 319862306a36Sopenharmony_ci msecs_to_jiffies(ms)); 319962306a36Sopenharmony_ci regulator_unlock(rdev); 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci return 0; 320262306a36Sopenharmony_ci} 320362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_disable_deferred); 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_cistatic int _regulator_is_enabled(struct regulator_dev *rdev) 320662306a36Sopenharmony_ci{ 320762306a36Sopenharmony_ci /* A GPIO control always takes precedence */ 320862306a36Sopenharmony_ci if (rdev->ena_pin) 320962306a36Sopenharmony_ci return rdev->ena_gpio_state; 321062306a36Sopenharmony_ci 321162306a36Sopenharmony_ci /* If we don't know then assume that the regulator is always on */ 321262306a36Sopenharmony_ci if (!rdev->desc->ops->is_enabled) 321362306a36Sopenharmony_ci return 1; 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci return rdev->desc->ops->is_enabled(rdev); 321662306a36Sopenharmony_ci} 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_cistatic int _regulator_list_voltage(struct regulator_dev *rdev, 321962306a36Sopenharmony_ci unsigned selector, int lock) 322062306a36Sopenharmony_ci{ 322162306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 322262306a36Sopenharmony_ci int ret; 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) 322562306a36Sopenharmony_ci return rdev->desc->fixed_uV; 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci if (ops->list_voltage) { 322862306a36Sopenharmony_ci if (selector >= rdev->desc->n_voltages) 322962306a36Sopenharmony_ci return -EINVAL; 323062306a36Sopenharmony_ci if (selector < rdev->desc->linear_min_sel) 323162306a36Sopenharmony_ci return 0; 323262306a36Sopenharmony_ci if (lock) 323362306a36Sopenharmony_ci regulator_lock(rdev); 323462306a36Sopenharmony_ci ret = ops->list_voltage(rdev, selector); 323562306a36Sopenharmony_ci if (lock) 323662306a36Sopenharmony_ci regulator_unlock(rdev); 323762306a36Sopenharmony_ci } else if (rdev->is_switch && rdev->supply) { 323862306a36Sopenharmony_ci ret = _regulator_list_voltage(rdev->supply->rdev, 323962306a36Sopenharmony_ci selector, lock); 324062306a36Sopenharmony_ci } else { 324162306a36Sopenharmony_ci return -EINVAL; 324262306a36Sopenharmony_ci } 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci if (ret > 0) { 324562306a36Sopenharmony_ci if (ret < rdev->constraints->min_uV) 324662306a36Sopenharmony_ci ret = 0; 324762306a36Sopenharmony_ci else if (ret > rdev->constraints->max_uV) 324862306a36Sopenharmony_ci ret = 0; 324962306a36Sopenharmony_ci } 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci return ret; 325262306a36Sopenharmony_ci} 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci/** 325562306a36Sopenharmony_ci * regulator_is_enabled - is the regulator output enabled 325662306a36Sopenharmony_ci * @regulator: regulator source 325762306a36Sopenharmony_ci * 325862306a36Sopenharmony_ci * Returns positive if the regulator driver backing the source/client 325962306a36Sopenharmony_ci * has requested that the device be enabled, zero if it hasn't, else a 326062306a36Sopenharmony_ci * negative errno code. 326162306a36Sopenharmony_ci * 326262306a36Sopenharmony_ci * Note that the device backing this regulator handle can have multiple 326362306a36Sopenharmony_ci * users, so it might be enabled even if regulator_enable() was never 326462306a36Sopenharmony_ci * called for this particular source. 326562306a36Sopenharmony_ci */ 326662306a36Sopenharmony_ciint regulator_is_enabled(struct regulator *regulator) 326762306a36Sopenharmony_ci{ 326862306a36Sopenharmony_ci int ret; 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci if (regulator->always_on) 327162306a36Sopenharmony_ci return 1; 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci regulator_lock(regulator->rdev); 327462306a36Sopenharmony_ci ret = _regulator_is_enabled(regulator->rdev); 327562306a36Sopenharmony_ci regulator_unlock(regulator->rdev); 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ci return ret; 327862306a36Sopenharmony_ci} 327962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_is_enabled); 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci/** 328262306a36Sopenharmony_ci * regulator_count_voltages - count regulator_list_voltage() selectors 328362306a36Sopenharmony_ci * @regulator: regulator source 328462306a36Sopenharmony_ci * 328562306a36Sopenharmony_ci * Returns number of selectors, or negative errno. Selectors are 328662306a36Sopenharmony_ci * numbered starting at zero, and typically correspond to bitfields 328762306a36Sopenharmony_ci * in hardware registers. 328862306a36Sopenharmony_ci */ 328962306a36Sopenharmony_ciint regulator_count_voltages(struct regulator *regulator) 329062306a36Sopenharmony_ci{ 329162306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_ci if (rdev->desc->n_voltages) 329462306a36Sopenharmony_ci return rdev->desc->n_voltages; 329562306a36Sopenharmony_ci 329662306a36Sopenharmony_ci if (!rdev->is_switch || !rdev->supply) 329762306a36Sopenharmony_ci return -EINVAL; 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci return regulator_count_voltages(rdev->supply); 330062306a36Sopenharmony_ci} 330162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_count_voltages); 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci/** 330462306a36Sopenharmony_ci * regulator_list_voltage - enumerate supported voltages 330562306a36Sopenharmony_ci * @regulator: regulator source 330662306a36Sopenharmony_ci * @selector: identify voltage to list 330762306a36Sopenharmony_ci * Context: can sleep 330862306a36Sopenharmony_ci * 330962306a36Sopenharmony_ci * Returns a voltage that can be passed to @regulator_set_voltage(), 331062306a36Sopenharmony_ci * zero if this selector code can't be used on this system, or a 331162306a36Sopenharmony_ci * negative errno. 331262306a36Sopenharmony_ci */ 331362306a36Sopenharmony_ciint regulator_list_voltage(struct regulator *regulator, unsigned selector) 331462306a36Sopenharmony_ci{ 331562306a36Sopenharmony_ci return _regulator_list_voltage(regulator->rdev, selector, 1); 331662306a36Sopenharmony_ci} 331762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_list_voltage); 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci/** 332062306a36Sopenharmony_ci * regulator_get_regmap - get the regulator's register map 332162306a36Sopenharmony_ci * @regulator: regulator source 332262306a36Sopenharmony_ci * 332362306a36Sopenharmony_ci * Returns the register map for the given regulator, or an ERR_PTR value 332462306a36Sopenharmony_ci * if the regulator doesn't use regmap. 332562306a36Sopenharmony_ci */ 332662306a36Sopenharmony_cistruct regmap *regulator_get_regmap(struct regulator *regulator) 332762306a36Sopenharmony_ci{ 332862306a36Sopenharmony_ci struct regmap *map = regulator->rdev->regmap; 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci return map ? map : ERR_PTR(-EOPNOTSUPP); 333162306a36Sopenharmony_ci} 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci/** 333462306a36Sopenharmony_ci * regulator_get_hardware_vsel_register - get the HW voltage selector register 333562306a36Sopenharmony_ci * @regulator: regulator source 333662306a36Sopenharmony_ci * @vsel_reg: voltage selector register, output parameter 333762306a36Sopenharmony_ci * @vsel_mask: mask for voltage selector bitfield, output parameter 333862306a36Sopenharmony_ci * 333962306a36Sopenharmony_ci * Returns the hardware register offset and bitmask used for setting the 334062306a36Sopenharmony_ci * regulator voltage. This might be useful when configuring voltage-scaling 334162306a36Sopenharmony_ci * hardware or firmware that can make I2C requests behind the kernel's back, 334262306a36Sopenharmony_ci * for example. 334362306a36Sopenharmony_ci * 334462306a36Sopenharmony_ci * On success, the output parameters @vsel_reg and @vsel_mask are filled in 334562306a36Sopenharmony_ci * and 0 is returned, otherwise a negative errno is returned. 334662306a36Sopenharmony_ci */ 334762306a36Sopenharmony_ciint regulator_get_hardware_vsel_register(struct regulator *regulator, 334862306a36Sopenharmony_ci unsigned *vsel_reg, 334962306a36Sopenharmony_ci unsigned *vsel_mask) 335062306a36Sopenharmony_ci{ 335162306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 335262306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) 335562306a36Sopenharmony_ci return -EOPNOTSUPP; 335662306a36Sopenharmony_ci 335762306a36Sopenharmony_ci *vsel_reg = rdev->desc->vsel_reg; 335862306a36Sopenharmony_ci *vsel_mask = rdev->desc->vsel_mask; 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci return 0; 336162306a36Sopenharmony_ci} 336262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci/** 336562306a36Sopenharmony_ci * regulator_list_hardware_vsel - get the HW-specific register value for a selector 336662306a36Sopenharmony_ci * @regulator: regulator source 336762306a36Sopenharmony_ci * @selector: identify voltage to list 336862306a36Sopenharmony_ci * 336962306a36Sopenharmony_ci * Converts the selector to a hardware-specific voltage selector that can be 337062306a36Sopenharmony_ci * directly written to the regulator registers. The address of the voltage 337162306a36Sopenharmony_ci * register can be determined by calling @regulator_get_hardware_vsel_register. 337262306a36Sopenharmony_ci * 337362306a36Sopenharmony_ci * On error a negative errno is returned. 337462306a36Sopenharmony_ci */ 337562306a36Sopenharmony_ciint regulator_list_hardware_vsel(struct regulator *regulator, 337662306a36Sopenharmony_ci unsigned selector) 337762306a36Sopenharmony_ci{ 337862306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 337962306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ci if (selector >= rdev->desc->n_voltages) 338262306a36Sopenharmony_ci return -EINVAL; 338362306a36Sopenharmony_ci if (selector < rdev->desc->linear_min_sel) 338462306a36Sopenharmony_ci return 0; 338562306a36Sopenharmony_ci if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) 338662306a36Sopenharmony_ci return -EOPNOTSUPP; 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci return selector; 338962306a36Sopenharmony_ci} 339062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_list_hardware_vsel); 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci/** 339362306a36Sopenharmony_ci * regulator_get_linear_step - return the voltage step size between VSEL values 339462306a36Sopenharmony_ci * @regulator: regulator source 339562306a36Sopenharmony_ci * 339662306a36Sopenharmony_ci * Returns the voltage step size between VSEL values for linear 339762306a36Sopenharmony_ci * regulators, or return 0 if the regulator isn't a linear regulator. 339862306a36Sopenharmony_ci */ 339962306a36Sopenharmony_ciunsigned int regulator_get_linear_step(struct regulator *regulator) 340062306a36Sopenharmony_ci{ 340162306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci return rdev->desc->uV_step; 340462306a36Sopenharmony_ci} 340562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_linear_step); 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci/** 340862306a36Sopenharmony_ci * regulator_is_supported_voltage - check if a voltage range can be supported 340962306a36Sopenharmony_ci * 341062306a36Sopenharmony_ci * @regulator: Regulator to check. 341162306a36Sopenharmony_ci * @min_uV: Minimum required voltage in uV. 341262306a36Sopenharmony_ci * @max_uV: Maximum required voltage in uV. 341362306a36Sopenharmony_ci * 341462306a36Sopenharmony_ci * Returns a boolean. 341562306a36Sopenharmony_ci */ 341662306a36Sopenharmony_ciint regulator_is_supported_voltage(struct regulator *regulator, 341762306a36Sopenharmony_ci int min_uV, int max_uV) 341862306a36Sopenharmony_ci{ 341962306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 342062306a36Sopenharmony_ci int i, voltages, ret; 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci /* If we can't change voltage check the current voltage */ 342362306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 342462306a36Sopenharmony_ci ret = regulator_get_voltage(regulator); 342562306a36Sopenharmony_ci if (ret >= 0) 342662306a36Sopenharmony_ci return min_uV <= ret && ret <= max_uV; 342762306a36Sopenharmony_ci else 342862306a36Sopenharmony_ci return ret; 342962306a36Sopenharmony_ci } 343062306a36Sopenharmony_ci 343162306a36Sopenharmony_ci /* Any voltage within constrains range is fine? */ 343262306a36Sopenharmony_ci if (rdev->desc->continuous_voltage_range) 343362306a36Sopenharmony_ci return min_uV >= rdev->constraints->min_uV && 343462306a36Sopenharmony_ci max_uV <= rdev->constraints->max_uV; 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci ret = regulator_count_voltages(regulator); 343762306a36Sopenharmony_ci if (ret < 0) 343862306a36Sopenharmony_ci return 0; 343962306a36Sopenharmony_ci voltages = ret; 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci for (i = 0; i < voltages; i++) { 344262306a36Sopenharmony_ci ret = regulator_list_voltage(regulator, i); 344362306a36Sopenharmony_ci 344462306a36Sopenharmony_ci if (ret >= min_uV && ret <= max_uV) 344562306a36Sopenharmony_ci return 1; 344662306a36Sopenharmony_ci } 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci return 0; 344962306a36Sopenharmony_ci} 345062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_is_supported_voltage); 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_cistatic int regulator_map_voltage(struct regulator_dev *rdev, int min_uV, 345362306a36Sopenharmony_ci int max_uV) 345462306a36Sopenharmony_ci{ 345562306a36Sopenharmony_ci const struct regulator_desc *desc = rdev->desc; 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci if (desc->ops->map_voltage) 345862306a36Sopenharmony_ci return desc->ops->map_voltage(rdev, min_uV, max_uV); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci if (desc->ops->list_voltage == regulator_list_voltage_linear) 346162306a36Sopenharmony_ci return regulator_map_voltage_linear(rdev, min_uV, max_uV); 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_ci if (desc->ops->list_voltage == regulator_list_voltage_linear_range) 346462306a36Sopenharmony_ci return regulator_map_voltage_linear_range(rdev, min_uV, max_uV); 346562306a36Sopenharmony_ci 346662306a36Sopenharmony_ci if (desc->ops->list_voltage == 346762306a36Sopenharmony_ci regulator_list_voltage_pickable_linear_range) 346862306a36Sopenharmony_ci return regulator_map_voltage_pickable_linear_range(rdev, 346962306a36Sopenharmony_ci min_uV, max_uV); 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci return regulator_map_voltage_iterate(rdev, min_uV, max_uV); 347262306a36Sopenharmony_ci} 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_cistatic int _regulator_call_set_voltage(struct regulator_dev *rdev, 347562306a36Sopenharmony_ci int min_uV, int max_uV, 347662306a36Sopenharmony_ci unsigned *selector) 347762306a36Sopenharmony_ci{ 347862306a36Sopenharmony_ci struct pre_voltage_change_data data; 347962306a36Sopenharmony_ci int ret; 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci data.old_uV = regulator_get_voltage_rdev(rdev); 348262306a36Sopenharmony_ci data.min_uV = min_uV; 348362306a36Sopenharmony_ci data.max_uV = max_uV; 348462306a36Sopenharmony_ci ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, 348562306a36Sopenharmony_ci &data); 348662306a36Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 348762306a36Sopenharmony_ci return -EINVAL; 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, selector); 349062306a36Sopenharmony_ci if (ret >= 0) 349162306a36Sopenharmony_ci return ret; 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE, 349462306a36Sopenharmony_ci (void *)data.old_uV); 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_ci return ret; 349762306a36Sopenharmony_ci} 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_cistatic int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, 350062306a36Sopenharmony_ci int uV, unsigned selector) 350162306a36Sopenharmony_ci{ 350262306a36Sopenharmony_ci struct pre_voltage_change_data data; 350362306a36Sopenharmony_ci int ret; 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci data.old_uV = regulator_get_voltage_rdev(rdev); 350662306a36Sopenharmony_ci data.min_uV = uV; 350762306a36Sopenharmony_ci data.max_uV = uV; 350862306a36Sopenharmony_ci ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, 350962306a36Sopenharmony_ci &data); 351062306a36Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 351162306a36Sopenharmony_ci return -EINVAL; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci ret = rdev->desc->ops->set_voltage_sel(rdev, selector); 351462306a36Sopenharmony_ci if (ret >= 0) 351562306a36Sopenharmony_ci return ret; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE, 351862306a36Sopenharmony_ci (void *)data.old_uV); 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_ci return ret; 352162306a36Sopenharmony_ci} 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_cistatic int _regulator_set_voltage_sel_step(struct regulator_dev *rdev, 352462306a36Sopenharmony_ci int uV, int new_selector) 352562306a36Sopenharmony_ci{ 352662306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 352762306a36Sopenharmony_ci int diff, old_sel, curr_sel, ret; 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci /* Stepping is only needed if the regulator is enabled. */ 353062306a36Sopenharmony_ci if (!_regulator_is_enabled(rdev)) 353162306a36Sopenharmony_ci goto final_set; 353262306a36Sopenharmony_ci 353362306a36Sopenharmony_ci if (!ops->get_voltage_sel) 353462306a36Sopenharmony_ci return -EINVAL; 353562306a36Sopenharmony_ci 353662306a36Sopenharmony_ci old_sel = ops->get_voltage_sel(rdev); 353762306a36Sopenharmony_ci if (old_sel < 0) 353862306a36Sopenharmony_ci return old_sel; 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci diff = new_selector - old_sel; 354162306a36Sopenharmony_ci if (diff == 0) 354262306a36Sopenharmony_ci return 0; /* No change needed. */ 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_ci if (diff > 0) { 354562306a36Sopenharmony_ci /* Stepping up. */ 354662306a36Sopenharmony_ci for (curr_sel = old_sel + rdev->desc->vsel_step; 354762306a36Sopenharmony_ci curr_sel < new_selector; 354862306a36Sopenharmony_ci curr_sel += rdev->desc->vsel_step) { 354962306a36Sopenharmony_ci /* 355062306a36Sopenharmony_ci * Call the callback directly instead of using 355162306a36Sopenharmony_ci * _regulator_call_set_voltage_sel() as we don't 355262306a36Sopenharmony_ci * want to notify anyone yet. Same in the branch 355362306a36Sopenharmony_ci * below. 355462306a36Sopenharmony_ci */ 355562306a36Sopenharmony_ci ret = ops->set_voltage_sel(rdev, curr_sel); 355662306a36Sopenharmony_ci if (ret) 355762306a36Sopenharmony_ci goto try_revert; 355862306a36Sopenharmony_ci } 355962306a36Sopenharmony_ci } else { 356062306a36Sopenharmony_ci /* Stepping down. */ 356162306a36Sopenharmony_ci for (curr_sel = old_sel - rdev->desc->vsel_step; 356262306a36Sopenharmony_ci curr_sel > new_selector; 356362306a36Sopenharmony_ci curr_sel -= rdev->desc->vsel_step) { 356462306a36Sopenharmony_ci ret = ops->set_voltage_sel(rdev, curr_sel); 356562306a36Sopenharmony_ci if (ret) 356662306a36Sopenharmony_ci goto try_revert; 356762306a36Sopenharmony_ci } 356862306a36Sopenharmony_ci } 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_cifinal_set: 357162306a36Sopenharmony_ci /* The final selector will trigger the notifiers. */ 357262306a36Sopenharmony_ci return _regulator_call_set_voltage_sel(rdev, uV, new_selector); 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_citry_revert: 357562306a36Sopenharmony_ci /* 357662306a36Sopenharmony_ci * At least try to return to the previous voltage if setting a new 357762306a36Sopenharmony_ci * one failed. 357862306a36Sopenharmony_ci */ 357962306a36Sopenharmony_ci (void)ops->set_voltage_sel(rdev, old_sel); 358062306a36Sopenharmony_ci return ret; 358162306a36Sopenharmony_ci} 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_cistatic int _regulator_set_voltage_time(struct regulator_dev *rdev, 358462306a36Sopenharmony_ci int old_uV, int new_uV) 358562306a36Sopenharmony_ci{ 358662306a36Sopenharmony_ci unsigned int ramp_delay = 0; 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci if (rdev->constraints->ramp_delay) 358962306a36Sopenharmony_ci ramp_delay = rdev->constraints->ramp_delay; 359062306a36Sopenharmony_ci else if (rdev->desc->ramp_delay) 359162306a36Sopenharmony_ci ramp_delay = rdev->desc->ramp_delay; 359262306a36Sopenharmony_ci else if (rdev->constraints->settling_time) 359362306a36Sopenharmony_ci return rdev->constraints->settling_time; 359462306a36Sopenharmony_ci else if (rdev->constraints->settling_time_up && 359562306a36Sopenharmony_ci (new_uV > old_uV)) 359662306a36Sopenharmony_ci return rdev->constraints->settling_time_up; 359762306a36Sopenharmony_ci else if (rdev->constraints->settling_time_down && 359862306a36Sopenharmony_ci (new_uV < old_uV)) 359962306a36Sopenharmony_ci return rdev->constraints->settling_time_down; 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci if (ramp_delay == 0) 360262306a36Sopenharmony_ci return 0; 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci return DIV_ROUND_UP(abs(new_uV - old_uV), ramp_delay); 360562306a36Sopenharmony_ci} 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_cistatic int _regulator_do_set_voltage(struct regulator_dev *rdev, 360862306a36Sopenharmony_ci int min_uV, int max_uV) 360962306a36Sopenharmony_ci{ 361062306a36Sopenharmony_ci int ret; 361162306a36Sopenharmony_ci int delay = 0; 361262306a36Sopenharmony_ci int best_val = 0; 361362306a36Sopenharmony_ci unsigned int selector; 361462306a36Sopenharmony_ci int old_selector = -1; 361562306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 361662306a36Sopenharmony_ci int old_uV = regulator_get_voltage_rdev(rdev); 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci min_uV += rdev->constraints->uV_offset; 362162306a36Sopenharmony_ci max_uV += rdev->constraints->uV_offset; 362262306a36Sopenharmony_ci 362362306a36Sopenharmony_ci /* 362462306a36Sopenharmony_ci * If we can't obtain the old selector there is not enough 362562306a36Sopenharmony_ci * info to call set_voltage_time_sel(). 362662306a36Sopenharmony_ci */ 362762306a36Sopenharmony_ci if (_regulator_is_enabled(rdev) && 362862306a36Sopenharmony_ci ops->set_voltage_time_sel && ops->get_voltage_sel) { 362962306a36Sopenharmony_ci old_selector = ops->get_voltage_sel(rdev); 363062306a36Sopenharmony_ci if (old_selector < 0) 363162306a36Sopenharmony_ci return old_selector; 363262306a36Sopenharmony_ci } 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_ci if (ops->set_voltage) { 363562306a36Sopenharmony_ci ret = _regulator_call_set_voltage(rdev, min_uV, max_uV, 363662306a36Sopenharmony_ci &selector); 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci if (ret >= 0) { 363962306a36Sopenharmony_ci if (ops->list_voltage) 364062306a36Sopenharmony_ci best_val = ops->list_voltage(rdev, 364162306a36Sopenharmony_ci selector); 364262306a36Sopenharmony_ci else 364362306a36Sopenharmony_ci best_val = regulator_get_voltage_rdev(rdev); 364462306a36Sopenharmony_ci } 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci } else if (ops->set_voltage_sel) { 364762306a36Sopenharmony_ci ret = regulator_map_voltage(rdev, min_uV, max_uV); 364862306a36Sopenharmony_ci if (ret >= 0) { 364962306a36Sopenharmony_ci best_val = ops->list_voltage(rdev, ret); 365062306a36Sopenharmony_ci if (min_uV <= best_val && max_uV >= best_val) { 365162306a36Sopenharmony_ci selector = ret; 365262306a36Sopenharmony_ci if (old_selector == selector) 365362306a36Sopenharmony_ci ret = 0; 365462306a36Sopenharmony_ci else if (rdev->desc->vsel_step) 365562306a36Sopenharmony_ci ret = _regulator_set_voltage_sel_step( 365662306a36Sopenharmony_ci rdev, best_val, selector); 365762306a36Sopenharmony_ci else 365862306a36Sopenharmony_ci ret = _regulator_call_set_voltage_sel( 365962306a36Sopenharmony_ci rdev, best_val, selector); 366062306a36Sopenharmony_ci } else { 366162306a36Sopenharmony_ci ret = -EINVAL; 366262306a36Sopenharmony_ci } 366362306a36Sopenharmony_ci } 366462306a36Sopenharmony_ci } else { 366562306a36Sopenharmony_ci ret = -EINVAL; 366662306a36Sopenharmony_ci } 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_ci if (ret) 366962306a36Sopenharmony_ci goto out; 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ci if (ops->set_voltage_time_sel) { 367262306a36Sopenharmony_ci /* 367362306a36Sopenharmony_ci * Call set_voltage_time_sel if successfully obtained 367462306a36Sopenharmony_ci * old_selector 367562306a36Sopenharmony_ci */ 367662306a36Sopenharmony_ci if (old_selector >= 0 && old_selector != selector) 367762306a36Sopenharmony_ci delay = ops->set_voltage_time_sel(rdev, old_selector, 367862306a36Sopenharmony_ci selector); 367962306a36Sopenharmony_ci } else { 368062306a36Sopenharmony_ci if (old_uV != best_val) { 368162306a36Sopenharmony_ci if (ops->set_voltage_time) 368262306a36Sopenharmony_ci delay = ops->set_voltage_time(rdev, old_uV, 368362306a36Sopenharmony_ci best_val); 368462306a36Sopenharmony_ci else 368562306a36Sopenharmony_ci delay = _regulator_set_voltage_time(rdev, 368662306a36Sopenharmony_ci old_uV, 368762306a36Sopenharmony_ci best_val); 368862306a36Sopenharmony_ci } 368962306a36Sopenharmony_ci } 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci if (delay < 0) { 369262306a36Sopenharmony_ci rdev_warn(rdev, "failed to get delay: %pe\n", ERR_PTR(delay)); 369362306a36Sopenharmony_ci delay = 0; 369462306a36Sopenharmony_ci } 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci /* Insert any necessary delays */ 369762306a36Sopenharmony_ci _regulator_delay_helper(delay); 369862306a36Sopenharmony_ci 369962306a36Sopenharmony_ci if (best_val >= 0) { 370062306a36Sopenharmony_ci unsigned long data = best_val; 370162306a36Sopenharmony_ci 370262306a36Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, 370362306a36Sopenharmony_ci (void *)data); 370462306a36Sopenharmony_ci } 370562306a36Sopenharmony_ci 370662306a36Sopenharmony_ciout: 370762306a36Sopenharmony_ci trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci return ret; 371062306a36Sopenharmony_ci} 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_cistatic int _regulator_do_set_suspend_voltage(struct regulator_dev *rdev, 371362306a36Sopenharmony_ci int min_uV, int max_uV, suspend_state_t state) 371462306a36Sopenharmony_ci{ 371562306a36Sopenharmony_ci struct regulator_state *rstate; 371662306a36Sopenharmony_ci int uV, sel; 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 371962306a36Sopenharmony_ci if (rstate == NULL) 372062306a36Sopenharmony_ci return -EINVAL; 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_ci if (min_uV < rstate->min_uV) 372362306a36Sopenharmony_ci min_uV = rstate->min_uV; 372462306a36Sopenharmony_ci if (max_uV > rstate->max_uV) 372562306a36Sopenharmony_ci max_uV = rstate->max_uV; 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci sel = regulator_map_voltage(rdev, min_uV, max_uV); 372862306a36Sopenharmony_ci if (sel < 0) 372962306a36Sopenharmony_ci return sel; 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci uV = rdev->desc->ops->list_voltage(rdev, sel); 373262306a36Sopenharmony_ci if (uV >= min_uV && uV <= max_uV) 373362306a36Sopenharmony_ci rstate->uV = uV; 373462306a36Sopenharmony_ci 373562306a36Sopenharmony_ci return 0; 373662306a36Sopenharmony_ci} 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_cistatic int regulator_set_voltage_unlocked(struct regulator *regulator, 373962306a36Sopenharmony_ci int min_uV, int max_uV, 374062306a36Sopenharmony_ci suspend_state_t state) 374162306a36Sopenharmony_ci{ 374262306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 374362306a36Sopenharmony_ci struct regulator_voltage *voltage = ®ulator->voltage[state]; 374462306a36Sopenharmony_ci int ret = 0; 374562306a36Sopenharmony_ci int old_min_uV, old_max_uV; 374662306a36Sopenharmony_ci int current_uV; 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci /* If we're setting the same range as last time the change 374962306a36Sopenharmony_ci * should be a noop (some cpufreq implementations use the same 375062306a36Sopenharmony_ci * voltage for multiple frequencies, for example). 375162306a36Sopenharmony_ci */ 375262306a36Sopenharmony_ci if (voltage->min_uV == min_uV && voltage->max_uV == max_uV) 375362306a36Sopenharmony_ci goto out; 375462306a36Sopenharmony_ci 375562306a36Sopenharmony_ci /* If we're trying to set a range that overlaps the current voltage, 375662306a36Sopenharmony_ci * return successfully even though the regulator does not support 375762306a36Sopenharmony_ci * changing the voltage. 375862306a36Sopenharmony_ci */ 375962306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 376062306a36Sopenharmony_ci current_uV = regulator_get_voltage_rdev(rdev); 376162306a36Sopenharmony_ci if (min_uV <= current_uV && current_uV <= max_uV) { 376262306a36Sopenharmony_ci voltage->min_uV = min_uV; 376362306a36Sopenharmony_ci voltage->max_uV = max_uV; 376462306a36Sopenharmony_ci goto out; 376562306a36Sopenharmony_ci } 376662306a36Sopenharmony_ci } 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci /* sanity check */ 376962306a36Sopenharmony_ci if (!rdev->desc->ops->set_voltage && 377062306a36Sopenharmony_ci !rdev->desc->ops->set_voltage_sel) { 377162306a36Sopenharmony_ci ret = -EINVAL; 377262306a36Sopenharmony_ci goto out; 377362306a36Sopenharmony_ci } 377462306a36Sopenharmony_ci 377562306a36Sopenharmony_ci /* constraints check */ 377662306a36Sopenharmony_ci ret = regulator_check_voltage(rdev, &min_uV, &max_uV); 377762306a36Sopenharmony_ci if (ret < 0) 377862306a36Sopenharmony_ci goto out; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci /* restore original values in case of error */ 378162306a36Sopenharmony_ci old_min_uV = voltage->min_uV; 378262306a36Sopenharmony_ci old_max_uV = voltage->max_uV; 378362306a36Sopenharmony_ci voltage->min_uV = min_uV; 378462306a36Sopenharmony_ci voltage->max_uV = max_uV; 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci /* for not coupled regulators this will just set the voltage */ 378762306a36Sopenharmony_ci ret = regulator_balance_voltage(rdev, state); 378862306a36Sopenharmony_ci if (ret < 0) { 378962306a36Sopenharmony_ci voltage->min_uV = old_min_uV; 379062306a36Sopenharmony_ci voltage->max_uV = old_max_uV; 379162306a36Sopenharmony_ci } 379262306a36Sopenharmony_ci 379362306a36Sopenharmony_ciout: 379462306a36Sopenharmony_ci return ret; 379562306a36Sopenharmony_ci} 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ciint regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, 379862306a36Sopenharmony_ci int max_uV, suspend_state_t state) 379962306a36Sopenharmony_ci{ 380062306a36Sopenharmony_ci int best_supply_uV = 0; 380162306a36Sopenharmony_ci int supply_change_uV = 0; 380262306a36Sopenharmony_ci int ret; 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci if (rdev->supply && 380562306a36Sopenharmony_ci regulator_ops_is_valid(rdev->supply->rdev, 380662306a36Sopenharmony_ci REGULATOR_CHANGE_VOLTAGE) && 380762306a36Sopenharmony_ci (rdev->desc->min_dropout_uV || !(rdev->desc->ops->get_voltage || 380862306a36Sopenharmony_ci rdev->desc->ops->get_voltage_sel))) { 380962306a36Sopenharmony_ci int current_supply_uV; 381062306a36Sopenharmony_ci int selector; 381162306a36Sopenharmony_ci 381262306a36Sopenharmony_ci selector = regulator_map_voltage(rdev, min_uV, max_uV); 381362306a36Sopenharmony_ci if (selector < 0) { 381462306a36Sopenharmony_ci ret = selector; 381562306a36Sopenharmony_ci goto out; 381662306a36Sopenharmony_ci } 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_ci best_supply_uV = _regulator_list_voltage(rdev, selector, 0); 381962306a36Sopenharmony_ci if (best_supply_uV < 0) { 382062306a36Sopenharmony_ci ret = best_supply_uV; 382162306a36Sopenharmony_ci goto out; 382262306a36Sopenharmony_ci } 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_ci best_supply_uV += rdev->desc->min_dropout_uV; 382562306a36Sopenharmony_ci 382662306a36Sopenharmony_ci current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev); 382762306a36Sopenharmony_ci if (current_supply_uV < 0) { 382862306a36Sopenharmony_ci ret = current_supply_uV; 382962306a36Sopenharmony_ci goto out; 383062306a36Sopenharmony_ci } 383162306a36Sopenharmony_ci 383262306a36Sopenharmony_ci supply_change_uV = best_supply_uV - current_supply_uV; 383362306a36Sopenharmony_ci } 383462306a36Sopenharmony_ci 383562306a36Sopenharmony_ci if (supply_change_uV > 0) { 383662306a36Sopenharmony_ci ret = regulator_set_voltage_unlocked(rdev->supply, 383762306a36Sopenharmony_ci best_supply_uV, INT_MAX, state); 383862306a36Sopenharmony_ci if (ret) { 383962306a36Sopenharmony_ci dev_err(&rdev->dev, "Failed to increase supply voltage: %pe\n", 384062306a36Sopenharmony_ci ERR_PTR(ret)); 384162306a36Sopenharmony_ci goto out; 384262306a36Sopenharmony_ci } 384362306a36Sopenharmony_ci } 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci if (state == PM_SUSPEND_ON) 384662306a36Sopenharmony_ci ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 384762306a36Sopenharmony_ci else 384862306a36Sopenharmony_ci ret = _regulator_do_set_suspend_voltage(rdev, min_uV, 384962306a36Sopenharmony_ci max_uV, state); 385062306a36Sopenharmony_ci if (ret < 0) 385162306a36Sopenharmony_ci goto out; 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci if (supply_change_uV < 0) { 385462306a36Sopenharmony_ci ret = regulator_set_voltage_unlocked(rdev->supply, 385562306a36Sopenharmony_ci best_supply_uV, INT_MAX, state); 385662306a36Sopenharmony_ci if (ret) 385762306a36Sopenharmony_ci dev_warn(&rdev->dev, "Failed to decrease supply voltage: %pe\n", 385862306a36Sopenharmony_ci ERR_PTR(ret)); 385962306a36Sopenharmony_ci /* No need to fail here */ 386062306a36Sopenharmony_ci ret = 0; 386162306a36Sopenharmony_ci } 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ciout: 386462306a36Sopenharmony_ci return ret; 386562306a36Sopenharmony_ci} 386662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_voltage_rdev); 386762306a36Sopenharmony_ci 386862306a36Sopenharmony_cistatic int regulator_limit_voltage_step(struct regulator_dev *rdev, 386962306a36Sopenharmony_ci int *current_uV, int *min_uV) 387062306a36Sopenharmony_ci{ 387162306a36Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 387262306a36Sopenharmony_ci 387362306a36Sopenharmony_ci /* Limit voltage change only if necessary */ 387462306a36Sopenharmony_ci if (!constraints->max_uV_step || !_regulator_is_enabled(rdev)) 387562306a36Sopenharmony_ci return 1; 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci if (*current_uV < 0) { 387862306a36Sopenharmony_ci *current_uV = regulator_get_voltage_rdev(rdev); 387962306a36Sopenharmony_ci 388062306a36Sopenharmony_ci if (*current_uV < 0) 388162306a36Sopenharmony_ci return *current_uV; 388262306a36Sopenharmony_ci } 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci if (abs(*current_uV - *min_uV) <= constraints->max_uV_step) 388562306a36Sopenharmony_ci return 1; 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci /* Clamp target voltage within the given step */ 388862306a36Sopenharmony_ci if (*current_uV < *min_uV) 388962306a36Sopenharmony_ci *min_uV = min(*current_uV + constraints->max_uV_step, 389062306a36Sopenharmony_ci *min_uV); 389162306a36Sopenharmony_ci else 389262306a36Sopenharmony_ci *min_uV = max(*current_uV - constraints->max_uV_step, 389362306a36Sopenharmony_ci *min_uV); 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci return 0; 389662306a36Sopenharmony_ci} 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_cistatic int regulator_get_optimal_voltage(struct regulator_dev *rdev, 389962306a36Sopenharmony_ci int *current_uV, 390062306a36Sopenharmony_ci int *min_uV, int *max_uV, 390162306a36Sopenharmony_ci suspend_state_t state, 390262306a36Sopenharmony_ci int n_coupled) 390362306a36Sopenharmony_ci{ 390462306a36Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 390562306a36Sopenharmony_ci struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; 390662306a36Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 390762306a36Sopenharmony_ci int desired_min_uV = 0, desired_max_uV = INT_MAX; 390862306a36Sopenharmony_ci int max_current_uV = 0, min_current_uV = INT_MAX; 390962306a36Sopenharmony_ci int highest_min_uV = 0, target_uV, possible_uV; 391062306a36Sopenharmony_ci int i, ret, max_spread; 391162306a36Sopenharmony_ci bool done; 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_ci *current_uV = -1; 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_ci /* 391662306a36Sopenharmony_ci * If there are no coupled regulators, simply set the voltage 391762306a36Sopenharmony_ci * demanded by consumers. 391862306a36Sopenharmony_ci */ 391962306a36Sopenharmony_ci if (n_coupled == 1) { 392062306a36Sopenharmony_ci /* 392162306a36Sopenharmony_ci * If consumers don't provide any demands, set voltage 392262306a36Sopenharmony_ci * to min_uV 392362306a36Sopenharmony_ci */ 392462306a36Sopenharmony_ci desired_min_uV = constraints->min_uV; 392562306a36Sopenharmony_ci desired_max_uV = constraints->max_uV; 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_ci ret = regulator_check_consumers(rdev, 392862306a36Sopenharmony_ci &desired_min_uV, 392962306a36Sopenharmony_ci &desired_max_uV, state); 393062306a36Sopenharmony_ci if (ret < 0) 393162306a36Sopenharmony_ci return ret; 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_ci possible_uV = desired_min_uV; 393462306a36Sopenharmony_ci done = true; 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci goto finish; 393762306a36Sopenharmony_ci } 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci /* Find highest min desired voltage */ 394062306a36Sopenharmony_ci for (i = 0; i < n_coupled; i++) { 394162306a36Sopenharmony_ci int tmp_min = 0; 394262306a36Sopenharmony_ci int tmp_max = INT_MAX; 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci lockdep_assert_held_once(&c_rdevs[i]->mutex.base); 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci ret = regulator_check_consumers(c_rdevs[i], 394762306a36Sopenharmony_ci &tmp_min, 394862306a36Sopenharmony_ci &tmp_max, state); 394962306a36Sopenharmony_ci if (ret < 0) 395062306a36Sopenharmony_ci return ret; 395162306a36Sopenharmony_ci 395262306a36Sopenharmony_ci ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max); 395362306a36Sopenharmony_ci if (ret < 0) 395462306a36Sopenharmony_ci return ret; 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci highest_min_uV = max(highest_min_uV, tmp_min); 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci if (i == 0) { 395962306a36Sopenharmony_ci desired_min_uV = tmp_min; 396062306a36Sopenharmony_ci desired_max_uV = tmp_max; 396162306a36Sopenharmony_ci } 396262306a36Sopenharmony_ci } 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci max_spread = constraints->max_spread[0]; 396562306a36Sopenharmony_ci 396662306a36Sopenharmony_ci /* 396762306a36Sopenharmony_ci * Let target_uV be equal to the desired one if possible. 396862306a36Sopenharmony_ci * If not, set it to minimum voltage, allowed by other coupled 396962306a36Sopenharmony_ci * regulators. 397062306a36Sopenharmony_ci */ 397162306a36Sopenharmony_ci target_uV = max(desired_min_uV, highest_min_uV - max_spread); 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_ci /* 397462306a36Sopenharmony_ci * Find min and max voltages, which currently aren't violating 397562306a36Sopenharmony_ci * max_spread. 397662306a36Sopenharmony_ci */ 397762306a36Sopenharmony_ci for (i = 1; i < n_coupled; i++) { 397862306a36Sopenharmony_ci int tmp_act; 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci if (!_regulator_is_enabled(c_rdevs[i])) 398162306a36Sopenharmony_ci continue; 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci tmp_act = regulator_get_voltage_rdev(c_rdevs[i]); 398462306a36Sopenharmony_ci if (tmp_act < 0) 398562306a36Sopenharmony_ci return tmp_act; 398662306a36Sopenharmony_ci 398762306a36Sopenharmony_ci min_current_uV = min(tmp_act, min_current_uV); 398862306a36Sopenharmony_ci max_current_uV = max(tmp_act, max_current_uV); 398962306a36Sopenharmony_ci } 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci /* There aren't any other regulators enabled */ 399262306a36Sopenharmony_ci if (max_current_uV == 0) { 399362306a36Sopenharmony_ci possible_uV = target_uV; 399462306a36Sopenharmony_ci } else { 399562306a36Sopenharmony_ci /* 399662306a36Sopenharmony_ci * Correct target voltage, so as it currently isn't 399762306a36Sopenharmony_ci * violating max_spread 399862306a36Sopenharmony_ci */ 399962306a36Sopenharmony_ci possible_uV = max(target_uV, max_current_uV - max_spread); 400062306a36Sopenharmony_ci possible_uV = min(possible_uV, min_current_uV + max_spread); 400162306a36Sopenharmony_ci } 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_ci if (possible_uV > desired_max_uV) 400462306a36Sopenharmony_ci return -EINVAL; 400562306a36Sopenharmony_ci 400662306a36Sopenharmony_ci done = (possible_uV == target_uV); 400762306a36Sopenharmony_ci desired_min_uV = possible_uV; 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_cifinish: 401062306a36Sopenharmony_ci /* Apply max_uV_step constraint if necessary */ 401162306a36Sopenharmony_ci if (state == PM_SUSPEND_ON) { 401262306a36Sopenharmony_ci ret = regulator_limit_voltage_step(rdev, current_uV, 401362306a36Sopenharmony_ci &desired_min_uV); 401462306a36Sopenharmony_ci if (ret < 0) 401562306a36Sopenharmony_ci return ret; 401662306a36Sopenharmony_ci 401762306a36Sopenharmony_ci if (ret == 0) 401862306a36Sopenharmony_ci done = false; 401962306a36Sopenharmony_ci } 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci /* Set current_uV if wasn't done earlier in the code and if necessary */ 402262306a36Sopenharmony_ci if (n_coupled > 1 && *current_uV == -1) { 402362306a36Sopenharmony_ci 402462306a36Sopenharmony_ci if (_regulator_is_enabled(rdev)) { 402562306a36Sopenharmony_ci ret = regulator_get_voltage_rdev(rdev); 402662306a36Sopenharmony_ci if (ret < 0) 402762306a36Sopenharmony_ci return ret; 402862306a36Sopenharmony_ci 402962306a36Sopenharmony_ci *current_uV = ret; 403062306a36Sopenharmony_ci } else { 403162306a36Sopenharmony_ci *current_uV = desired_min_uV; 403262306a36Sopenharmony_ci } 403362306a36Sopenharmony_ci } 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_ci *min_uV = desired_min_uV; 403662306a36Sopenharmony_ci *max_uV = desired_max_uV; 403762306a36Sopenharmony_ci 403862306a36Sopenharmony_ci return done; 403962306a36Sopenharmony_ci} 404062306a36Sopenharmony_ci 404162306a36Sopenharmony_ciint regulator_do_balance_voltage(struct regulator_dev *rdev, 404262306a36Sopenharmony_ci suspend_state_t state, bool skip_coupled) 404362306a36Sopenharmony_ci{ 404462306a36Sopenharmony_ci struct regulator_dev **c_rdevs; 404562306a36Sopenharmony_ci struct regulator_dev *best_rdev; 404662306a36Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 404762306a36Sopenharmony_ci int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev; 404862306a36Sopenharmony_ci unsigned int delta, best_delta; 404962306a36Sopenharmony_ci unsigned long c_rdev_done = 0; 405062306a36Sopenharmony_ci bool best_c_rdev_done; 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_ci c_rdevs = c_desc->coupled_rdevs; 405362306a36Sopenharmony_ci n_coupled = skip_coupled ? 1 : c_desc->n_coupled; 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci /* 405662306a36Sopenharmony_ci * Find the best possible voltage change on each loop. Leave the loop 405762306a36Sopenharmony_ci * if there isn't any possible change. 405862306a36Sopenharmony_ci */ 405962306a36Sopenharmony_ci do { 406062306a36Sopenharmony_ci best_c_rdev_done = false; 406162306a36Sopenharmony_ci best_delta = 0; 406262306a36Sopenharmony_ci best_min_uV = 0; 406362306a36Sopenharmony_ci best_max_uV = 0; 406462306a36Sopenharmony_ci best_c_rdev = 0; 406562306a36Sopenharmony_ci best_rdev = NULL; 406662306a36Sopenharmony_ci 406762306a36Sopenharmony_ci /* 406862306a36Sopenharmony_ci * Find highest difference between optimal voltage 406962306a36Sopenharmony_ci * and current voltage. 407062306a36Sopenharmony_ci */ 407162306a36Sopenharmony_ci for (i = 0; i < n_coupled; i++) { 407262306a36Sopenharmony_ci /* 407362306a36Sopenharmony_ci * optimal_uV is the best voltage that can be set for 407462306a36Sopenharmony_ci * i-th regulator at the moment without violating 407562306a36Sopenharmony_ci * max_spread constraint in order to balance 407662306a36Sopenharmony_ci * the coupled voltages. 407762306a36Sopenharmony_ci */ 407862306a36Sopenharmony_ci int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; 407962306a36Sopenharmony_ci 408062306a36Sopenharmony_ci if (test_bit(i, &c_rdev_done)) 408162306a36Sopenharmony_ci continue; 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_ci ret = regulator_get_optimal_voltage(c_rdevs[i], 408462306a36Sopenharmony_ci ¤t_uV, 408562306a36Sopenharmony_ci &optimal_uV, 408662306a36Sopenharmony_ci &optimal_max_uV, 408762306a36Sopenharmony_ci state, n_coupled); 408862306a36Sopenharmony_ci if (ret < 0) 408962306a36Sopenharmony_ci goto out; 409062306a36Sopenharmony_ci 409162306a36Sopenharmony_ci delta = abs(optimal_uV - current_uV); 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci if (delta && best_delta <= delta) { 409462306a36Sopenharmony_ci best_c_rdev_done = ret; 409562306a36Sopenharmony_ci best_delta = delta; 409662306a36Sopenharmony_ci best_rdev = c_rdevs[i]; 409762306a36Sopenharmony_ci best_min_uV = optimal_uV; 409862306a36Sopenharmony_ci best_max_uV = optimal_max_uV; 409962306a36Sopenharmony_ci best_c_rdev = i; 410062306a36Sopenharmony_ci } 410162306a36Sopenharmony_ci } 410262306a36Sopenharmony_ci 410362306a36Sopenharmony_ci /* Nothing to change, return successfully */ 410462306a36Sopenharmony_ci if (!best_rdev) { 410562306a36Sopenharmony_ci ret = 0; 410662306a36Sopenharmony_ci goto out; 410762306a36Sopenharmony_ci } 410862306a36Sopenharmony_ci 410962306a36Sopenharmony_ci ret = regulator_set_voltage_rdev(best_rdev, best_min_uV, 411062306a36Sopenharmony_ci best_max_uV, state); 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_ci if (ret < 0) 411362306a36Sopenharmony_ci goto out; 411462306a36Sopenharmony_ci 411562306a36Sopenharmony_ci if (best_c_rdev_done) 411662306a36Sopenharmony_ci set_bit(best_c_rdev, &c_rdev_done); 411762306a36Sopenharmony_ci 411862306a36Sopenharmony_ci } while (n_coupled > 1); 411962306a36Sopenharmony_ci 412062306a36Sopenharmony_ciout: 412162306a36Sopenharmony_ci return ret; 412262306a36Sopenharmony_ci} 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_cistatic int regulator_balance_voltage(struct regulator_dev *rdev, 412562306a36Sopenharmony_ci suspend_state_t state) 412662306a36Sopenharmony_ci{ 412762306a36Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 412862306a36Sopenharmony_ci struct regulator_coupler *coupler = c_desc->coupler; 412962306a36Sopenharmony_ci bool skip_coupled = false; 413062306a36Sopenharmony_ci 413162306a36Sopenharmony_ci /* 413262306a36Sopenharmony_ci * If system is in a state other than PM_SUSPEND_ON, don't check 413362306a36Sopenharmony_ci * other coupled regulators. 413462306a36Sopenharmony_ci */ 413562306a36Sopenharmony_ci if (state != PM_SUSPEND_ON) 413662306a36Sopenharmony_ci skip_coupled = true; 413762306a36Sopenharmony_ci 413862306a36Sopenharmony_ci if (c_desc->n_resolved < c_desc->n_coupled) { 413962306a36Sopenharmony_ci rdev_err(rdev, "Not all coupled regulators registered\n"); 414062306a36Sopenharmony_ci return -EPERM; 414162306a36Sopenharmony_ci } 414262306a36Sopenharmony_ci 414362306a36Sopenharmony_ci /* Invoke custom balancer for customized couplers */ 414462306a36Sopenharmony_ci if (coupler && coupler->balance_voltage) 414562306a36Sopenharmony_ci return coupler->balance_voltage(coupler, rdev, state); 414662306a36Sopenharmony_ci 414762306a36Sopenharmony_ci return regulator_do_balance_voltage(rdev, state, skip_coupled); 414862306a36Sopenharmony_ci} 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_ci/** 415162306a36Sopenharmony_ci * regulator_set_voltage - set regulator output voltage 415262306a36Sopenharmony_ci * @regulator: regulator source 415362306a36Sopenharmony_ci * @min_uV: Minimum required voltage in uV 415462306a36Sopenharmony_ci * @max_uV: Maximum acceptable voltage in uV 415562306a36Sopenharmony_ci * 415662306a36Sopenharmony_ci * Sets a voltage regulator to the desired output voltage. This can be set 415762306a36Sopenharmony_ci * during any regulator state. IOW, regulator can be disabled or enabled. 415862306a36Sopenharmony_ci * 415962306a36Sopenharmony_ci * If the regulator is enabled then the voltage will change to the new value 416062306a36Sopenharmony_ci * immediately otherwise if the regulator is disabled the regulator will 416162306a36Sopenharmony_ci * output at the new voltage when enabled. 416262306a36Sopenharmony_ci * 416362306a36Sopenharmony_ci * NOTE: If the regulator is shared between several devices then the lowest 416462306a36Sopenharmony_ci * request voltage that meets the system constraints will be used. 416562306a36Sopenharmony_ci * Regulator system constraints must be set for this regulator before 416662306a36Sopenharmony_ci * calling this function otherwise this call will fail. 416762306a36Sopenharmony_ci */ 416862306a36Sopenharmony_ciint regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) 416962306a36Sopenharmony_ci{ 417062306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 417162306a36Sopenharmony_ci int ret; 417262306a36Sopenharmony_ci 417362306a36Sopenharmony_ci regulator_lock_dependent(regulator->rdev, &ww_ctx); 417462306a36Sopenharmony_ci 417562306a36Sopenharmony_ci ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV, 417662306a36Sopenharmony_ci PM_SUSPEND_ON); 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_ci regulator_unlock_dependent(regulator->rdev, &ww_ctx); 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ci return ret; 418162306a36Sopenharmony_ci} 418262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_voltage); 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_cistatic inline int regulator_suspend_toggle(struct regulator_dev *rdev, 418562306a36Sopenharmony_ci suspend_state_t state, bool en) 418662306a36Sopenharmony_ci{ 418762306a36Sopenharmony_ci struct regulator_state *rstate; 418862306a36Sopenharmony_ci 418962306a36Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 419062306a36Sopenharmony_ci if (rstate == NULL) 419162306a36Sopenharmony_ci return -EINVAL; 419262306a36Sopenharmony_ci 419362306a36Sopenharmony_ci if (!rstate->changeable) 419462306a36Sopenharmony_ci return -EPERM; 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_ci rstate->enabled = (en) ? ENABLE_IN_SUSPEND : DISABLE_IN_SUSPEND; 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ci return 0; 419962306a36Sopenharmony_ci} 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ciint regulator_suspend_enable(struct regulator_dev *rdev, 420262306a36Sopenharmony_ci suspend_state_t state) 420362306a36Sopenharmony_ci{ 420462306a36Sopenharmony_ci return regulator_suspend_toggle(rdev, state, true); 420562306a36Sopenharmony_ci} 420662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_suspend_enable); 420762306a36Sopenharmony_ci 420862306a36Sopenharmony_ciint regulator_suspend_disable(struct regulator_dev *rdev, 420962306a36Sopenharmony_ci suspend_state_t state) 421062306a36Sopenharmony_ci{ 421162306a36Sopenharmony_ci struct regulator *regulator; 421262306a36Sopenharmony_ci struct regulator_voltage *voltage; 421362306a36Sopenharmony_ci 421462306a36Sopenharmony_ci /* 421562306a36Sopenharmony_ci * if any consumer wants this regulator device keeping on in 421662306a36Sopenharmony_ci * suspend states, don't set it as disabled. 421762306a36Sopenharmony_ci */ 421862306a36Sopenharmony_ci list_for_each_entry(regulator, &rdev->consumer_list, list) { 421962306a36Sopenharmony_ci voltage = ®ulator->voltage[state]; 422062306a36Sopenharmony_ci if (voltage->min_uV || voltage->max_uV) 422162306a36Sopenharmony_ci return 0; 422262306a36Sopenharmony_ci } 422362306a36Sopenharmony_ci 422462306a36Sopenharmony_ci return regulator_suspend_toggle(rdev, state, false); 422562306a36Sopenharmony_ci} 422662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_suspend_disable); 422762306a36Sopenharmony_ci 422862306a36Sopenharmony_cistatic int _regulator_set_suspend_voltage(struct regulator *regulator, 422962306a36Sopenharmony_ci int min_uV, int max_uV, 423062306a36Sopenharmony_ci suspend_state_t state) 423162306a36Sopenharmony_ci{ 423262306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 423362306a36Sopenharmony_ci struct regulator_state *rstate; 423462306a36Sopenharmony_ci 423562306a36Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 423662306a36Sopenharmony_ci if (rstate == NULL) 423762306a36Sopenharmony_ci return -EINVAL; 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ci if (rstate->min_uV == rstate->max_uV) { 424062306a36Sopenharmony_ci rdev_err(rdev, "The suspend voltage can't be changed!\n"); 424162306a36Sopenharmony_ci return -EPERM; 424262306a36Sopenharmony_ci } 424362306a36Sopenharmony_ci 424462306a36Sopenharmony_ci return regulator_set_voltage_unlocked(regulator, min_uV, max_uV, state); 424562306a36Sopenharmony_ci} 424662306a36Sopenharmony_ci 424762306a36Sopenharmony_ciint regulator_set_suspend_voltage(struct regulator *regulator, int min_uV, 424862306a36Sopenharmony_ci int max_uV, suspend_state_t state) 424962306a36Sopenharmony_ci{ 425062306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 425162306a36Sopenharmony_ci int ret; 425262306a36Sopenharmony_ci 425362306a36Sopenharmony_ci /* PM_SUSPEND_ON is handled by regulator_set_voltage() */ 425462306a36Sopenharmony_ci if (regulator_check_states(state) || state == PM_SUSPEND_ON) 425562306a36Sopenharmony_ci return -EINVAL; 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_ci regulator_lock_dependent(regulator->rdev, &ww_ctx); 425862306a36Sopenharmony_ci 425962306a36Sopenharmony_ci ret = _regulator_set_suspend_voltage(regulator, min_uV, 426062306a36Sopenharmony_ci max_uV, state); 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci regulator_unlock_dependent(regulator->rdev, &ww_ctx); 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_ci return ret; 426562306a36Sopenharmony_ci} 426662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_suspend_voltage); 426762306a36Sopenharmony_ci 426862306a36Sopenharmony_ci/** 426962306a36Sopenharmony_ci * regulator_set_voltage_time - get raise/fall time 427062306a36Sopenharmony_ci * @regulator: regulator source 427162306a36Sopenharmony_ci * @old_uV: starting voltage in microvolts 427262306a36Sopenharmony_ci * @new_uV: target voltage in microvolts 427362306a36Sopenharmony_ci * 427462306a36Sopenharmony_ci * Provided with the starting and ending voltage, this function attempts to 427562306a36Sopenharmony_ci * calculate the time in microseconds required to rise or fall to this new 427662306a36Sopenharmony_ci * voltage. 427762306a36Sopenharmony_ci */ 427862306a36Sopenharmony_ciint regulator_set_voltage_time(struct regulator *regulator, 427962306a36Sopenharmony_ci int old_uV, int new_uV) 428062306a36Sopenharmony_ci{ 428162306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 428262306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 428362306a36Sopenharmony_ci int old_sel = -1; 428462306a36Sopenharmony_ci int new_sel = -1; 428562306a36Sopenharmony_ci int voltage; 428662306a36Sopenharmony_ci int i; 428762306a36Sopenharmony_ci 428862306a36Sopenharmony_ci if (ops->set_voltage_time) 428962306a36Sopenharmony_ci return ops->set_voltage_time(rdev, old_uV, new_uV); 429062306a36Sopenharmony_ci else if (!ops->set_voltage_time_sel) 429162306a36Sopenharmony_ci return _regulator_set_voltage_time(rdev, old_uV, new_uV); 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_ci /* Currently requires operations to do this */ 429462306a36Sopenharmony_ci if (!ops->list_voltage || !rdev->desc->n_voltages) 429562306a36Sopenharmony_ci return -EINVAL; 429662306a36Sopenharmony_ci 429762306a36Sopenharmony_ci for (i = 0; i < rdev->desc->n_voltages; i++) { 429862306a36Sopenharmony_ci /* We only look for exact voltage matches here */ 429962306a36Sopenharmony_ci if (i < rdev->desc->linear_min_sel) 430062306a36Sopenharmony_ci continue; 430162306a36Sopenharmony_ci 430262306a36Sopenharmony_ci if (old_sel >= 0 && new_sel >= 0) 430362306a36Sopenharmony_ci break; 430462306a36Sopenharmony_ci 430562306a36Sopenharmony_ci voltage = regulator_list_voltage(regulator, i); 430662306a36Sopenharmony_ci if (voltage < 0) 430762306a36Sopenharmony_ci return -EINVAL; 430862306a36Sopenharmony_ci if (voltage == 0) 430962306a36Sopenharmony_ci continue; 431062306a36Sopenharmony_ci if (voltage == old_uV) 431162306a36Sopenharmony_ci old_sel = i; 431262306a36Sopenharmony_ci if (voltage == new_uV) 431362306a36Sopenharmony_ci new_sel = i; 431462306a36Sopenharmony_ci } 431562306a36Sopenharmony_ci 431662306a36Sopenharmony_ci if (old_sel < 0 || new_sel < 0) 431762306a36Sopenharmony_ci return -EINVAL; 431862306a36Sopenharmony_ci 431962306a36Sopenharmony_ci return ops->set_voltage_time_sel(rdev, old_sel, new_sel); 432062306a36Sopenharmony_ci} 432162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_voltage_time); 432262306a36Sopenharmony_ci 432362306a36Sopenharmony_ci/** 432462306a36Sopenharmony_ci * regulator_set_voltage_time_sel - get raise/fall time 432562306a36Sopenharmony_ci * @rdev: regulator source device 432662306a36Sopenharmony_ci * @old_selector: selector for starting voltage 432762306a36Sopenharmony_ci * @new_selector: selector for target voltage 432862306a36Sopenharmony_ci * 432962306a36Sopenharmony_ci * Provided with the starting and target voltage selectors, this function 433062306a36Sopenharmony_ci * returns time in microseconds required to rise or fall to this new voltage 433162306a36Sopenharmony_ci * 433262306a36Sopenharmony_ci * Drivers providing ramp_delay in regulation_constraints can use this as their 433362306a36Sopenharmony_ci * set_voltage_time_sel() operation. 433462306a36Sopenharmony_ci */ 433562306a36Sopenharmony_ciint regulator_set_voltage_time_sel(struct regulator_dev *rdev, 433662306a36Sopenharmony_ci unsigned int old_selector, 433762306a36Sopenharmony_ci unsigned int new_selector) 433862306a36Sopenharmony_ci{ 433962306a36Sopenharmony_ci int old_volt, new_volt; 434062306a36Sopenharmony_ci 434162306a36Sopenharmony_ci /* sanity check */ 434262306a36Sopenharmony_ci if (!rdev->desc->ops->list_voltage) 434362306a36Sopenharmony_ci return -EINVAL; 434462306a36Sopenharmony_ci 434562306a36Sopenharmony_ci old_volt = rdev->desc->ops->list_voltage(rdev, old_selector); 434662306a36Sopenharmony_ci new_volt = rdev->desc->ops->list_voltage(rdev, new_selector); 434762306a36Sopenharmony_ci 434862306a36Sopenharmony_ci if (rdev->desc->ops->set_voltage_time) 434962306a36Sopenharmony_ci return rdev->desc->ops->set_voltage_time(rdev, old_volt, 435062306a36Sopenharmony_ci new_volt); 435162306a36Sopenharmony_ci else 435262306a36Sopenharmony_ci return _regulator_set_voltage_time(rdev, old_volt, new_volt); 435362306a36Sopenharmony_ci} 435462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel); 435562306a36Sopenharmony_ci 435662306a36Sopenharmony_ciint regulator_sync_voltage_rdev(struct regulator_dev *rdev) 435762306a36Sopenharmony_ci{ 435862306a36Sopenharmony_ci int ret; 435962306a36Sopenharmony_ci 436062306a36Sopenharmony_ci regulator_lock(rdev); 436162306a36Sopenharmony_ci 436262306a36Sopenharmony_ci if (!rdev->desc->ops->set_voltage && 436362306a36Sopenharmony_ci !rdev->desc->ops->set_voltage_sel) { 436462306a36Sopenharmony_ci ret = -EINVAL; 436562306a36Sopenharmony_ci goto out; 436662306a36Sopenharmony_ci } 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci /* balance only, if regulator is coupled */ 436962306a36Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 1) 437062306a36Sopenharmony_ci ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 437162306a36Sopenharmony_ci else 437262306a36Sopenharmony_ci ret = -EOPNOTSUPP; 437362306a36Sopenharmony_ci 437462306a36Sopenharmony_ciout: 437562306a36Sopenharmony_ci regulator_unlock(rdev); 437662306a36Sopenharmony_ci return ret; 437762306a36Sopenharmony_ci} 437862306a36Sopenharmony_ci 437962306a36Sopenharmony_ci/** 438062306a36Sopenharmony_ci * regulator_sync_voltage - re-apply last regulator output voltage 438162306a36Sopenharmony_ci * @regulator: regulator source 438262306a36Sopenharmony_ci * 438362306a36Sopenharmony_ci * Re-apply the last configured voltage. This is intended to be used 438462306a36Sopenharmony_ci * where some external control source the consumer is cooperating with 438562306a36Sopenharmony_ci * has caused the configured voltage to change. 438662306a36Sopenharmony_ci */ 438762306a36Sopenharmony_ciint regulator_sync_voltage(struct regulator *regulator) 438862306a36Sopenharmony_ci{ 438962306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 439062306a36Sopenharmony_ci struct regulator_voltage *voltage = ®ulator->voltage[PM_SUSPEND_ON]; 439162306a36Sopenharmony_ci int ret, min_uV, max_uV; 439262306a36Sopenharmony_ci 439362306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) 439462306a36Sopenharmony_ci return 0; 439562306a36Sopenharmony_ci 439662306a36Sopenharmony_ci regulator_lock(rdev); 439762306a36Sopenharmony_ci 439862306a36Sopenharmony_ci if (!rdev->desc->ops->set_voltage && 439962306a36Sopenharmony_ci !rdev->desc->ops->set_voltage_sel) { 440062306a36Sopenharmony_ci ret = -EINVAL; 440162306a36Sopenharmony_ci goto out; 440262306a36Sopenharmony_ci } 440362306a36Sopenharmony_ci 440462306a36Sopenharmony_ci /* This is only going to work if we've had a voltage configured. */ 440562306a36Sopenharmony_ci if (!voltage->min_uV && !voltage->max_uV) { 440662306a36Sopenharmony_ci ret = -EINVAL; 440762306a36Sopenharmony_ci goto out; 440862306a36Sopenharmony_ci } 440962306a36Sopenharmony_ci 441062306a36Sopenharmony_ci min_uV = voltage->min_uV; 441162306a36Sopenharmony_ci max_uV = voltage->max_uV; 441262306a36Sopenharmony_ci 441362306a36Sopenharmony_ci /* This should be a paranoia check... */ 441462306a36Sopenharmony_ci ret = regulator_check_voltage(rdev, &min_uV, &max_uV); 441562306a36Sopenharmony_ci if (ret < 0) 441662306a36Sopenharmony_ci goto out; 441762306a36Sopenharmony_ci 441862306a36Sopenharmony_ci ret = regulator_check_consumers(rdev, &min_uV, &max_uV, 0); 441962306a36Sopenharmony_ci if (ret < 0) 442062306a36Sopenharmony_ci goto out; 442162306a36Sopenharmony_ci 442262306a36Sopenharmony_ci /* balance only, if regulator is coupled */ 442362306a36Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 1) 442462306a36Sopenharmony_ci ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 442562306a36Sopenharmony_ci else 442662306a36Sopenharmony_ci ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 442762306a36Sopenharmony_ci 442862306a36Sopenharmony_ciout: 442962306a36Sopenharmony_ci regulator_unlock(rdev); 443062306a36Sopenharmony_ci return ret; 443162306a36Sopenharmony_ci} 443262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_sync_voltage); 443362306a36Sopenharmony_ci 443462306a36Sopenharmony_ciint regulator_get_voltage_rdev(struct regulator_dev *rdev) 443562306a36Sopenharmony_ci{ 443662306a36Sopenharmony_ci int sel, ret; 443762306a36Sopenharmony_ci bool bypassed; 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci if (rdev->desc->ops->get_bypass) { 444062306a36Sopenharmony_ci ret = rdev->desc->ops->get_bypass(rdev, &bypassed); 444162306a36Sopenharmony_ci if (ret < 0) 444262306a36Sopenharmony_ci return ret; 444362306a36Sopenharmony_ci if (bypassed) { 444462306a36Sopenharmony_ci /* if bypassed the regulator must have a supply */ 444562306a36Sopenharmony_ci if (!rdev->supply) { 444662306a36Sopenharmony_ci rdev_err(rdev, 444762306a36Sopenharmony_ci "bypassed regulator has no supply!\n"); 444862306a36Sopenharmony_ci return -EPROBE_DEFER; 444962306a36Sopenharmony_ci } 445062306a36Sopenharmony_ci 445162306a36Sopenharmony_ci return regulator_get_voltage_rdev(rdev->supply->rdev); 445262306a36Sopenharmony_ci } 445362306a36Sopenharmony_ci } 445462306a36Sopenharmony_ci 445562306a36Sopenharmony_ci if (rdev->desc->ops->get_voltage_sel) { 445662306a36Sopenharmony_ci sel = rdev->desc->ops->get_voltage_sel(rdev); 445762306a36Sopenharmony_ci if (sel < 0) 445862306a36Sopenharmony_ci return sel; 445962306a36Sopenharmony_ci ret = rdev->desc->ops->list_voltage(rdev, sel); 446062306a36Sopenharmony_ci } else if (rdev->desc->ops->get_voltage) { 446162306a36Sopenharmony_ci ret = rdev->desc->ops->get_voltage(rdev); 446262306a36Sopenharmony_ci } else if (rdev->desc->ops->list_voltage) { 446362306a36Sopenharmony_ci ret = rdev->desc->ops->list_voltage(rdev, 0); 446462306a36Sopenharmony_ci } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { 446562306a36Sopenharmony_ci ret = rdev->desc->fixed_uV; 446662306a36Sopenharmony_ci } else if (rdev->supply) { 446762306a36Sopenharmony_ci ret = regulator_get_voltage_rdev(rdev->supply->rdev); 446862306a36Sopenharmony_ci } else if (rdev->supply_name) { 446962306a36Sopenharmony_ci return -EPROBE_DEFER; 447062306a36Sopenharmony_ci } else { 447162306a36Sopenharmony_ci return -EINVAL; 447262306a36Sopenharmony_ci } 447362306a36Sopenharmony_ci 447462306a36Sopenharmony_ci if (ret < 0) 447562306a36Sopenharmony_ci return ret; 447662306a36Sopenharmony_ci return ret - rdev->constraints->uV_offset; 447762306a36Sopenharmony_ci} 447862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_voltage_rdev); 447962306a36Sopenharmony_ci 448062306a36Sopenharmony_ci/** 448162306a36Sopenharmony_ci * regulator_get_voltage - get regulator output voltage 448262306a36Sopenharmony_ci * @regulator: regulator source 448362306a36Sopenharmony_ci * 448462306a36Sopenharmony_ci * This returns the current regulator voltage in uV. 448562306a36Sopenharmony_ci * 448662306a36Sopenharmony_ci * NOTE: If the regulator is disabled it will return the voltage value. This 448762306a36Sopenharmony_ci * function should not be used to determine regulator state. 448862306a36Sopenharmony_ci */ 448962306a36Sopenharmony_ciint regulator_get_voltage(struct regulator *regulator) 449062306a36Sopenharmony_ci{ 449162306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 449262306a36Sopenharmony_ci int ret; 449362306a36Sopenharmony_ci 449462306a36Sopenharmony_ci regulator_lock_dependent(regulator->rdev, &ww_ctx); 449562306a36Sopenharmony_ci ret = regulator_get_voltage_rdev(regulator->rdev); 449662306a36Sopenharmony_ci regulator_unlock_dependent(regulator->rdev, &ww_ctx); 449762306a36Sopenharmony_ci 449862306a36Sopenharmony_ci return ret; 449962306a36Sopenharmony_ci} 450062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_voltage); 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci/** 450362306a36Sopenharmony_ci * regulator_set_current_limit - set regulator output current limit 450462306a36Sopenharmony_ci * @regulator: regulator source 450562306a36Sopenharmony_ci * @min_uA: Minimum supported current in uA 450662306a36Sopenharmony_ci * @max_uA: Maximum supported current in uA 450762306a36Sopenharmony_ci * 450862306a36Sopenharmony_ci * Sets current sink to the desired output current. This can be set during 450962306a36Sopenharmony_ci * any regulator state. IOW, regulator can be disabled or enabled. 451062306a36Sopenharmony_ci * 451162306a36Sopenharmony_ci * If the regulator is enabled then the current will change to the new value 451262306a36Sopenharmony_ci * immediately otherwise if the regulator is disabled the regulator will 451362306a36Sopenharmony_ci * output at the new current when enabled. 451462306a36Sopenharmony_ci * 451562306a36Sopenharmony_ci * NOTE: Regulator system constraints must be set for this regulator before 451662306a36Sopenharmony_ci * calling this function otherwise this call will fail. 451762306a36Sopenharmony_ci */ 451862306a36Sopenharmony_ciint regulator_set_current_limit(struct regulator *regulator, 451962306a36Sopenharmony_ci int min_uA, int max_uA) 452062306a36Sopenharmony_ci{ 452162306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 452262306a36Sopenharmony_ci int ret; 452362306a36Sopenharmony_ci 452462306a36Sopenharmony_ci regulator_lock(rdev); 452562306a36Sopenharmony_ci 452662306a36Sopenharmony_ci /* sanity check */ 452762306a36Sopenharmony_ci if (!rdev->desc->ops->set_current_limit) { 452862306a36Sopenharmony_ci ret = -EINVAL; 452962306a36Sopenharmony_ci goto out; 453062306a36Sopenharmony_ci } 453162306a36Sopenharmony_ci 453262306a36Sopenharmony_ci /* constraints check */ 453362306a36Sopenharmony_ci ret = regulator_check_current_limit(rdev, &min_uA, &max_uA); 453462306a36Sopenharmony_ci if (ret < 0) 453562306a36Sopenharmony_ci goto out; 453662306a36Sopenharmony_ci 453762306a36Sopenharmony_ci ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA); 453862306a36Sopenharmony_ciout: 453962306a36Sopenharmony_ci regulator_unlock(rdev); 454062306a36Sopenharmony_ci return ret; 454162306a36Sopenharmony_ci} 454262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_current_limit); 454362306a36Sopenharmony_ci 454462306a36Sopenharmony_cistatic int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev) 454562306a36Sopenharmony_ci{ 454662306a36Sopenharmony_ci /* sanity check */ 454762306a36Sopenharmony_ci if (!rdev->desc->ops->get_current_limit) 454862306a36Sopenharmony_ci return -EINVAL; 454962306a36Sopenharmony_ci 455062306a36Sopenharmony_ci return rdev->desc->ops->get_current_limit(rdev); 455162306a36Sopenharmony_ci} 455262306a36Sopenharmony_ci 455362306a36Sopenharmony_cistatic int _regulator_get_current_limit(struct regulator_dev *rdev) 455462306a36Sopenharmony_ci{ 455562306a36Sopenharmony_ci int ret; 455662306a36Sopenharmony_ci 455762306a36Sopenharmony_ci regulator_lock(rdev); 455862306a36Sopenharmony_ci ret = _regulator_get_current_limit_unlocked(rdev); 455962306a36Sopenharmony_ci regulator_unlock(rdev); 456062306a36Sopenharmony_ci 456162306a36Sopenharmony_ci return ret; 456262306a36Sopenharmony_ci} 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_ci/** 456562306a36Sopenharmony_ci * regulator_get_current_limit - get regulator output current 456662306a36Sopenharmony_ci * @regulator: regulator source 456762306a36Sopenharmony_ci * 456862306a36Sopenharmony_ci * This returns the current supplied by the specified current sink in uA. 456962306a36Sopenharmony_ci * 457062306a36Sopenharmony_ci * NOTE: If the regulator is disabled it will return the current value. This 457162306a36Sopenharmony_ci * function should not be used to determine regulator state. 457262306a36Sopenharmony_ci */ 457362306a36Sopenharmony_ciint regulator_get_current_limit(struct regulator *regulator) 457462306a36Sopenharmony_ci{ 457562306a36Sopenharmony_ci return _regulator_get_current_limit(regulator->rdev); 457662306a36Sopenharmony_ci} 457762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_current_limit); 457862306a36Sopenharmony_ci 457962306a36Sopenharmony_ci/** 458062306a36Sopenharmony_ci * regulator_set_mode - set regulator operating mode 458162306a36Sopenharmony_ci * @regulator: regulator source 458262306a36Sopenharmony_ci * @mode: operating mode - one of the REGULATOR_MODE constants 458362306a36Sopenharmony_ci * 458462306a36Sopenharmony_ci * Set regulator operating mode to increase regulator efficiency or improve 458562306a36Sopenharmony_ci * regulation performance. 458662306a36Sopenharmony_ci * 458762306a36Sopenharmony_ci * NOTE: Regulator system constraints must be set for this regulator before 458862306a36Sopenharmony_ci * calling this function otherwise this call will fail. 458962306a36Sopenharmony_ci */ 459062306a36Sopenharmony_ciint regulator_set_mode(struct regulator *regulator, unsigned int mode) 459162306a36Sopenharmony_ci{ 459262306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 459362306a36Sopenharmony_ci int ret; 459462306a36Sopenharmony_ci int regulator_curr_mode; 459562306a36Sopenharmony_ci 459662306a36Sopenharmony_ci regulator_lock(rdev); 459762306a36Sopenharmony_ci 459862306a36Sopenharmony_ci /* sanity check */ 459962306a36Sopenharmony_ci if (!rdev->desc->ops->set_mode) { 460062306a36Sopenharmony_ci ret = -EINVAL; 460162306a36Sopenharmony_ci goto out; 460262306a36Sopenharmony_ci } 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_ci /* return if the same mode is requested */ 460562306a36Sopenharmony_ci if (rdev->desc->ops->get_mode) { 460662306a36Sopenharmony_ci regulator_curr_mode = rdev->desc->ops->get_mode(rdev); 460762306a36Sopenharmony_ci if (regulator_curr_mode == mode) { 460862306a36Sopenharmony_ci ret = 0; 460962306a36Sopenharmony_ci goto out; 461062306a36Sopenharmony_ci } 461162306a36Sopenharmony_ci } 461262306a36Sopenharmony_ci 461362306a36Sopenharmony_ci /* constraints check */ 461462306a36Sopenharmony_ci ret = regulator_mode_constrain(rdev, &mode); 461562306a36Sopenharmony_ci if (ret < 0) 461662306a36Sopenharmony_ci goto out; 461762306a36Sopenharmony_ci 461862306a36Sopenharmony_ci ret = rdev->desc->ops->set_mode(rdev, mode); 461962306a36Sopenharmony_ciout: 462062306a36Sopenharmony_ci regulator_unlock(rdev); 462162306a36Sopenharmony_ci return ret; 462262306a36Sopenharmony_ci} 462362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_mode); 462462306a36Sopenharmony_ci 462562306a36Sopenharmony_cistatic unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev) 462662306a36Sopenharmony_ci{ 462762306a36Sopenharmony_ci /* sanity check */ 462862306a36Sopenharmony_ci if (!rdev->desc->ops->get_mode) 462962306a36Sopenharmony_ci return -EINVAL; 463062306a36Sopenharmony_ci 463162306a36Sopenharmony_ci return rdev->desc->ops->get_mode(rdev); 463262306a36Sopenharmony_ci} 463362306a36Sopenharmony_ci 463462306a36Sopenharmony_cistatic unsigned int _regulator_get_mode(struct regulator_dev *rdev) 463562306a36Sopenharmony_ci{ 463662306a36Sopenharmony_ci int ret; 463762306a36Sopenharmony_ci 463862306a36Sopenharmony_ci regulator_lock(rdev); 463962306a36Sopenharmony_ci ret = _regulator_get_mode_unlocked(rdev); 464062306a36Sopenharmony_ci regulator_unlock(rdev); 464162306a36Sopenharmony_ci 464262306a36Sopenharmony_ci return ret; 464362306a36Sopenharmony_ci} 464462306a36Sopenharmony_ci 464562306a36Sopenharmony_ci/** 464662306a36Sopenharmony_ci * regulator_get_mode - get regulator operating mode 464762306a36Sopenharmony_ci * @regulator: regulator source 464862306a36Sopenharmony_ci * 464962306a36Sopenharmony_ci * Get the current regulator operating mode. 465062306a36Sopenharmony_ci */ 465162306a36Sopenharmony_ciunsigned int regulator_get_mode(struct regulator *regulator) 465262306a36Sopenharmony_ci{ 465362306a36Sopenharmony_ci return _regulator_get_mode(regulator->rdev); 465462306a36Sopenharmony_ci} 465562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_mode); 465662306a36Sopenharmony_ci 465762306a36Sopenharmony_cistatic int rdev_get_cached_err_flags(struct regulator_dev *rdev) 465862306a36Sopenharmony_ci{ 465962306a36Sopenharmony_ci int ret = 0; 466062306a36Sopenharmony_ci 466162306a36Sopenharmony_ci if (rdev->use_cached_err) { 466262306a36Sopenharmony_ci spin_lock(&rdev->err_lock); 466362306a36Sopenharmony_ci ret = rdev->cached_err; 466462306a36Sopenharmony_ci spin_unlock(&rdev->err_lock); 466562306a36Sopenharmony_ci } 466662306a36Sopenharmony_ci return ret; 466762306a36Sopenharmony_ci} 466862306a36Sopenharmony_ci 466962306a36Sopenharmony_cistatic int _regulator_get_error_flags(struct regulator_dev *rdev, 467062306a36Sopenharmony_ci unsigned int *flags) 467162306a36Sopenharmony_ci{ 467262306a36Sopenharmony_ci int cached_flags, ret = 0; 467362306a36Sopenharmony_ci 467462306a36Sopenharmony_ci regulator_lock(rdev); 467562306a36Sopenharmony_ci 467662306a36Sopenharmony_ci cached_flags = rdev_get_cached_err_flags(rdev); 467762306a36Sopenharmony_ci 467862306a36Sopenharmony_ci if (rdev->desc->ops->get_error_flags) 467962306a36Sopenharmony_ci ret = rdev->desc->ops->get_error_flags(rdev, flags); 468062306a36Sopenharmony_ci else if (!rdev->use_cached_err) 468162306a36Sopenharmony_ci ret = -EINVAL; 468262306a36Sopenharmony_ci 468362306a36Sopenharmony_ci *flags |= cached_flags; 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci regulator_unlock(rdev); 468662306a36Sopenharmony_ci 468762306a36Sopenharmony_ci return ret; 468862306a36Sopenharmony_ci} 468962306a36Sopenharmony_ci 469062306a36Sopenharmony_ci/** 469162306a36Sopenharmony_ci * regulator_get_error_flags - get regulator error information 469262306a36Sopenharmony_ci * @regulator: regulator source 469362306a36Sopenharmony_ci * @flags: pointer to store error flags 469462306a36Sopenharmony_ci * 469562306a36Sopenharmony_ci * Get the current regulator error information. 469662306a36Sopenharmony_ci */ 469762306a36Sopenharmony_ciint regulator_get_error_flags(struct regulator *regulator, 469862306a36Sopenharmony_ci unsigned int *flags) 469962306a36Sopenharmony_ci{ 470062306a36Sopenharmony_ci return _regulator_get_error_flags(regulator->rdev, flags); 470162306a36Sopenharmony_ci} 470262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_error_flags); 470362306a36Sopenharmony_ci 470462306a36Sopenharmony_ci/** 470562306a36Sopenharmony_ci * regulator_set_load - set regulator load 470662306a36Sopenharmony_ci * @regulator: regulator source 470762306a36Sopenharmony_ci * @uA_load: load current 470862306a36Sopenharmony_ci * 470962306a36Sopenharmony_ci * Notifies the regulator core of a new device load. This is then used by 471062306a36Sopenharmony_ci * DRMS (if enabled by constraints) to set the most efficient regulator 471162306a36Sopenharmony_ci * operating mode for the new regulator loading. 471262306a36Sopenharmony_ci * 471362306a36Sopenharmony_ci * Consumer devices notify their supply regulator of the maximum power 471462306a36Sopenharmony_ci * they will require (can be taken from device datasheet in the power 471562306a36Sopenharmony_ci * consumption tables) when they change operational status and hence power 471662306a36Sopenharmony_ci * state. Examples of operational state changes that can affect power 471762306a36Sopenharmony_ci * consumption are :- 471862306a36Sopenharmony_ci * 471962306a36Sopenharmony_ci * o Device is opened / closed. 472062306a36Sopenharmony_ci * o Device I/O is about to begin or has just finished. 472162306a36Sopenharmony_ci * o Device is idling in between work. 472262306a36Sopenharmony_ci * 472362306a36Sopenharmony_ci * This information is also exported via sysfs to userspace. 472462306a36Sopenharmony_ci * 472562306a36Sopenharmony_ci * DRMS will sum the total requested load on the regulator and change 472662306a36Sopenharmony_ci * to the most efficient operating mode if platform constraints allow. 472762306a36Sopenharmony_ci * 472862306a36Sopenharmony_ci * NOTE: when a regulator consumer requests to have a regulator 472962306a36Sopenharmony_ci * disabled then any load that consumer requested no longer counts 473062306a36Sopenharmony_ci * toward the total requested load. If the regulator is re-enabled 473162306a36Sopenharmony_ci * then the previously requested load will start counting again. 473262306a36Sopenharmony_ci * 473362306a36Sopenharmony_ci * If a regulator is an always-on regulator then an individual consumer's 473462306a36Sopenharmony_ci * load will still be removed if that consumer is fully disabled. 473562306a36Sopenharmony_ci * 473662306a36Sopenharmony_ci * On error a negative errno is returned. 473762306a36Sopenharmony_ci */ 473862306a36Sopenharmony_ciint regulator_set_load(struct regulator *regulator, int uA_load) 473962306a36Sopenharmony_ci{ 474062306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 474162306a36Sopenharmony_ci int old_uA_load; 474262306a36Sopenharmony_ci int ret = 0; 474362306a36Sopenharmony_ci 474462306a36Sopenharmony_ci regulator_lock(rdev); 474562306a36Sopenharmony_ci old_uA_load = regulator->uA_load; 474662306a36Sopenharmony_ci regulator->uA_load = uA_load; 474762306a36Sopenharmony_ci if (regulator->enable_count && old_uA_load != uA_load) { 474862306a36Sopenharmony_ci ret = drms_uA_update(rdev); 474962306a36Sopenharmony_ci if (ret < 0) 475062306a36Sopenharmony_ci regulator->uA_load = old_uA_load; 475162306a36Sopenharmony_ci } 475262306a36Sopenharmony_ci regulator_unlock(rdev); 475362306a36Sopenharmony_ci 475462306a36Sopenharmony_ci return ret; 475562306a36Sopenharmony_ci} 475662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_load); 475762306a36Sopenharmony_ci 475862306a36Sopenharmony_ci/** 475962306a36Sopenharmony_ci * regulator_allow_bypass - allow the regulator to go into bypass mode 476062306a36Sopenharmony_ci * 476162306a36Sopenharmony_ci * @regulator: Regulator to configure 476262306a36Sopenharmony_ci * @enable: enable or disable bypass mode 476362306a36Sopenharmony_ci * 476462306a36Sopenharmony_ci * Allow the regulator to go into bypass mode if all other consumers 476562306a36Sopenharmony_ci * for the regulator also enable bypass mode and the machine 476662306a36Sopenharmony_ci * constraints allow this. Bypass mode means that the regulator is 476762306a36Sopenharmony_ci * simply passing the input directly to the output with no regulation. 476862306a36Sopenharmony_ci */ 476962306a36Sopenharmony_ciint regulator_allow_bypass(struct regulator *regulator, bool enable) 477062306a36Sopenharmony_ci{ 477162306a36Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 477262306a36Sopenharmony_ci const char *name = rdev_get_name(rdev); 477362306a36Sopenharmony_ci int ret = 0; 477462306a36Sopenharmony_ci 477562306a36Sopenharmony_ci if (!rdev->desc->ops->set_bypass) 477662306a36Sopenharmony_ci return 0; 477762306a36Sopenharmony_ci 477862306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_BYPASS)) 477962306a36Sopenharmony_ci return 0; 478062306a36Sopenharmony_ci 478162306a36Sopenharmony_ci regulator_lock(rdev); 478262306a36Sopenharmony_ci 478362306a36Sopenharmony_ci if (enable && !regulator->bypass) { 478462306a36Sopenharmony_ci rdev->bypass_count++; 478562306a36Sopenharmony_ci 478662306a36Sopenharmony_ci if (rdev->bypass_count == rdev->open_count) { 478762306a36Sopenharmony_ci trace_regulator_bypass_enable(name); 478862306a36Sopenharmony_ci 478962306a36Sopenharmony_ci ret = rdev->desc->ops->set_bypass(rdev, enable); 479062306a36Sopenharmony_ci if (ret != 0) 479162306a36Sopenharmony_ci rdev->bypass_count--; 479262306a36Sopenharmony_ci else 479362306a36Sopenharmony_ci trace_regulator_bypass_enable_complete(name); 479462306a36Sopenharmony_ci } 479562306a36Sopenharmony_ci 479662306a36Sopenharmony_ci } else if (!enable && regulator->bypass) { 479762306a36Sopenharmony_ci rdev->bypass_count--; 479862306a36Sopenharmony_ci 479962306a36Sopenharmony_ci if (rdev->bypass_count != rdev->open_count) { 480062306a36Sopenharmony_ci trace_regulator_bypass_disable(name); 480162306a36Sopenharmony_ci 480262306a36Sopenharmony_ci ret = rdev->desc->ops->set_bypass(rdev, enable); 480362306a36Sopenharmony_ci if (ret != 0) 480462306a36Sopenharmony_ci rdev->bypass_count++; 480562306a36Sopenharmony_ci else 480662306a36Sopenharmony_ci trace_regulator_bypass_disable_complete(name); 480762306a36Sopenharmony_ci } 480862306a36Sopenharmony_ci } 480962306a36Sopenharmony_ci 481062306a36Sopenharmony_ci if (ret == 0) 481162306a36Sopenharmony_ci regulator->bypass = enable; 481262306a36Sopenharmony_ci 481362306a36Sopenharmony_ci regulator_unlock(rdev); 481462306a36Sopenharmony_ci 481562306a36Sopenharmony_ci return ret; 481662306a36Sopenharmony_ci} 481762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_allow_bypass); 481862306a36Sopenharmony_ci 481962306a36Sopenharmony_ci/** 482062306a36Sopenharmony_ci * regulator_register_notifier - register regulator event notifier 482162306a36Sopenharmony_ci * @regulator: regulator source 482262306a36Sopenharmony_ci * @nb: notifier block 482362306a36Sopenharmony_ci * 482462306a36Sopenharmony_ci * Register notifier block to receive regulator events. 482562306a36Sopenharmony_ci */ 482662306a36Sopenharmony_ciint regulator_register_notifier(struct regulator *regulator, 482762306a36Sopenharmony_ci struct notifier_block *nb) 482862306a36Sopenharmony_ci{ 482962306a36Sopenharmony_ci return blocking_notifier_chain_register(®ulator->rdev->notifier, 483062306a36Sopenharmony_ci nb); 483162306a36Sopenharmony_ci} 483262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_register_notifier); 483362306a36Sopenharmony_ci 483462306a36Sopenharmony_ci/** 483562306a36Sopenharmony_ci * regulator_unregister_notifier - unregister regulator event notifier 483662306a36Sopenharmony_ci * @regulator: regulator source 483762306a36Sopenharmony_ci * @nb: notifier block 483862306a36Sopenharmony_ci * 483962306a36Sopenharmony_ci * Unregister regulator event notifier block. 484062306a36Sopenharmony_ci */ 484162306a36Sopenharmony_ciint regulator_unregister_notifier(struct regulator *regulator, 484262306a36Sopenharmony_ci struct notifier_block *nb) 484362306a36Sopenharmony_ci{ 484462306a36Sopenharmony_ci return blocking_notifier_chain_unregister(®ulator->rdev->notifier, 484562306a36Sopenharmony_ci nb); 484662306a36Sopenharmony_ci} 484762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_unregister_notifier); 484862306a36Sopenharmony_ci 484962306a36Sopenharmony_ci/* notify regulator consumers and downstream regulator consumers. 485062306a36Sopenharmony_ci * Note mutex must be held by caller. 485162306a36Sopenharmony_ci */ 485262306a36Sopenharmony_cistatic int _notifier_call_chain(struct regulator_dev *rdev, 485362306a36Sopenharmony_ci unsigned long event, void *data) 485462306a36Sopenharmony_ci{ 485562306a36Sopenharmony_ci /* call rdev chain first */ 485662306a36Sopenharmony_ci return blocking_notifier_call_chain(&rdev->notifier, event, data); 485762306a36Sopenharmony_ci} 485862306a36Sopenharmony_ci 485962306a36Sopenharmony_ciint _regulator_bulk_get(struct device *dev, int num_consumers, 486062306a36Sopenharmony_ci struct regulator_bulk_data *consumers, enum regulator_get_type get_type) 486162306a36Sopenharmony_ci{ 486262306a36Sopenharmony_ci int i; 486362306a36Sopenharmony_ci int ret; 486462306a36Sopenharmony_ci 486562306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) 486662306a36Sopenharmony_ci consumers[i].consumer = NULL; 486762306a36Sopenharmony_ci 486862306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 486962306a36Sopenharmony_ci consumers[i].consumer = _regulator_get(dev, 487062306a36Sopenharmony_ci consumers[i].supply, get_type); 487162306a36Sopenharmony_ci if (IS_ERR(consumers[i].consumer)) { 487262306a36Sopenharmony_ci ret = dev_err_probe(dev, PTR_ERR(consumers[i].consumer), 487362306a36Sopenharmony_ci "Failed to get supply '%s'", 487462306a36Sopenharmony_ci consumers[i].supply); 487562306a36Sopenharmony_ci consumers[i].consumer = NULL; 487662306a36Sopenharmony_ci goto err; 487762306a36Sopenharmony_ci } 487862306a36Sopenharmony_ci 487962306a36Sopenharmony_ci if (consumers[i].init_load_uA > 0) { 488062306a36Sopenharmony_ci ret = regulator_set_load(consumers[i].consumer, 488162306a36Sopenharmony_ci consumers[i].init_load_uA); 488262306a36Sopenharmony_ci if (ret) { 488362306a36Sopenharmony_ci i++; 488462306a36Sopenharmony_ci goto err; 488562306a36Sopenharmony_ci } 488662306a36Sopenharmony_ci } 488762306a36Sopenharmony_ci } 488862306a36Sopenharmony_ci 488962306a36Sopenharmony_ci return 0; 489062306a36Sopenharmony_ci 489162306a36Sopenharmony_cierr: 489262306a36Sopenharmony_ci while (--i >= 0) 489362306a36Sopenharmony_ci regulator_put(consumers[i].consumer); 489462306a36Sopenharmony_ci 489562306a36Sopenharmony_ci return ret; 489662306a36Sopenharmony_ci} 489762306a36Sopenharmony_ci 489862306a36Sopenharmony_ci/** 489962306a36Sopenharmony_ci * regulator_bulk_get - get multiple regulator consumers 490062306a36Sopenharmony_ci * 490162306a36Sopenharmony_ci * @dev: Device to supply 490262306a36Sopenharmony_ci * @num_consumers: Number of consumers to register 490362306a36Sopenharmony_ci * @consumers: Configuration of consumers; clients are stored here. 490462306a36Sopenharmony_ci * 490562306a36Sopenharmony_ci * @return 0 on success, an errno on failure. 490662306a36Sopenharmony_ci * 490762306a36Sopenharmony_ci * This helper function allows drivers to get several regulator 490862306a36Sopenharmony_ci * consumers in one operation. If any of the regulators cannot be 490962306a36Sopenharmony_ci * acquired then any regulators that were allocated will be freed 491062306a36Sopenharmony_ci * before returning to the caller. 491162306a36Sopenharmony_ci */ 491262306a36Sopenharmony_ciint regulator_bulk_get(struct device *dev, int num_consumers, 491362306a36Sopenharmony_ci struct regulator_bulk_data *consumers) 491462306a36Sopenharmony_ci{ 491562306a36Sopenharmony_ci return _regulator_bulk_get(dev, num_consumers, consumers, NORMAL_GET); 491662306a36Sopenharmony_ci} 491762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_get); 491862306a36Sopenharmony_ci 491962306a36Sopenharmony_cistatic void regulator_bulk_enable_async(void *data, async_cookie_t cookie) 492062306a36Sopenharmony_ci{ 492162306a36Sopenharmony_ci struct regulator_bulk_data *bulk = data; 492262306a36Sopenharmony_ci 492362306a36Sopenharmony_ci bulk->ret = regulator_enable(bulk->consumer); 492462306a36Sopenharmony_ci} 492562306a36Sopenharmony_ci 492662306a36Sopenharmony_ci/** 492762306a36Sopenharmony_ci * regulator_bulk_enable - enable multiple regulator consumers 492862306a36Sopenharmony_ci * 492962306a36Sopenharmony_ci * @num_consumers: Number of consumers 493062306a36Sopenharmony_ci * @consumers: Consumer data; clients are stored here. 493162306a36Sopenharmony_ci * @return 0 on success, an errno on failure 493262306a36Sopenharmony_ci * 493362306a36Sopenharmony_ci * This convenience API allows consumers to enable multiple regulator 493462306a36Sopenharmony_ci * clients in a single API call. If any consumers cannot be enabled 493562306a36Sopenharmony_ci * then any others that were enabled will be disabled again prior to 493662306a36Sopenharmony_ci * return. 493762306a36Sopenharmony_ci */ 493862306a36Sopenharmony_ciint regulator_bulk_enable(int num_consumers, 493962306a36Sopenharmony_ci struct regulator_bulk_data *consumers) 494062306a36Sopenharmony_ci{ 494162306a36Sopenharmony_ci ASYNC_DOMAIN_EXCLUSIVE(async_domain); 494262306a36Sopenharmony_ci int i; 494362306a36Sopenharmony_ci int ret = 0; 494462306a36Sopenharmony_ci 494562306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 494662306a36Sopenharmony_ci async_schedule_domain(regulator_bulk_enable_async, 494762306a36Sopenharmony_ci &consumers[i], &async_domain); 494862306a36Sopenharmony_ci } 494962306a36Sopenharmony_ci 495062306a36Sopenharmony_ci async_synchronize_full_domain(&async_domain); 495162306a36Sopenharmony_ci 495262306a36Sopenharmony_ci /* If any consumer failed we need to unwind any that succeeded */ 495362306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 495462306a36Sopenharmony_ci if (consumers[i].ret != 0) { 495562306a36Sopenharmony_ci ret = consumers[i].ret; 495662306a36Sopenharmony_ci goto err; 495762306a36Sopenharmony_ci } 495862306a36Sopenharmony_ci } 495962306a36Sopenharmony_ci 496062306a36Sopenharmony_ci return 0; 496162306a36Sopenharmony_ci 496262306a36Sopenharmony_cierr: 496362306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 496462306a36Sopenharmony_ci if (consumers[i].ret < 0) 496562306a36Sopenharmony_ci pr_err("Failed to enable %s: %pe\n", consumers[i].supply, 496662306a36Sopenharmony_ci ERR_PTR(consumers[i].ret)); 496762306a36Sopenharmony_ci else 496862306a36Sopenharmony_ci regulator_disable(consumers[i].consumer); 496962306a36Sopenharmony_ci } 497062306a36Sopenharmony_ci 497162306a36Sopenharmony_ci return ret; 497262306a36Sopenharmony_ci} 497362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_enable); 497462306a36Sopenharmony_ci 497562306a36Sopenharmony_ci/** 497662306a36Sopenharmony_ci * regulator_bulk_disable - disable multiple regulator consumers 497762306a36Sopenharmony_ci * 497862306a36Sopenharmony_ci * @num_consumers: Number of consumers 497962306a36Sopenharmony_ci * @consumers: Consumer data; clients are stored here. 498062306a36Sopenharmony_ci * @return 0 on success, an errno on failure 498162306a36Sopenharmony_ci * 498262306a36Sopenharmony_ci * This convenience API allows consumers to disable multiple regulator 498362306a36Sopenharmony_ci * clients in a single API call. If any consumers cannot be disabled 498462306a36Sopenharmony_ci * then any others that were disabled will be enabled again prior to 498562306a36Sopenharmony_ci * return. 498662306a36Sopenharmony_ci */ 498762306a36Sopenharmony_ciint regulator_bulk_disable(int num_consumers, 498862306a36Sopenharmony_ci struct regulator_bulk_data *consumers) 498962306a36Sopenharmony_ci{ 499062306a36Sopenharmony_ci int i; 499162306a36Sopenharmony_ci int ret, r; 499262306a36Sopenharmony_ci 499362306a36Sopenharmony_ci for (i = num_consumers - 1; i >= 0; --i) { 499462306a36Sopenharmony_ci ret = regulator_disable(consumers[i].consumer); 499562306a36Sopenharmony_ci if (ret != 0) 499662306a36Sopenharmony_ci goto err; 499762306a36Sopenharmony_ci } 499862306a36Sopenharmony_ci 499962306a36Sopenharmony_ci return 0; 500062306a36Sopenharmony_ci 500162306a36Sopenharmony_cierr: 500262306a36Sopenharmony_ci pr_err("Failed to disable %s: %pe\n", consumers[i].supply, ERR_PTR(ret)); 500362306a36Sopenharmony_ci for (++i; i < num_consumers; ++i) { 500462306a36Sopenharmony_ci r = regulator_enable(consumers[i].consumer); 500562306a36Sopenharmony_ci if (r != 0) 500662306a36Sopenharmony_ci pr_err("Failed to re-enable %s: %pe\n", 500762306a36Sopenharmony_ci consumers[i].supply, ERR_PTR(r)); 500862306a36Sopenharmony_ci } 500962306a36Sopenharmony_ci 501062306a36Sopenharmony_ci return ret; 501162306a36Sopenharmony_ci} 501262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_disable); 501362306a36Sopenharmony_ci 501462306a36Sopenharmony_ci/** 501562306a36Sopenharmony_ci * regulator_bulk_force_disable - force disable multiple regulator consumers 501662306a36Sopenharmony_ci * 501762306a36Sopenharmony_ci * @num_consumers: Number of consumers 501862306a36Sopenharmony_ci * @consumers: Consumer data; clients are stored here. 501962306a36Sopenharmony_ci * @return 0 on success, an errno on failure 502062306a36Sopenharmony_ci * 502162306a36Sopenharmony_ci * This convenience API allows consumers to forcibly disable multiple regulator 502262306a36Sopenharmony_ci * clients in a single API call. 502362306a36Sopenharmony_ci * NOTE: This should be used for situations when device damage will 502462306a36Sopenharmony_ci * likely occur if the regulators are not disabled (e.g. over temp). 502562306a36Sopenharmony_ci * Although regulator_force_disable function call for some consumers can 502662306a36Sopenharmony_ci * return error numbers, the function is called for all consumers. 502762306a36Sopenharmony_ci */ 502862306a36Sopenharmony_ciint regulator_bulk_force_disable(int num_consumers, 502962306a36Sopenharmony_ci struct regulator_bulk_data *consumers) 503062306a36Sopenharmony_ci{ 503162306a36Sopenharmony_ci int i; 503262306a36Sopenharmony_ci int ret = 0; 503362306a36Sopenharmony_ci 503462306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 503562306a36Sopenharmony_ci consumers[i].ret = 503662306a36Sopenharmony_ci regulator_force_disable(consumers[i].consumer); 503762306a36Sopenharmony_ci 503862306a36Sopenharmony_ci /* Store first error for reporting */ 503962306a36Sopenharmony_ci if (consumers[i].ret && !ret) 504062306a36Sopenharmony_ci ret = consumers[i].ret; 504162306a36Sopenharmony_ci } 504262306a36Sopenharmony_ci 504362306a36Sopenharmony_ci return ret; 504462306a36Sopenharmony_ci} 504562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_force_disable); 504662306a36Sopenharmony_ci 504762306a36Sopenharmony_ci/** 504862306a36Sopenharmony_ci * regulator_bulk_free - free multiple regulator consumers 504962306a36Sopenharmony_ci * 505062306a36Sopenharmony_ci * @num_consumers: Number of consumers 505162306a36Sopenharmony_ci * @consumers: Consumer data; clients are stored here. 505262306a36Sopenharmony_ci * 505362306a36Sopenharmony_ci * This convenience API allows consumers to free multiple regulator 505462306a36Sopenharmony_ci * clients in a single API call. 505562306a36Sopenharmony_ci */ 505662306a36Sopenharmony_civoid regulator_bulk_free(int num_consumers, 505762306a36Sopenharmony_ci struct regulator_bulk_data *consumers) 505862306a36Sopenharmony_ci{ 505962306a36Sopenharmony_ci int i; 506062306a36Sopenharmony_ci 506162306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 506262306a36Sopenharmony_ci regulator_put(consumers[i].consumer); 506362306a36Sopenharmony_ci consumers[i].consumer = NULL; 506462306a36Sopenharmony_ci } 506562306a36Sopenharmony_ci} 506662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_free); 506762306a36Sopenharmony_ci 506862306a36Sopenharmony_ci/** 506962306a36Sopenharmony_ci * regulator_notifier_call_chain - call regulator event notifier 507062306a36Sopenharmony_ci * @rdev: regulator source 507162306a36Sopenharmony_ci * @event: notifier block 507262306a36Sopenharmony_ci * @data: callback-specific data. 507362306a36Sopenharmony_ci * 507462306a36Sopenharmony_ci * Called by regulator drivers to notify clients a regulator event has 507562306a36Sopenharmony_ci * occurred. 507662306a36Sopenharmony_ci */ 507762306a36Sopenharmony_ciint regulator_notifier_call_chain(struct regulator_dev *rdev, 507862306a36Sopenharmony_ci unsigned long event, void *data) 507962306a36Sopenharmony_ci{ 508062306a36Sopenharmony_ci _notifier_call_chain(rdev, event, data); 508162306a36Sopenharmony_ci return NOTIFY_DONE; 508262306a36Sopenharmony_ci 508362306a36Sopenharmony_ci} 508462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_notifier_call_chain); 508562306a36Sopenharmony_ci 508662306a36Sopenharmony_ci/** 508762306a36Sopenharmony_ci * regulator_mode_to_status - convert a regulator mode into a status 508862306a36Sopenharmony_ci * 508962306a36Sopenharmony_ci * @mode: Mode to convert 509062306a36Sopenharmony_ci * 509162306a36Sopenharmony_ci * Convert a regulator mode into a status. 509262306a36Sopenharmony_ci */ 509362306a36Sopenharmony_ciint regulator_mode_to_status(unsigned int mode) 509462306a36Sopenharmony_ci{ 509562306a36Sopenharmony_ci switch (mode) { 509662306a36Sopenharmony_ci case REGULATOR_MODE_FAST: 509762306a36Sopenharmony_ci return REGULATOR_STATUS_FAST; 509862306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 509962306a36Sopenharmony_ci return REGULATOR_STATUS_NORMAL; 510062306a36Sopenharmony_ci case REGULATOR_MODE_IDLE: 510162306a36Sopenharmony_ci return REGULATOR_STATUS_IDLE; 510262306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 510362306a36Sopenharmony_ci return REGULATOR_STATUS_STANDBY; 510462306a36Sopenharmony_ci default: 510562306a36Sopenharmony_ci return REGULATOR_STATUS_UNDEFINED; 510662306a36Sopenharmony_ci } 510762306a36Sopenharmony_ci} 510862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_mode_to_status); 510962306a36Sopenharmony_ci 511062306a36Sopenharmony_cistatic struct attribute *regulator_dev_attrs[] = { 511162306a36Sopenharmony_ci &dev_attr_name.attr, 511262306a36Sopenharmony_ci &dev_attr_num_users.attr, 511362306a36Sopenharmony_ci &dev_attr_type.attr, 511462306a36Sopenharmony_ci &dev_attr_microvolts.attr, 511562306a36Sopenharmony_ci &dev_attr_microamps.attr, 511662306a36Sopenharmony_ci &dev_attr_opmode.attr, 511762306a36Sopenharmony_ci &dev_attr_state.attr, 511862306a36Sopenharmony_ci &dev_attr_status.attr, 511962306a36Sopenharmony_ci &dev_attr_bypass.attr, 512062306a36Sopenharmony_ci &dev_attr_requested_microamps.attr, 512162306a36Sopenharmony_ci &dev_attr_min_microvolts.attr, 512262306a36Sopenharmony_ci &dev_attr_max_microvolts.attr, 512362306a36Sopenharmony_ci &dev_attr_min_microamps.attr, 512462306a36Sopenharmony_ci &dev_attr_max_microamps.attr, 512562306a36Sopenharmony_ci &dev_attr_under_voltage.attr, 512662306a36Sopenharmony_ci &dev_attr_over_current.attr, 512762306a36Sopenharmony_ci &dev_attr_regulation_out.attr, 512862306a36Sopenharmony_ci &dev_attr_fail.attr, 512962306a36Sopenharmony_ci &dev_attr_over_temp.attr, 513062306a36Sopenharmony_ci &dev_attr_under_voltage_warn.attr, 513162306a36Sopenharmony_ci &dev_attr_over_current_warn.attr, 513262306a36Sopenharmony_ci &dev_attr_over_voltage_warn.attr, 513362306a36Sopenharmony_ci &dev_attr_over_temp_warn.attr, 513462306a36Sopenharmony_ci &dev_attr_suspend_standby_state.attr, 513562306a36Sopenharmony_ci &dev_attr_suspend_mem_state.attr, 513662306a36Sopenharmony_ci &dev_attr_suspend_disk_state.attr, 513762306a36Sopenharmony_ci &dev_attr_suspend_standby_microvolts.attr, 513862306a36Sopenharmony_ci &dev_attr_suspend_mem_microvolts.attr, 513962306a36Sopenharmony_ci &dev_attr_suspend_disk_microvolts.attr, 514062306a36Sopenharmony_ci &dev_attr_suspend_standby_mode.attr, 514162306a36Sopenharmony_ci &dev_attr_suspend_mem_mode.attr, 514262306a36Sopenharmony_ci &dev_attr_suspend_disk_mode.attr, 514362306a36Sopenharmony_ci NULL 514462306a36Sopenharmony_ci}; 514562306a36Sopenharmony_ci 514662306a36Sopenharmony_ci/* 514762306a36Sopenharmony_ci * To avoid cluttering sysfs (and memory) with useless state, only 514862306a36Sopenharmony_ci * create attributes that can be meaningfully displayed. 514962306a36Sopenharmony_ci */ 515062306a36Sopenharmony_cistatic umode_t regulator_attr_is_visible(struct kobject *kobj, 515162306a36Sopenharmony_ci struct attribute *attr, int idx) 515262306a36Sopenharmony_ci{ 515362306a36Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 515462306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 515562306a36Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 515662306a36Sopenharmony_ci umode_t mode = attr->mode; 515762306a36Sopenharmony_ci 515862306a36Sopenharmony_ci /* these three are always present */ 515962306a36Sopenharmony_ci if (attr == &dev_attr_name.attr || 516062306a36Sopenharmony_ci attr == &dev_attr_num_users.attr || 516162306a36Sopenharmony_ci attr == &dev_attr_type.attr) 516262306a36Sopenharmony_ci return mode; 516362306a36Sopenharmony_ci 516462306a36Sopenharmony_ci /* some attributes need specific methods to be displayed */ 516562306a36Sopenharmony_ci if (attr == &dev_attr_microvolts.attr) { 516662306a36Sopenharmony_ci if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || 516762306a36Sopenharmony_ci (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || 516862306a36Sopenharmony_ci (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || 516962306a36Sopenharmony_ci (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1)) 517062306a36Sopenharmony_ci return mode; 517162306a36Sopenharmony_ci return 0; 517262306a36Sopenharmony_ci } 517362306a36Sopenharmony_ci 517462306a36Sopenharmony_ci if (attr == &dev_attr_microamps.attr) 517562306a36Sopenharmony_ci return ops->get_current_limit ? mode : 0; 517662306a36Sopenharmony_ci 517762306a36Sopenharmony_ci if (attr == &dev_attr_opmode.attr) 517862306a36Sopenharmony_ci return ops->get_mode ? mode : 0; 517962306a36Sopenharmony_ci 518062306a36Sopenharmony_ci if (attr == &dev_attr_state.attr) 518162306a36Sopenharmony_ci return (rdev->ena_pin || ops->is_enabled) ? mode : 0; 518262306a36Sopenharmony_ci 518362306a36Sopenharmony_ci if (attr == &dev_attr_status.attr) 518462306a36Sopenharmony_ci return ops->get_status ? mode : 0; 518562306a36Sopenharmony_ci 518662306a36Sopenharmony_ci if (attr == &dev_attr_bypass.attr) 518762306a36Sopenharmony_ci return ops->get_bypass ? mode : 0; 518862306a36Sopenharmony_ci 518962306a36Sopenharmony_ci if (attr == &dev_attr_under_voltage.attr || 519062306a36Sopenharmony_ci attr == &dev_attr_over_current.attr || 519162306a36Sopenharmony_ci attr == &dev_attr_regulation_out.attr || 519262306a36Sopenharmony_ci attr == &dev_attr_fail.attr || 519362306a36Sopenharmony_ci attr == &dev_attr_over_temp.attr || 519462306a36Sopenharmony_ci attr == &dev_attr_under_voltage_warn.attr || 519562306a36Sopenharmony_ci attr == &dev_attr_over_current_warn.attr || 519662306a36Sopenharmony_ci attr == &dev_attr_over_voltage_warn.attr || 519762306a36Sopenharmony_ci attr == &dev_attr_over_temp_warn.attr) 519862306a36Sopenharmony_ci return ops->get_error_flags ? mode : 0; 519962306a36Sopenharmony_ci 520062306a36Sopenharmony_ci /* constraints need specific supporting methods */ 520162306a36Sopenharmony_ci if (attr == &dev_attr_min_microvolts.attr || 520262306a36Sopenharmony_ci attr == &dev_attr_max_microvolts.attr) 520362306a36Sopenharmony_ci return (ops->set_voltage || ops->set_voltage_sel) ? mode : 0; 520462306a36Sopenharmony_ci 520562306a36Sopenharmony_ci if (attr == &dev_attr_min_microamps.attr || 520662306a36Sopenharmony_ci attr == &dev_attr_max_microamps.attr) 520762306a36Sopenharmony_ci return ops->set_current_limit ? mode : 0; 520862306a36Sopenharmony_ci 520962306a36Sopenharmony_ci if (attr == &dev_attr_suspend_standby_state.attr || 521062306a36Sopenharmony_ci attr == &dev_attr_suspend_mem_state.attr || 521162306a36Sopenharmony_ci attr == &dev_attr_suspend_disk_state.attr) 521262306a36Sopenharmony_ci return mode; 521362306a36Sopenharmony_ci 521462306a36Sopenharmony_ci if (attr == &dev_attr_suspend_standby_microvolts.attr || 521562306a36Sopenharmony_ci attr == &dev_attr_suspend_mem_microvolts.attr || 521662306a36Sopenharmony_ci attr == &dev_attr_suspend_disk_microvolts.attr) 521762306a36Sopenharmony_ci return ops->set_suspend_voltage ? mode : 0; 521862306a36Sopenharmony_ci 521962306a36Sopenharmony_ci if (attr == &dev_attr_suspend_standby_mode.attr || 522062306a36Sopenharmony_ci attr == &dev_attr_suspend_mem_mode.attr || 522162306a36Sopenharmony_ci attr == &dev_attr_suspend_disk_mode.attr) 522262306a36Sopenharmony_ci return ops->set_suspend_mode ? mode : 0; 522362306a36Sopenharmony_ci 522462306a36Sopenharmony_ci return mode; 522562306a36Sopenharmony_ci} 522662306a36Sopenharmony_ci 522762306a36Sopenharmony_cistatic const struct attribute_group regulator_dev_group = { 522862306a36Sopenharmony_ci .attrs = regulator_dev_attrs, 522962306a36Sopenharmony_ci .is_visible = regulator_attr_is_visible, 523062306a36Sopenharmony_ci}; 523162306a36Sopenharmony_ci 523262306a36Sopenharmony_cistatic const struct attribute_group *regulator_dev_groups[] = { 523362306a36Sopenharmony_ci ®ulator_dev_group, 523462306a36Sopenharmony_ci NULL 523562306a36Sopenharmony_ci}; 523662306a36Sopenharmony_ci 523762306a36Sopenharmony_cistatic void regulator_dev_release(struct device *dev) 523862306a36Sopenharmony_ci{ 523962306a36Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 524062306a36Sopenharmony_ci 524162306a36Sopenharmony_ci debugfs_remove_recursive(rdev->debugfs); 524262306a36Sopenharmony_ci kfree(rdev->constraints); 524362306a36Sopenharmony_ci of_node_put(rdev->dev.of_node); 524462306a36Sopenharmony_ci kfree(rdev); 524562306a36Sopenharmony_ci} 524662306a36Sopenharmony_ci 524762306a36Sopenharmony_cistatic void rdev_init_debugfs(struct regulator_dev *rdev) 524862306a36Sopenharmony_ci{ 524962306a36Sopenharmony_ci struct device *parent = rdev->dev.parent; 525062306a36Sopenharmony_ci const char *rname = rdev_get_name(rdev); 525162306a36Sopenharmony_ci char name[NAME_MAX]; 525262306a36Sopenharmony_ci 525362306a36Sopenharmony_ci /* Avoid duplicate debugfs directory names */ 525462306a36Sopenharmony_ci if (parent && rname == rdev->desc->name) { 525562306a36Sopenharmony_ci snprintf(name, sizeof(name), "%s-%s", dev_name(parent), 525662306a36Sopenharmony_ci rname); 525762306a36Sopenharmony_ci rname = name; 525862306a36Sopenharmony_ci } 525962306a36Sopenharmony_ci 526062306a36Sopenharmony_ci rdev->debugfs = debugfs_create_dir(rname, debugfs_root); 526162306a36Sopenharmony_ci if (IS_ERR(rdev->debugfs)) 526262306a36Sopenharmony_ci rdev_dbg(rdev, "Failed to create debugfs directory\n"); 526362306a36Sopenharmony_ci 526462306a36Sopenharmony_ci debugfs_create_u32("use_count", 0444, rdev->debugfs, 526562306a36Sopenharmony_ci &rdev->use_count); 526662306a36Sopenharmony_ci debugfs_create_u32("open_count", 0444, rdev->debugfs, 526762306a36Sopenharmony_ci &rdev->open_count); 526862306a36Sopenharmony_ci debugfs_create_u32("bypass_count", 0444, rdev->debugfs, 526962306a36Sopenharmony_ci &rdev->bypass_count); 527062306a36Sopenharmony_ci} 527162306a36Sopenharmony_ci 527262306a36Sopenharmony_cistatic int regulator_register_resolve_supply(struct device *dev, void *data) 527362306a36Sopenharmony_ci{ 527462306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 527562306a36Sopenharmony_ci 527662306a36Sopenharmony_ci if (regulator_resolve_supply(rdev)) 527762306a36Sopenharmony_ci rdev_dbg(rdev, "unable to resolve supply\n"); 527862306a36Sopenharmony_ci 527962306a36Sopenharmony_ci return 0; 528062306a36Sopenharmony_ci} 528162306a36Sopenharmony_ci 528262306a36Sopenharmony_ciint regulator_coupler_register(struct regulator_coupler *coupler) 528362306a36Sopenharmony_ci{ 528462306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 528562306a36Sopenharmony_ci list_add_tail(&coupler->list, ®ulator_coupler_list); 528662306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 528762306a36Sopenharmony_ci 528862306a36Sopenharmony_ci return 0; 528962306a36Sopenharmony_ci} 529062306a36Sopenharmony_ci 529162306a36Sopenharmony_cistatic struct regulator_coupler * 529262306a36Sopenharmony_ciregulator_find_coupler(struct regulator_dev *rdev) 529362306a36Sopenharmony_ci{ 529462306a36Sopenharmony_ci struct regulator_coupler *coupler; 529562306a36Sopenharmony_ci int err; 529662306a36Sopenharmony_ci 529762306a36Sopenharmony_ci /* 529862306a36Sopenharmony_ci * Note that regulators are appended to the list and the generic 529962306a36Sopenharmony_ci * coupler is registered first, hence it will be attached at last 530062306a36Sopenharmony_ci * if nobody cared. 530162306a36Sopenharmony_ci */ 530262306a36Sopenharmony_ci list_for_each_entry_reverse(coupler, ®ulator_coupler_list, list) { 530362306a36Sopenharmony_ci err = coupler->attach_regulator(coupler, rdev); 530462306a36Sopenharmony_ci if (!err) { 530562306a36Sopenharmony_ci if (!coupler->balance_voltage && 530662306a36Sopenharmony_ci rdev->coupling_desc.n_coupled > 2) 530762306a36Sopenharmony_ci goto err_unsupported; 530862306a36Sopenharmony_ci 530962306a36Sopenharmony_ci return coupler; 531062306a36Sopenharmony_ci } 531162306a36Sopenharmony_ci 531262306a36Sopenharmony_ci if (err < 0) 531362306a36Sopenharmony_ci return ERR_PTR(err); 531462306a36Sopenharmony_ci 531562306a36Sopenharmony_ci if (err == 1) 531662306a36Sopenharmony_ci continue; 531762306a36Sopenharmony_ci 531862306a36Sopenharmony_ci break; 531962306a36Sopenharmony_ci } 532062306a36Sopenharmony_ci 532162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 532262306a36Sopenharmony_ci 532362306a36Sopenharmony_cierr_unsupported: 532462306a36Sopenharmony_ci if (coupler->detach_regulator) 532562306a36Sopenharmony_ci coupler->detach_regulator(coupler, rdev); 532662306a36Sopenharmony_ci 532762306a36Sopenharmony_ci rdev_err(rdev, 532862306a36Sopenharmony_ci "Voltage balancing for multiple regulator couples is unimplemented\n"); 532962306a36Sopenharmony_ci 533062306a36Sopenharmony_ci return ERR_PTR(-EPERM); 533162306a36Sopenharmony_ci} 533262306a36Sopenharmony_ci 533362306a36Sopenharmony_cistatic void regulator_resolve_coupling(struct regulator_dev *rdev) 533462306a36Sopenharmony_ci{ 533562306a36Sopenharmony_ci struct regulator_coupler *coupler = rdev->coupling_desc.coupler; 533662306a36Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 533762306a36Sopenharmony_ci int n_coupled = c_desc->n_coupled; 533862306a36Sopenharmony_ci struct regulator_dev *c_rdev; 533962306a36Sopenharmony_ci int i; 534062306a36Sopenharmony_ci 534162306a36Sopenharmony_ci for (i = 1; i < n_coupled; i++) { 534262306a36Sopenharmony_ci /* already resolved */ 534362306a36Sopenharmony_ci if (c_desc->coupled_rdevs[i]) 534462306a36Sopenharmony_ci continue; 534562306a36Sopenharmony_ci 534662306a36Sopenharmony_ci c_rdev = of_parse_coupled_regulator(rdev, i - 1); 534762306a36Sopenharmony_ci 534862306a36Sopenharmony_ci if (!c_rdev) 534962306a36Sopenharmony_ci continue; 535062306a36Sopenharmony_ci 535162306a36Sopenharmony_ci if (c_rdev->coupling_desc.coupler != coupler) { 535262306a36Sopenharmony_ci rdev_err(rdev, "coupler mismatch with %s\n", 535362306a36Sopenharmony_ci rdev_get_name(c_rdev)); 535462306a36Sopenharmony_ci return; 535562306a36Sopenharmony_ci } 535662306a36Sopenharmony_ci 535762306a36Sopenharmony_ci c_desc->coupled_rdevs[i] = c_rdev; 535862306a36Sopenharmony_ci c_desc->n_resolved++; 535962306a36Sopenharmony_ci 536062306a36Sopenharmony_ci regulator_resolve_coupling(c_rdev); 536162306a36Sopenharmony_ci } 536262306a36Sopenharmony_ci} 536362306a36Sopenharmony_ci 536462306a36Sopenharmony_cistatic void regulator_remove_coupling(struct regulator_dev *rdev) 536562306a36Sopenharmony_ci{ 536662306a36Sopenharmony_ci struct regulator_coupler *coupler = rdev->coupling_desc.coupler; 536762306a36Sopenharmony_ci struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc; 536862306a36Sopenharmony_ci struct regulator_dev *__c_rdev, *c_rdev; 536962306a36Sopenharmony_ci unsigned int __n_coupled, n_coupled; 537062306a36Sopenharmony_ci int i, k; 537162306a36Sopenharmony_ci int err; 537262306a36Sopenharmony_ci 537362306a36Sopenharmony_ci n_coupled = c_desc->n_coupled; 537462306a36Sopenharmony_ci 537562306a36Sopenharmony_ci for (i = 1; i < n_coupled; i++) { 537662306a36Sopenharmony_ci c_rdev = c_desc->coupled_rdevs[i]; 537762306a36Sopenharmony_ci 537862306a36Sopenharmony_ci if (!c_rdev) 537962306a36Sopenharmony_ci continue; 538062306a36Sopenharmony_ci 538162306a36Sopenharmony_ci regulator_lock(c_rdev); 538262306a36Sopenharmony_ci 538362306a36Sopenharmony_ci __c_desc = &c_rdev->coupling_desc; 538462306a36Sopenharmony_ci __n_coupled = __c_desc->n_coupled; 538562306a36Sopenharmony_ci 538662306a36Sopenharmony_ci for (k = 1; k < __n_coupled; k++) { 538762306a36Sopenharmony_ci __c_rdev = __c_desc->coupled_rdevs[k]; 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_ci if (__c_rdev == rdev) { 539062306a36Sopenharmony_ci __c_desc->coupled_rdevs[k] = NULL; 539162306a36Sopenharmony_ci __c_desc->n_resolved--; 539262306a36Sopenharmony_ci break; 539362306a36Sopenharmony_ci } 539462306a36Sopenharmony_ci } 539562306a36Sopenharmony_ci 539662306a36Sopenharmony_ci regulator_unlock(c_rdev); 539762306a36Sopenharmony_ci 539862306a36Sopenharmony_ci c_desc->coupled_rdevs[i] = NULL; 539962306a36Sopenharmony_ci c_desc->n_resolved--; 540062306a36Sopenharmony_ci } 540162306a36Sopenharmony_ci 540262306a36Sopenharmony_ci if (coupler && coupler->detach_regulator) { 540362306a36Sopenharmony_ci err = coupler->detach_regulator(coupler, rdev); 540462306a36Sopenharmony_ci if (err) 540562306a36Sopenharmony_ci rdev_err(rdev, "failed to detach from coupler: %pe\n", 540662306a36Sopenharmony_ci ERR_PTR(err)); 540762306a36Sopenharmony_ci } 540862306a36Sopenharmony_ci 540962306a36Sopenharmony_ci kfree(rdev->coupling_desc.coupled_rdevs); 541062306a36Sopenharmony_ci rdev->coupling_desc.coupled_rdevs = NULL; 541162306a36Sopenharmony_ci} 541262306a36Sopenharmony_ci 541362306a36Sopenharmony_cistatic int regulator_init_coupling(struct regulator_dev *rdev) 541462306a36Sopenharmony_ci{ 541562306a36Sopenharmony_ci struct regulator_dev **coupled; 541662306a36Sopenharmony_ci int err, n_phandles; 541762306a36Sopenharmony_ci 541862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_OF)) 541962306a36Sopenharmony_ci n_phandles = 0; 542062306a36Sopenharmony_ci else 542162306a36Sopenharmony_ci n_phandles = of_get_n_coupled(rdev); 542262306a36Sopenharmony_ci 542362306a36Sopenharmony_ci coupled = kcalloc(n_phandles + 1, sizeof(*coupled), GFP_KERNEL); 542462306a36Sopenharmony_ci if (!coupled) 542562306a36Sopenharmony_ci return -ENOMEM; 542662306a36Sopenharmony_ci 542762306a36Sopenharmony_ci rdev->coupling_desc.coupled_rdevs = coupled; 542862306a36Sopenharmony_ci 542962306a36Sopenharmony_ci /* 543062306a36Sopenharmony_ci * Every regulator should always have coupling descriptor filled with 543162306a36Sopenharmony_ci * at least pointer to itself. 543262306a36Sopenharmony_ci */ 543362306a36Sopenharmony_ci rdev->coupling_desc.coupled_rdevs[0] = rdev; 543462306a36Sopenharmony_ci rdev->coupling_desc.n_coupled = n_phandles + 1; 543562306a36Sopenharmony_ci rdev->coupling_desc.n_resolved++; 543662306a36Sopenharmony_ci 543762306a36Sopenharmony_ci /* regulator isn't coupled */ 543862306a36Sopenharmony_ci if (n_phandles == 0) 543962306a36Sopenharmony_ci return 0; 544062306a36Sopenharmony_ci 544162306a36Sopenharmony_ci if (!of_check_coupling_data(rdev)) 544262306a36Sopenharmony_ci return -EPERM; 544362306a36Sopenharmony_ci 544462306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 544562306a36Sopenharmony_ci rdev->coupling_desc.coupler = regulator_find_coupler(rdev); 544662306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 544762306a36Sopenharmony_ci 544862306a36Sopenharmony_ci if (IS_ERR(rdev->coupling_desc.coupler)) { 544962306a36Sopenharmony_ci err = PTR_ERR(rdev->coupling_desc.coupler); 545062306a36Sopenharmony_ci rdev_err(rdev, "failed to get coupler: %pe\n", ERR_PTR(err)); 545162306a36Sopenharmony_ci return err; 545262306a36Sopenharmony_ci } 545362306a36Sopenharmony_ci 545462306a36Sopenharmony_ci return 0; 545562306a36Sopenharmony_ci} 545662306a36Sopenharmony_ci 545762306a36Sopenharmony_cistatic int generic_coupler_attach(struct regulator_coupler *coupler, 545862306a36Sopenharmony_ci struct regulator_dev *rdev) 545962306a36Sopenharmony_ci{ 546062306a36Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 2) { 546162306a36Sopenharmony_ci rdev_err(rdev, 546262306a36Sopenharmony_ci "Voltage balancing for multiple regulator couples is unimplemented\n"); 546362306a36Sopenharmony_ci return -EPERM; 546462306a36Sopenharmony_ci } 546562306a36Sopenharmony_ci 546662306a36Sopenharmony_ci if (!rdev->constraints->always_on) { 546762306a36Sopenharmony_ci rdev_err(rdev, 546862306a36Sopenharmony_ci "Coupling of a non always-on regulator is unimplemented\n"); 546962306a36Sopenharmony_ci return -ENOTSUPP; 547062306a36Sopenharmony_ci } 547162306a36Sopenharmony_ci 547262306a36Sopenharmony_ci return 0; 547362306a36Sopenharmony_ci} 547462306a36Sopenharmony_ci 547562306a36Sopenharmony_cistatic struct regulator_coupler generic_regulator_coupler = { 547662306a36Sopenharmony_ci .attach_regulator = generic_coupler_attach, 547762306a36Sopenharmony_ci}; 547862306a36Sopenharmony_ci 547962306a36Sopenharmony_ci/** 548062306a36Sopenharmony_ci * regulator_register - register regulator 548162306a36Sopenharmony_ci * @dev: the device that drive the regulator 548262306a36Sopenharmony_ci * @regulator_desc: regulator to register 548362306a36Sopenharmony_ci * @cfg: runtime configuration for regulator 548462306a36Sopenharmony_ci * 548562306a36Sopenharmony_ci * Called by regulator drivers to register a regulator. 548662306a36Sopenharmony_ci * Returns a valid pointer to struct regulator_dev on success 548762306a36Sopenharmony_ci * or an ERR_PTR() on error. 548862306a36Sopenharmony_ci */ 548962306a36Sopenharmony_cistruct regulator_dev * 549062306a36Sopenharmony_ciregulator_register(struct device *dev, 549162306a36Sopenharmony_ci const struct regulator_desc *regulator_desc, 549262306a36Sopenharmony_ci const struct regulator_config *cfg) 549362306a36Sopenharmony_ci{ 549462306a36Sopenharmony_ci const struct regulator_init_data *init_data; 549562306a36Sopenharmony_ci struct regulator_config *config = NULL; 549662306a36Sopenharmony_ci static atomic_t regulator_no = ATOMIC_INIT(-1); 549762306a36Sopenharmony_ci struct regulator_dev *rdev; 549862306a36Sopenharmony_ci bool dangling_cfg_gpiod = false; 549962306a36Sopenharmony_ci bool dangling_of_gpiod = false; 550062306a36Sopenharmony_ci int ret, i; 550162306a36Sopenharmony_ci bool resolved_early = false; 550262306a36Sopenharmony_ci 550362306a36Sopenharmony_ci if (cfg == NULL) 550462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 550562306a36Sopenharmony_ci if (cfg->ena_gpiod) 550662306a36Sopenharmony_ci dangling_cfg_gpiod = true; 550762306a36Sopenharmony_ci if (regulator_desc == NULL) { 550862306a36Sopenharmony_ci ret = -EINVAL; 550962306a36Sopenharmony_ci goto rinse; 551062306a36Sopenharmony_ci } 551162306a36Sopenharmony_ci 551262306a36Sopenharmony_ci WARN_ON(!dev || !cfg->dev); 551362306a36Sopenharmony_ci 551462306a36Sopenharmony_ci if (regulator_desc->name == NULL || regulator_desc->ops == NULL) { 551562306a36Sopenharmony_ci ret = -EINVAL; 551662306a36Sopenharmony_ci goto rinse; 551762306a36Sopenharmony_ci } 551862306a36Sopenharmony_ci 551962306a36Sopenharmony_ci if (regulator_desc->type != REGULATOR_VOLTAGE && 552062306a36Sopenharmony_ci regulator_desc->type != REGULATOR_CURRENT) { 552162306a36Sopenharmony_ci ret = -EINVAL; 552262306a36Sopenharmony_ci goto rinse; 552362306a36Sopenharmony_ci } 552462306a36Sopenharmony_ci 552562306a36Sopenharmony_ci /* Only one of each should be implemented */ 552662306a36Sopenharmony_ci WARN_ON(regulator_desc->ops->get_voltage && 552762306a36Sopenharmony_ci regulator_desc->ops->get_voltage_sel); 552862306a36Sopenharmony_ci WARN_ON(regulator_desc->ops->set_voltage && 552962306a36Sopenharmony_ci regulator_desc->ops->set_voltage_sel); 553062306a36Sopenharmony_ci 553162306a36Sopenharmony_ci /* If we're using selectors we must implement list_voltage. */ 553262306a36Sopenharmony_ci if (regulator_desc->ops->get_voltage_sel && 553362306a36Sopenharmony_ci !regulator_desc->ops->list_voltage) { 553462306a36Sopenharmony_ci ret = -EINVAL; 553562306a36Sopenharmony_ci goto rinse; 553662306a36Sopenharmony_ci } 553762306a36Sopenharmony_ci if (regulator_desc->ops->set_voltage_sel && 553862306a36Sopenharmony_ci !regulator_desc->ops->list_voltage) { 553962306a36Sopenharmony_ci ret = -EINVAL; 554062306a36Sopenharmony_ci goto rinse; 554162306a36Sopenharmony_ci } 554262306a36Sopenharmony_ci 554362306a36Sopenharmony_ci rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); 554462306a36Sopenharmony_ci if (rdev == NULL) { 554562306a36Sopenharmony_ci ret = -ENOMEM; 554662306a36Sopenharmony_ci goto rinse; 554762306a36Sopenharmony_ci } 554862306a36Sopenharmony_ci device_initialize(&rdev->dev); 554962306a36Sopenharmony_ci dev_set_drvdata(&rdev->dev, rdev); 555062306a36Sopenharmony_ci rdev->dev.class = ®ulator_class; 555162306a36Sopenharmony_ci spin_lock_init(&rdev->err_lock); 555262306a36Sopenharmony_ci 555362306a36Sopenharmony_ci /* 555462306a36Sopenharmony_ci * Duplicate the config so the driver could override it after 555562306a36Sopenharmony_ci * parsing init data. 555662306a36Sopenharmony_ci */ 555762306a36Sopenharmony_ci config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL); 555862306a36Sopenharmony_ci if (config == NULL) { 555962306a36Sopenharmony_ci ret = -ENOMEM; 556062306a36Sopenharmony_ci goto clean; 556162306a36Sopenharmony_ci } 556262306a36Sopenharmony_ci 556362306a36Sopenharmony_ci init_data = regulator_of_get_init_data(dev, regulator_desc, config, 556462306a36Sopenharmony_ci &rdev->dev.of_node); 556562306a36Sopenharmony_ci 556662306a36Sopenharmony_ci /* 556762306a36Sopenharmony_ci * Sometimes not all resources are probed already so we need to take 556862306a36Sopenharmony_ci * that into account. This happens most the time if the ena_gpiod comes 556962306a36Sopenharmony_ci * from a gpio extender or something else. 557062306a36Sopenharmony_ci */ 557162306a36Sopenharmony_ci if (PTR_ERR(init_data) == -EPROBE_DEFER) { 557262306a36Sopenharmony_ci ret = -EPROBE_DEFER; 557362306a36Sopenharmony_ci goto clean; 557462306a36Sopenharmony_ci } 557562306a36Sopenharmony_ci 557662306a36Sopenharmony_ci /* 557762306a36Sopenharmony_ci * We need to keep track of any GPIO descriptor coming from the 557862306a36Sopenharmony_ci * device tree until we have handled it over to the core. If the 557962306a36Sopenharmony_ci * config that was passed in to this function DOES NOT contain 558062306a36Sopenharmony_ci * a descriptor, and the config after this call DOES contain 558162306a36Sopenharmony_ci * a descriptor, we definitely got one from parsing the device 558262306a36Sopenharmony_ci * tree. 558362306a36Sopenharmony_ci */ 558462306a36Sopenharmony_ci if (!cfg->ena_gpiod && config->ena_gpiod) 558562306a36Sopenharmony_ci dangling_of_gpiod = true; 558662306a36Sopenharmony_ci if (!init_data) { 558762306a36Sopenharmony_ci init_data = config->init_data; 558862306a36Sopenharmony_ci rdev->dev.of_node = of_node_get(config->of_node); 558962306a36Sopenharmony_ci } 559062306a36Sopenharmony_ci 559162306a36Sopenharmony_ci ww_mutex_init(&rdev->mutex, ®ulator_ww_class); 559262306a36Sopenharmony_ci rdev->reg_data = config->driver_data; 559362306a36Sopenharmony_ci rdev->owner = regulator_desc->owner; 559462306a36Sopenharmony_ci rdev->desc = regulator_desc; 559562306a36Sopenharmony_ci if (config->regmap) 559662306a36Sopenharmony_ci rdev->regmap = config->regmap; 559762306a36Sopenharmony_ci else if (dev_get_regmap(dev, NULL)) 559862306a36Sopenharmony_ci rdev->regmap = dev_get_regmap(dev, NULL); 559962306a36Sopenharmony_ci else if (dev->parent) 560062306a36Sopenharmony_ci rdev->regmap = dev_get_regmap(dev->parent, NULL); 560162306a36Sopenharmony_ci INIT_LIST_HEAD(&rdev->consumer_list); 560262306a36Sopenharmony_ci INIT_LIST_HEAD(&rdev->list); 560362306a36Sopenharmony_ci BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); 560462306a36Sopenharmony_ci INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); 560562306a36Sopenharmony_ci 560662306a36Sopenharmony_ci if (init_data && init_data->supply_regulator) 560762306a36Sopenharmony_ci rdev->supply_name = init_data->supply_regulator; 560862306a36Sopenharmony_ci else if (regulator_desc->supply_name) 560962306a36Sopenharmony_ci rdev->supply_name = regulator_desc->supply_name; 561062306a36Sopenharmony_ci 561162306a36Sopenharmony_ci /* register with sysfs */ 561262306a36Sopenharmony_ci rdev->dev.parent = config->dev; 561362306a36Sopenharmony_ci dev_set_name(&rdev->dev, "regulator.%lu", 561462306a36Sopenharmony_ci (unsigned long) atomic_inc_return(®ulator_no)); 561562306a36Sopenharmony_ci 561662306a36Sopenharmony_ci /* set regulator constraints */ 561762306a36Sopenharmony_ci if (init_data) 561862306a36Sopenharmony_ci rdev->constraints = kmemdup(&init_data->constraints, 561962306a36Sopenharmony_ci sizeof(*rdev->constraints), 562062306a36Sopenharmony_ci GFP_KERNEL); 562162306a36Sopenharmony_ci else 562262306a36Sopenharmony_ci rdev->constraints = kzalloc(sizeof(*rdev->constraints), 562362306a36Sopenharmony_ci GFP_KERNEL); 562462306a36Sopenharmony_ci if (!rdev->constraints) { 562562306a36Sopenharmony_ci ret = -ENOMEM; 562662306a36Sopenharmony_ci goto wash; 562762306a36Sopenharmony_ci } 562862306a36Sopenharmony_ci 562962306a36Sopenharmony_ci if ((rdev->supply_name && !rdev->supply) && 563062306a36Sopenharmony_ci (rdev->constraints->always_on || 563162306a36Sopenharmony_ci rdev->constraints->boot_on)) { 563262306a36Sopenharmony_ci ret = regulator_resolve_supply(rdev); 563362306a36Sopenharmony_ci if (ret) 563462306a36Sopenharmony_ci rdev_dbg(rdev, "unable to resolve supply early: %pe\n", 563562306a36Sopenharmony_ci ERR_PTR(ret)); 563662306a36Sopenharmony_ci 563762306a36Sopenharmony_ci resolved_early = true; 563862306a36Sopenharmony_ci } 563962306a36Sopenharmony_ci 564062306a36Sopenharmony_ci /* perform any regulator specific init */ 564162306a36Sopenharmony_ci if (init_data && init_data->regulator_init) { 564262306a36Sopenharmony_ci ret = init_data->regulator_init(rdev->reg_data); 564362306a36Sopenharmony_ci if (ret < 0) 564462306a36Sopenharmony_ci goto wash; 564562306a36Sopenharmony_ci } 564662306a36Sopenharmony_ci 564762306a36Sopenharmony_ci if (config->ena_gpiod) { 564862306a36Sopenharmony_ci ret = regulator_ena_gpio_request(rdev, config); 564962306a36Sopenharmony_ci if (ret != 0) { 565062306a36Sopenharmony_ci rdev_err(rdev, "Failed to request enable GPIO: %pe\n", 565162306a36Sopenharmony_ci ERR_PTR(ret)); 565262306a36Sopenharmony_ci goto wash; 565362306a36Sopenharmony_ci } 565462306a36Sopenharmony_ci /* The regulator core took over the GPIO descriptor */ 565562306a36Sopenharmony_ci dangling_cfg_gpiod = false; 565662306a36Sopenharmony_ci dangling_of_gpiod = false; 565762306a36Sopenharmony_ci } 565862306a36Sopenharmony_ci 565962306a36Sopenharmony_ci ret = set_machine_constraints(rdev); 566062306a36Sopenharmony_ci if (ret == -EPROBE_DEFER && !resolved_early) { 566162306a36Sopenharmony_ci /* Regulator might be in bypass mode and so needs its supply 566262306a36Sopenharmony_ci * to set the constraints 566362306a36Sopenharmony_ci */ 566462306a36Sopenharmony_ci /* FIXME: this currently triggers a chicken-and-egg problem 566562306a36Sopenharmony_ci * when creating -SUPPLY symlink in sysfs to a regulator 566662306a36Sopenharmony_ci * that is just being created 566762306a36Sopenharmony_ci */ 566862306a36Sopenharmony_ci rdev_dbg(rdev, "will resolve supply early: %s\n", 566962306a36Sopenharmony_ci rdev->supply_name); 567062306a36Sopenharmony_ci ret = regulator_resolve_supply(rdev); 567162306a36Sopenharmony_ci if (!ret) 567262306a36Sopenharmony_ci ret = set_machine_constraints(rdev); 567362306a36Sopenharmony_ci else 567462306a36Sopenharmony_ci rdev_dbg(rdev, "unable to resolve supply early: %pe\n", 567562306a36Sopenharmony_ci ERR_PTR(ret)); 567662306a36Sopenharmony_ci } 567762306a36Sopenharmony_ci if (ret < 0) 567862306a36Sopenharmony_ci goto wash; 567962306a36Sopenharmony_ci 568062306a36Sopenharmony_ci ret = regulator_init_coupling(rdev); 568162306a36Sopenharmony_ci if (ret < 0) 568262306a36Sopenharmony_ci goto wash; 568362306a36Sopenharmony_ci 568462306a36Sopenharmony_ci /* add consumers devices */ 568562306a36Sopenharmony_ci if (init_data) { 568662306a36Sopenharmony_ci for (i = 0; i < init_data->num_consumer_supplies; i++) { 568762306a36Sopenharmony_ci ret = set_consumer_device_supply(rdev, 568862306a36Sopenharmony_ci init_data->consumer_supplies[i].dev_name, 568962306a36Sopenharmony_ci init_data->consumer_supplies[i].supply); 569062306a36Sopenharmony_ci if (ret < 0) { 569162306a36Sopenharmony_ci dev_err(dev, "Failed to set supply %s\n", 569262306a36Sopenharmony_ci init_data->consumer_supplies[i].supply); 569362306a36Sopenharmony_ci goto unset_supplies; 569462306a36Sopenharmony_ci } 569562306a36Sopenharmony_ci } 569662306a36Sopenharmony_ci } 569762306a36Sopenharmony_ci 569862306a36Sopenharmony_ci if (!rdev->desc->ops->get_voltage && 569962306a36Sopenharmony_ci !rdev->desc->ops->list_voltage && 570062306a36Sopenharmony_ci !rdev->desc->fixed_uV) 570162306a36Sopenharmony_ci rdev->is_switch = true; 570262306a36Sopenharmony_ci 570362306a36Sopenharmony_ci ret = device_add(&rdev->dev); 570462306a36Sopenharmony_ci if (ret != 0) 570562306a36Sopenharmony_ci goto unset_supplies; 570662306a36Sopenharmony_ci 570762306a36Sopenharmony_ci rdev_init_debugfs(rdev); 570862306a36Sopenharmony_ci 570962306a36Sopenharmony_ci /* try to resolve regulators coupling since a new one was registered */ 571062306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 571162306a36Sopenharmony_ci regulator_resolve_coupling(rdev); 571262306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 571362306a36Sopenharmony_ci 571462306a36Sopenharmony_ci /* try to resolve regulators supply since a new one was registered */ 571562306a36Sopenharmony_ci class_for_each_device(®ulator_class, NULL, NULL, 571662306a36Sopenharmony_ci regulator_register_resolve_supply); 571762306a36Sopenharmony_ci kfree(config); 571862306a36Sopenharmony_ci return rdev; 571962306a36Sopenharmony_ci 572062306a36Sopenharmony_ciunset_supplies: 572162306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 572262306a36Sopenharmony_ci unset_regulator_supplies(rdev); 572362306a36Sopenharmony_ci regulator_remove_coupling(rdev); 572462306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 572562306a36Sopenharmony_ciwash: 572662306a36Sopenharmony_ci regulator_put(rdev->supply); 572762306a36Sopenharmony_ci kfree(rdev->coupling_desc.coupled_rdevs); 572862306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 572962306a36Sopenharmony_ci regulator_ena_gpio_free(rdev); 573062306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 573162306a36Sopenharmony_ciclean: 573262306a36Sopenharmony_ci if (dangling_of_gpiod) 573362306a36Sopenharmony_ci gpiod_put(config->ena_gpiod); 573462306a36Sopenharmony_ci kfree(config); 573562306a36Sopenharmony_ci put_device(&rdev->dev); 573662306a36Sopenharmony_cirinse: 573762306a36Sopenharmony_ci if (dangling_cfg_gpiod) 573862306a36Sopenharmony_ci gpiod_put(cfg->ena_gpiod); 573962306a36Sopenharmony_ci return ERR_PTR(ret); 574062306a36Sopenharmony_ci} 574162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_register); 574262306a36Sopenharmony_ci 574362306a36Sopenharmony_ci/** 574462306a36Sopenharmony_ci * regulator_unregister - unregister regulator 574562306a36Sopenharmony_ci * @rdev: regulator to unregister 574662306a36Sopenharmony_ci * 574762306a36Sopenharmony_ci * Called by regulator drivers to unregister a regulator. 574862306a36Sopenharmony_ci */ 574962306a36Sopenharmony_civoid regulator_unregister(struct regulator_dev *rdev) 575062306a36Sopenharmony_ci{ 575162306a36Sopenharmony_ci if (rdev == NULL) 575262306a36Sopenharmony_ci return; 575362306a36Sopenharmony_ci 575462306a36Sopenharmony_ci if (rdev->supply) { 575562306a36Sopenharmony_ci while (rdev->use_count--) 575662306a36Sopenharmony_ci regulator_disable(rdev->supply); 575762306a36Sopenharmony_ci regulator_put(rdev->supply); 575862306a36Sopenharmony_ci } 575962306a36Sopenharmony_ci 576062306a36Sopenharmony_ci flush_work(&rdev->disable_work.work); 576162306a36Sopenharmony_ci 576262306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 576362306a36Sopenharmony_ci 576462306a36Sopenharmony_ci WARN_ON(rdev->open_count); 576562306a36Sopenharmony_ci regulator_remove_coupling(rdev); 576662306a36Sopenharmony_ci unset_regulator_supplies(rdev); 576762306a36Sopenharmony_ci list_del(&rdev->list); 576862306a36Sopenharmony_ci regulator_ena_gpio_free(rdev); 576962306a36Sopenharmony_ci device_unregister(&rdev->dev); 577062306a36Sopenharmony_ci 577162306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 577262306a36Sopenharmony_ci} 577362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_unregister); 577462306a36Sopenharmony_ci 577562306a36Sopenharmony_ci#ifdef CONFIG_SUSPEND 577662306a36Sopenharmony_ci/** 577762306a36Sopenharmony_ci * regulator_suspend - prepare regulators for system wide suspend 577862306a36Sopenharmony_ci * @dev: ``&struct device`` pointer that is passed to _regulator_suspend() 577962306a36Sopenharmony_ci * 578062306a36Sopenharmony_ci * Configure each regulator with it's suspend operating parameters for state. 578162306a36Sopenharmony_ci */ 578262306a36Sopenharmony_cistatic int regulator_suspend(struct device *dev) 578362306a36Sopenharmony_ci{ 578462306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 578562306a36Sopenharmony_ci suspend_state_t state = pm_suspend_target_state; 578662306a36Sopenharmony_ci int ret; 578762306a36Sopenharmony_ci const struct regulator_state *rstate; 578862306a36Sopenharmony_ci 578962306a36Sopenharmony_ci rstate = regulator_get_suspend_state_check(rdev, state); 579062306a36Sopenharmony_ci if (!rstate) 579162306a36Sopenharmony_ci return 0; 579262306a36Sopenharmony_ci 579362306a36Sopenharmony_ci regulator_lock(rdev); 579462306a36Sopenharmony_ci ret = __suspend_set_state(rdev, rstate); 579562306a36Sopenharmony_ci regulator_unlock(rdev); 579662306a36Sopenharmony_ci 579762306a36Sopenharmony_ci return ret; 579862306a36Sopenharmony_ci} 579962306a36Sopenharmony_ci 580062306a36Sopenharmony_cistatic int regulator_resume(struct device *dev) 580162306a36Sopenharmony_ci{ 580262306a36Sopenharmony_ci suspend_state_t state = pm_suspend_target_state; 580362306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 580462306a36Sopenharmony_ci struct regulator_state *rstate; 580562306a36Sopenharmony_ci int ret = 0; 580662306a36Sopenharmony_ci 580762306a36Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 580862306a36Sopenharmony_ci if (rstate == NULL) 580962306a36Sopenharmony_ci return 0; 581062306a36Sopenharmony_ci 581162306a36Sopenharmony_ci /* Avoid grabbing the lock if we don't need to */ 581262306a36Sopenharmony_ci if (!rdev->desc->ops->resume) 581362306a36Sopenharmony_ci return 0; 581462306a36Sopenharmony_ci 581562306a36Sopenharmony_ci regulator_lock(rdev); 581662306a36Sopenharmony_ci 581762306a36Sopenharmony_ci if (rstate->enabled == ENABLE_IN_SUSPEND || 581862306a36Sopenharmony_ci rstate->enabled == DISABLE_IN_SUSPEND) 581962306a36Sopenharmony_ci ret = rdev->desc->ops->resume(rdev); 582062306a36Sopenharmony_ci 582162306a36Sopenharmony_ci regulator_unlock(rdev); 582262306a36Sopenharmony_ci 582362306a36Sopenharmony_ci return ret; 582462306a36Sopenharmony_ci} 582562306a36Sopenharmony_ci#else /* !CONFIG_SUSPEND */ 582662306a36Sopenharmony_ci 582762306a36Sopenharmony_ci#define regulator_suspend NULL 582862306a36Sopenharmony_ci#define regulator_resume NULL 582962306a36Sopenharmony_ci 583062306a36Sopenharmony_ci#endif /* !CONFIG_SUSPEND */ 583162306a36Sopenharmony_ci 583262306a36Sopenharmony_ci#ifdef CONFIG_PM 583362306a36Sopenharmony_cistatic const struct dev_pm_ops __maybe_unused regulator_pm_ops = { 583462306a36Sopenharmony_ci .suspend = regulator_suspend, 583562306a36Sopenharmony_ci .resume = regulator_resume, 583662306a36Sopenharmony_ci}; 583762306a36Sopenharmony_ci#endif 583862306a36Sopenharmony_ci 583962306a36Sopenharmony_cistruct class regulator_class = { 584062306a36Sopenharmony_ci .name = "regulator", 584162306a36Sopenharmony_ci .dev_release = regulator_dev_release, 584262306a36Sopenharmony_ci .dev_groups = regulator_dev_groups, 584362306a36Sopenharmony_ci#ifdef CONFIG_PM 584462306a36Sopenharmony_ci .pm = ®ulator_pm_ops, 584562306a36Sopenharmony_ci#endif 584662306a36Sopenharmony_ci}; 584762306a36Sopenharmony_ci/** 584862306a36Sopenharmony_ci * regulator_has_full_constraints - the system has fully specified constraints 584962306a36Sopenharmony_ci * 585062306a36Sopenharmony_ci * Calling this function will cause the regulator API to disable all 585162306a36Sopenharmony_ci * regulators which have a zero use count and don't have an always_on 585262306a36Sopenharmony_ci * constraint in a late_initcall. 585362306a36Sopenharmony_ci * 585462306a36Sopenharmony_ci * The intention is that this will become the default behaviour in a 585562306a36Sopenharmony_ci * future kernel release so users are encouraged to use this facility 585662306a36Sopenharmony_ci * now. 585762306a36Sopenharmony_ci */ 585862306a36Sopenharmony_civoid regulator_has_full_constraints(void) 585962306a36Sopenharmony_ci{ 586062306a36Sopenharmony_ci has_full_constraints = 1; 586162306a36Sopenharmony_ci} 586262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_has_full_constraints); 586362306a36Sopenharmony_ci 586462306a36Sopenharmony_ci/** 586562306a36Sopenharmony_ci * rdev_get_drvdata - get rdev regulator driver data 586662306a36Sopenharmony_ci * @rdev: regulator 586762306a36Sopenharmony_ci * 586862306a36Sopenharmony_ci * Get rdev regulator driver private data. This call can be used in the 586962306a36Sopenharmony_ci * regulator driver context. 587062306a36Sopenharmony_ci */ 587162306a36Sopenharmony_civoid *rdev_get_drvdata(struct regulator_dev *rdev) 587262306a36Sopenharmony_ci{ 587362306a36Sopenharmony_ci return rdev->reg_data; 587462306a36Sopenharmony_ci} 587562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_drvdata); 587662306a36Sopenharmony_ci 587762306a36Sopenharmony_ci/** 587862306a36Sopenharmony_ci * regulator_get_drvdata - get regulator driver data 587962306a36Sopenharmony_ci * @regulator: regulator 588062306a36Sopenharmony_ci * 588162306a36Sopenharmony_ci * Get regulator driver private data. This call can be used in the consumer 588262306a36Sopenharmony_ci * driver context when non API regulator specific functions need to be called. 588362306a36Sopenharmony_ci */ 588462306a36Sopenharmony_civoid *regulator_get_drvdata(struct regulator *regulator) 588562306a36Sopenharmony_ci{ 588662306a36Sopenharmony_ci return regulator->rdev->reg_data; 588762306a36Sopenharmony_ci} 588862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_drvdata); 588962306a36Sopenharmony_ci 589062306a36Sopenharmony_ci/** 589162306a36Sopenharmony_ci * regulator_set_drvdata - set regulator driver data 589262306a36Sopenharmony_ci * @regulator: regulator 589362306a36Sopenharmony_ci * @data: data 589462306a36Sopenharmony_ci */ 589562306a36Sopenharmony_civoid regulator_set_drvdata(struct regulator *regulator, void *data) 589662306a36Sopenharmony_ci{ 589762306a36Sopenharmony_ci regulator->rdev->reg_data = data; 589862306a36Sopenharmony_ci} 589962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_drvdata); 590062306a36Sopenharmony_ci 590162306a36Sopenharmony_ci/** 590262306a36Sopenharmony_ci * rdev_get_id - get regulator ID 590362306a36Sopenharmony_ci * @rdev: regulator 590462306a36Sopenharmony_ci */ 590562306a36Sopenharmony_ciint rdev_get_id(struct regulator_dev *rdev) 590662306a36Sopenharmony_ci{ 590762306a36Sopenharmony_ci return rdev->desc->id; 590862306a36Sopenharmony_ci} 590962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_id); 591062306a36Sopenharmony_ci 591162306a36Sopenharmony_cistruct device *rdev_get_dev(struct regulator_dev *rdev) 591262306a36Sopenharmony_ci{ 591362306a36Sopenharmony_ci return &rdev->dev; 591462306a36Sopenharmony_ci} 591562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_dev); 591662306a36Sopenharmony_ci 591762306a36Sopenharmony_cistruct regmap *rdev_get_regmap(struct regulator_dev *rdev) 591862306a36Sopenharmony_ci{ 591962306a36Sopenharmony_ci return rdev->regmap; 592062306a36Sopenharmony_ci} 592162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_regmap); 592262306a36Sopenharmony_ci 592362306a36Sopenharmony_civoid *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) 592462306a36Sopenharmony_ci{ 592562306a36Sopenharmony_ci return reg_init_data->driver_data; 592662306a36Sopenharmony_ci} 592762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_init_drvdata); 592862306a36Sopenharmony_ci 592962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 593062306a36Sopenharmony_cistatic int supply_map_show(struct seq_file *sf, void *data) 593162306a36Sopenharmony_ci{ 593262306a36Sopenharmony_ci struct regulator_map *map; 593362306a36Sopenharmony_ci 593462306a36Sopenharmony_ci list_for_each_entry(map, ®ulator_map_list, list) { 593562306a36Sopenharmony_ci seq_printf(sf, "%s -> %s.%s\n", 593662306a36Sopenharmony_ci rdev_get_name(map->regulator), map->dev_name, 593762306a36Sopenharmony_ci map->supply); 593862306a36Sopenharmony_ci } 593962306a36Sopenharmony_ci 594062306a36Sopenharmony_ci return 0; 594162306a36Sopenharmony_ci} 594262306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(supply_map); 594362306a36Sopenharmony_ci 594462306a36Sopenharmony_cistruct summary_data { 594562306a36Sopenharmony_ci struct seq_file *s; 594662306a36Sopenharmony_ci struct regulator_dev *parent; 594762306a36Sopenharmony_ci int level; 594862306a36Sopenharmony_ci}; 594962306a36Sopenharmony_ci 595062306a36Sopenharmony_cistatic void regulator_summary_show_subtree(struct seq_file *s, 595162306a36Sopenharmony_ci struct regulator_dev *rdev, 595262306a36Sopenharmony_ci int level); 595362306a36Sopenharmony_ci 595462306a36Sopenharmony_cistatic int regulator_summary_show_children(struct device *dev, void *data) 595562306a36Sopenharmony_ci{ 595662306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 595762306a36Sopenharmony_ci struct summary_data *summary_data = data; 595862306a36Sopenharmony_ci 595962306a36Sopenharmony_ci if (rdev->supply && rdev->supply->rdev == summary_data->parent) 596062306a36Sopenharmony_ci regulator_summary_show_subtree(summary_data->s, rdev, 596162306a36Sopenharmony_ci summary_data->level + 1); 596262306a36Sopenharmony_ci 596362306a36Sopenharmony_ci return 0; 596462306a36Sopenharmony_ci} 596562306a36Sopenharmony_ci 596662306a36Sopenharmony_cistatic void regulator_summary_show_subtree(struct seq_file *s, 596762306a36Sopenharmony_ci struct regulator_dev *rdev, 596862306a36Sopenharmony_ci int level) 596962306a36Sopenharmony_ci{ 597062306a36Sopenharmony_ci struct regulation_constraints *c; 597162306a36Sopenharmony_ci struct regulator *consumer; 597262306a36Sopenharmony_ci struct summary_data summary_data; 597362306a36Sopenharmony_ci unsigned int opmode; 597462306a36Sopenharmony_ci 597562306a36Sopenharmony_ci if (!rdev) 597662306a36Sopenharmony_ci return; 597762306a36Sopenharmony_ci 597862306a36Sopenharmony_ci opmode = _regulator_get_mode_unlocked(rdev); 597962306a36Sopenharmony_ci seq_printf(s, "%*s%-*s %3d %4d %6d %7s ", 598062306a36Sopenharmony_ci level * 3 + 1, "", 598162306a36Sopenharmony_ci 30 - level * 3, rdev_get_name(rdev), 598262306a36Sopenharmony_ci rdev->use_count, rdev->open_count, rdev->bypass_count, 598362306a36Sopenharmony_ci regulator_opmode_to_str(opmode)); 598462306a36Sopenharmony_ci 598562306a36Sopenharmony_ci seq_printf(s, "%5dmV ", regulator_get_voltage_rdev(rdev) / 1000); 598662306a36Sopenharmony_ci seq_printf(s, "%5dmA ", 598762306a36Sopenharmony_ci _regulator_get_current_limit_unlocked(rdev) / 1000); 598862306a36Sopenharmony_ci 598962306a36Sopenharmony_ci c = rdev->constraints; 599062306a36Sopenharmony_ci if (c) { 599162306a36Sopenharmony_ci switch (rdev->desc->type) { 599262306a36Sopenharmony_ci case REGULATOR_VOLTAGE: 599362306a36Sopenharmony_ci seq_printf(s, "%5dmV %5dmV ", 599462306a36Sopenharmony_ci c->min_uV / 1000, c->max_uV / 1000); 599562306a36Sopenharmony_ci break; 599662306a36Sopenharmony_ci case REGULATOR_CURRENT: 599762306a36Sopenharmony_ci seq_printf(s, "%5dmA %5dmA ", 599862306a36Sopenharmony_ci c->min_uA / 1000, c->max_uA / 1000); 599962306a36Sopenharmony_ci break; 600062306a36Sopenharmony_ci } 600162306a36Sopenharmony_ci } 600262306a36Sopenharmony_ci 600362306a36Sopenharmony_ci seq_puts(s, "\n"); 600462306a36Sopenharmony_ci 600562306a36Sopenharmony_ci list_for_each_entry(consumer, &rdev->consumer_list, list) { 600662306a36Sopenharmony_ci if (consumer->dev && consumer->dev->class == ®ulator_class) 600762306a36Sopenharmony_ci continue; 600862306a36Sopenharmony_ci 600962306a36Sopenharmony_ci seq_printf(s, "%*s%-*s ", 601062306a36Sopenharmony_ci (level + 1) * 3 + 1, "", 601162306a36Sopenharmony_ci 30 - (level + 1) * 3, 601262306a36Sopenharmony_ci consumer->supply_name ? consumer->supply_name : 601362306a36Sopenharmony_ci consumer->dev ? dev_name(consumer->dev) : "deviceless"); 601462306a36Sopenharmony_ci 601562306a36Sopenharmony_ci switch (rdev->desc->type) { 601662306a36Sopenharmony_ci case REGULATOR_VOLTAGE: 601762306a36Sopenharmony_ci seq_printf(s, "%3d %33dmA%c%5dmV %5dmV", 601862306a36Sopenharmony_ci consumer->enable_count, 601962306a36Sopenharmony_ci consumer->uA_load / 1000, 602062306a36Sopenharmony_ci consumer->uA_load && !consumer->enable_count ? 602162306a36Sopenharmony_ci '*' : ' ', 602262306a36Sopenharmony_ci consumer->voltage[PM_SUSPEND_ON].min_uV / 1000, 602362306a36Sopenharmony_ci consumer->voltage[PM_SUSPEND_ON].max_uV / 1000); 602462306a36Sopenharmony_ci break; 602562306a36Sopenharmony_ci case REGULATOR_CURRENT: 602662306a36Sopenharmony_ci break; 602762306a36Sopenharmony_ci } 602862306a36Sopenharmony_ci 602962306a36Sopenharmony_ci seq_puts(s, "\n"); 603062306a36Sopenharmony_ci } 603162306a36Sopenharmony_ci 603262306a36Sopenharmony_ci summary_data.s = s; 603362306a36Sopenharmony_ci summary_data.level = level; 603462306a36Sopenharmony_ci summary_data.parent = rdev; 603562306a36Sopenharmony_ci 603662306a36Sopenharmony_ci class_for_each_device(®ulator_class, NULL, &summary_data, 603762306a36Sopenharmony_ci regulator_summary_show_children); 603862306a36Sopenharmony_ci} 603962306a36Sopenharmony_ci 604062306a36Sopenharmony_cistruct summary_lock_data { 604162306a36Sopenharmony_ci struct ww_acquire_ctx *ww_ctx; 604262306a36Sopenharmony_ci struct regulator_dev **new_contended_rdev; 604362306a36Sopenharmony_ci struct regulator_dev **old_contended_rdev; 604462306a36Sopenharmony_ci}; 604562306a36Sopenharmony_ci 604662306a36Sopenharmony_cistatic int regulator_summary_lock_one(struct device *dev, void *data) 604762306a36Sopenharmony_ci{ 604862306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 604962306a36Sopenharmony_ci struct summary_lock_data *lock_data = data; 605062306a36Sopenharmony_ci int ret = 0; 605162306a36Sopenharmony_ci 605262306a36Sopenharmony_ci if (rdev != *lock_data->old_contended_rdev) { 605362306a36Sopenharmony_ci ret = regulator_lock_nested(rdev, lock_data->ww_ctx); 605462306a36Sopenharmony_ci 605562306a36Sopenharmony_ci if (ret == -EDEADLK) 605662306a36Sopenharmony_ci *lock_data->new_contended_rdev = rdev; 605762306a36Sopenharmony_ci else 605862306a36Sopenharmony_ci WARN_ON_ONCE(ret); 605962306a36Sopenharmony_ci } else { 606062306a36Sopenharmony_ci *lock_data->old_contended_rdev = NULL; 606162306a36Sopenharmony_ci } 606262306a36Sopenharmony_ci 606362306a36Sopenharmony_ci return ret; 606462306a36Sopenharmony_ci} 606562306a36Sopenharmony_ci 606662306a36Sopenharmony_cistatic int regulator_summary_unlock_one(struct device *dev, void *data) 606762306a36Sopenharmony_ci{ 606862306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 606962306a36Sopenharmony_ci struct summary_lock_data *lock_data = data; 607062306a36Sopenharmony_ci 607162306a36Sopenharmony_ci if (lock_data) { 607262306a36Sopenharmony_ci if (rdev == *lock_data->new_contended_rdev) 607362306a36Sopenharmony_ci return -EDEADLK; 607462306a36Sopenharmony_ci } 607562306a36Sopenharmony_ci 607662306a36Sopenharmony_ci regulator_unlock(rdev); 607762306a36Sopenharmony_ci 607862306a36Sopenharmony_ci return 0; 607962306a36Sopenharmony_ci} 608062306a36Sopenharmony_ci 608162306a36Sopenharmony_cistatic int regulator_summary_lock_all(struct ww_acquire_ctx *ww_ctx, 608262306a36Sopenharmony_ci struct regulator_dev **new_contended_rdev, 608362306a36Sopenharmony_ci struct regulator_dev **old_contended_rdev) 608462306a36Sopenharmony_ci{ 608562306a36Sopenharmony_ci struct summary_lock_data lock_data; 608662306a36Sopenharmony_ci int ret; 608762306a36Sopenharmony_ci 608862306a36Sopenharmony_ci lock_data.ww_ctx = ww_ctx; 608962306a36Sopenharmony_ci lock_data.new_contended_rdev = new_contended_rdev; 609062306a36Sopenharmony_ci lock_data.old_contended_rdev = old_contended_rdev; 609162306a36Sopenharmony_ci 609262306a36Sopenharmony_ci ret = class_for_each_device(®ulator_class, NULL, &lock_data, 609362306a36Sopenharmony_ci regulator_summary_lock_one); 609462306a36Sopenharmony_ci if (ret) 609562306a36Sopenharmony_ci class_for_each_device(®ulator_class, NULL, &lock_data, 609662306a36Sopenharmony_ci regulator_summary_unlock_one); 609762306a36Sopenharmony_ci 609862306a36Sopenharmony_ci return ret; 609962306a36Sopenharmony_ci} 610062306a36Sopenharmony_ci 610162306a36Sopenharmony_cistatic void regulator_summary_lock(struct ww_acquire_ctx *ww_ctx) 610262306a36Sopenharmony_ci{ 610362306a36Sopenharmony_ci struct regulator_dev *new_contended_rdev = NULL; 610462306a36Sopenharmony_ci struct regulator_dev *old_contended_rdev = NULL; 610562306a36Sopenharmony_ci int err; 610662306a36Sopenharmony_ci 610762306a36Sopenharmony_ci mutex_lock(®ulator_list_mutex); 610862306a36Sopenharmony_ci 610962306a36Sopenharmony_ci ww_acquire_init(ww_ctx, ®ulator_ww_class); 611062306a36Sopenharmony_ci 611162306a36Sopenharmony_ci do { 611262306a36Sopenharmony_ci if (new_contended_rdev) { 611362306a36Sopenharmony_ci ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx); 611462306a36Sopenharmony_ci old_contended_rdev = new_contended_rdev; 611562306a36Sopenharmony_ci old_contended_rdev->ref_cnt++; 611662306a36Sopenharmony_ci old_contended_rdev->mutex_owner = current; 611762306a36Sopenharmony_ci } 611862306a36Sopenharmony_ci 611962306a36Sopenharmony_ci err = regulator_summary_lock_all(ww_ctx, 612062306a36Sopenharmony_ci &new_contended_rdev, 612162306a36Sopenharmony_ci &old_contended_rdev); 612262306a36Sopenharmony_ci 612362306a36Sopenharmony_ci if (old_contended_rdev) 612462306a36Sopenharmony_ci regulator_unlock(old_contended_rdev); 612562306a36Sopenharmony_ci 612662306a36Sopenharmony_ci } while (err == -EDEADLK); 612762306a36Sopenharmony_ci 612862306a36Sopenharmony_ci ww_acquire_done(ww_ctx); 612962306a36Sopenharmony_ci} 613062306a36Sopenharmony_ci 613162306a36Sopenharmony_cistatic void regulator_summary_unlock(struct ww_acquire_ctx *ww_ctx) 613262306a36Sopenharmony_ci{ 613362306a36Sopenharmony_ci class_for_each_device(®ulator_class, NULL, NULL, 613462306a36Sopenharmony_ci regulator_summary_unlock_one); 613562306a36Sopenharmony_ci ww_acquire_fini(ww_ctx); 613662306a36Sopenharmony_ci 613762306a36Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 613862306a36Sopenharmony_ci} 613962306a36Sopenharmony_ci 614062306a36Sopenharmony_cistatic int regulator_summary_show_roots(struct device *dev, void *data) 614162306a36Sopenharmony_ci{ 614262306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 614362306a36Sopenharmony_ci struct seq_file *s = data; 614462306a36Sopenharmony_ci 614562306a36Sopenharmony_ci if (!rdev->supply) 614662306a36Sopenharmony_ci regulator_summary_show_subtree(s, rdev, 0); 614762306a36Sopenharmony_ci 614862306a36Sopenharmony_ci return 0; 614962306a36Sopenharmony_ci} 615062306a36Sopenharmony_ci 615162306a36Sopenharmony_cistatic int regulator_summary_show(struct seq_file *s, void *data) 615262306a36Sopenharmony_ci{ 615362306a36Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 615462306a36Sopenharmony_ci 615562306a36Sopenharmony_ci seq_puts(s, " regulator use open bypass opmode voltage current min max\n"); 615662306a36Sopenharmony_ci seq_puts(s, "---------------------------------------------------------------------------------------\n"); 615762306a36Sopenharmony_ci 615862306a36Sopenharmony_ci regulator_summary_lock(&ww_ctx); 615962306a36Sopenharmony_ci 616062306a36Sopenharmony_ci class_for_each_device(®ulator_class, NULL, s, 616162306a36Sopenharmony_ci regulator_summary_show_roots); 616262306a36Sopenharmony_ci 616362306a36Sopenharmony_ci regulator_summary_unlock(&ww_ctx); 616462306a36Sopenharmony_ci 616562306a36Sopenharmony_ci return 0; 616662306a36Sopenharmony_ci} 616762306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(regulator_summary); 616862306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 616962306a36Sopenharmony_ci 617062306a36Sopenharmony_cistatic int __init regulator_init(void) 617162306a36Sopenharmony_ci{ 617262306a36Sopenharmony_ci int ret; 617362306a36Sopenharmony_ci 617462306a36Sopenharmony_ci ret = class_register(®ulator_class); 617562306a36Sopenharmony_ci 617662306a36Sopenharmony_ci debugfs_root = debugfs_create_dir("regulator", NULL); 617762306a36Sopenharmony_ci if (IS_ERR(debugfs_root)) 617862306a36Sopenharmony_ci pr_debug("regulator: Failed to create debugfs directory\n"); 617962306a36Sopenharmony_ci 618062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 618162306a36Sopenharmony_ci debugfs_create_file("supply_map", 0444, debugfs_root, NULL, 618262306a36Sopenharmony_ci &supply_map_fops); 618362306a36Sopenharmony_ci 618462306a36Sopenharmony_ci debugfs_create_file("regulator_summary", 0444, debugfs_root, 618562306a36Sopenharmony_ci NULL, ®ulator_summary_fops); 618662306a36Sopenharmony_ci#endif 618762306a36Sopenharmony_ci regulator_dummy_init(); 618862306a36Sopenharmony_ci 618962306a36Sopenharmony_ci regulator_coupler_register(&generic_regulator_coupler); 619062306a36Sopenharmony_ci 619162306a36Sopenharmony_ci return ret; 619262306a36Sopenharmony_ci} 619362306a36Sopenharmony_ci 619462306a36Sopenharmony_ci/* init early to allow our consumers to complete system booting */ 619562306a36Sopenharmony_cicore_initcall(regulator_init); 619662306a36Sopenharmony_ci 619762306a36Sopenharmony_cistatic int regulator_late_cleanup(struct device *dev, void *data) 619862306a36Sopenharmony_ci{ 619962306a36Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 620062306a36Sopenharmony_ci struct regulation_constraints *c = rdev->constraints; 620162306a36Sopenharmony_ci int ret; 620262306a36Sopenharmony_ci 620362306a36Sopenharmony_ci if (c && c->always_on) 620462306a36Sopenharmony_ci return 0; 620562306a36Sopenharmony_ci 620662306a36Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) 620762306a36Sopenharmony_ci return 0; 620862306a36Sopenharmony_ci 620962306a36Sopenharmony_ci regulator_lock(rdev); 621062306a36Sopenharmony_ci 621162306a36Sopenharmony_ci if (rdev->use_count) 621262306a36Sopenharmony_ci goto unlock; 621362306a36Sopenharmony_ci 621462306a36Sopenharmony_ci /* If reading the status failed, assume that it's off. */ 621562306a36Sopenharmony_ci if (_regulator_is_enabled(rdev) <= 0) 621662306a36Sopenharmony_ci goto unlock; 621762306a36Sopenharmony_ci 621862306a36Sopenharmony_ci if (have_full_constraints()) { 621962306a36Sopenharmony_ci /* We log since this may kill the system if it goes 622062306a36Sopenharmony_ci * wrong. 622162306a36Sopenharmony_ci */ 622262306a36Sopenharmony_ci rdev_info(rdev, "disabling\n"); 622362306a36Sopenharmony_ci ret = _regulator_do_disable(rdev); 622462306a36Sopenharmony_ci if (ret != 0) 622562306a36Sopenharmony_ci rdev_err(rdev, "couldn't disable: %pe\n", ERR_PTR(ret)); 622662306a36Sopenharmony_ci } else { 622762306a36Sopenharmony_ci /* The intention is that in future we will 622862306a36Sopenharmony_ci * assume that full constraints are provided 622962306a36Sopenharmony_ci * so warn even if we aren't going to do 623062306a36Sopenharmony_ci * anything here. 623162306a36Sopenharmony_ci */ 623262306a36Sopenharmony_ci rdev_warn(rdev, "incomplete constraints, leaving on\n"); 623362306a36Sopenharmony_ci } 623462306a36Sopenharmony_ci 623562306a36Sopenharmony_ciunlock: 623662306a36Sopenharmony_ci regulator_unlock(rdev); 623762306a36Sopenharmony_ci 623862306a36Sopenharmony_ci return 0; 623962306a36Sopenharmony_ci} 624062306a36Sopenharmony_ci 624162306a36Sopenharmony_cistatic void regulator_init_complete_work_function(struct work_struct *work) 624262306a36Sopenharmony_ci{ 624362306a36Sopenharmony_ci /* 624462306a36Sopenharmony_ci * Regulators may had failed to resolve their input supplies 624562306a36Sopenharmony_ci * when were registered, either because the input supply was 624662306a36Sopenharmony_ci * not registered yet or because its parent device was not 624762306a36Sopenharmony_ci * bound yet. So attempt to resolve the input supplies for 624862306a36Sopenharmony_ci * pending regulators before trying to disable unused ones. 624962306a36Sopenharmony_ci */ 625062306a36Sopenharmony_ci class_for_each_device(®ulator_class, NULL, NULL, 625162306a36Sopenharmony_ci regulator_register_resolve_supply); 625262306a36Sopenharmony_ci 625362306a36Sopenharmony_ci /* If we have a full configuration then disable any regulators 625462306a36Sopenharmony_ci * we have permission to change the status for and which are 625562306a36Sopenharmony_ci * not in use or always_on. This is effectively the default 625662306a36Sopenharmony_ci * for DT and ACPI as they have full constraints. 625762306a36Sopenharmony_ci */ 625862306a36Sopenharmony_ci class_for_each_device(®ulator_class, NULL, NULL, 625962306a36Sopenharmony_ci regulator_late_cleanup); 626062306a36Sopenharmony_ci} 626162306a36Sopenharmony_ci 626262306a36Sopenharmony_cistatic DECLARE_DELAYED_WORK(regulator_init_complete_work, 626362306a36Sopenharmony_ci regulator_init_complete_work_function); 626462306a36Sopenharmony_ci 626562306a36Sopenharmony_cistatic int __init regulator_init_complete(void) 626662306a36Sopenharmony_ci{ 626762306a36Sopenharmony_ci /* 626862306a36Sopenharmony_ci * Since DT doesn't provide an idiomatic mechanism for 626962306a36Sopenharmony_ci * enabling full constraints and since it's much more natural 627062306a36Sopenharmony_ci * with DT to provide them just assume that a DT enabled 627162306a36Sopenharmony_ci * system has full constraints. 627262306a36Sopenharmony_ci */ 627362306a36Sopenharmony_ci if (of_have_populated_dt()) 627462306a36Sopenharmony_ci has_full_constraints = true; 627562306a36Sopenharmony_ci 627662306a36Sopenharmony_ci /* 627762306a36Sopenharmony_ci * We punt completion for an arbitrary amount of time since 627862306a36Sopenharmony_ci * systems like distros will load many drivers from userspace 627962306a36Sopenharmony_ci * so consumers might not always be ready yet, this is 628062306a36Sopenharmony_ci * particularly an issue with laptops where this might bounce 628162306a36Sopenharmony_ci * the display off then on. Ideally we'd get a notification 628262306a36Sopenharmony_ci * from userspace when this happens but we don't so just wait 628362306a36Sopenharmony_ci * a bit and hope we waited long enough. It'd be better if 628462306a36Sopenharmony_ci * we'd only do this on systems that need it, and a kernel 628562306a36Sopenharmony_ci * command line option might be useful. 628662306a36Sopenharmony_ci */ 628762306a36Sopenharmony_ci schedule_delayed_work(®ulator_init_complete_work, 628862306a36Sopenharmony_ci msecs_to_jiffies(30000)); 628962306a36Sopenharmony_ci 629062306a36Sopenharmony_ci return 0; 629162306a36Sopenharmony_ci} 629262306a36Sopenharmony_cilate_initcall_sync(regulator_init_complete); 6293