12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2f2c6203fSMark Brown // 3f2c6203fSMark Brown // core.c -- Voltage/Current Regulator framework. 4f2c6203fSMark Brown // 5f2c6203fSMark Brown // Copyright 2007, 2008 Wolfson Microelectronics PLC. 6f2c6203fSMark Brown // Copyright 2008 SlimLogic Ltd. 7f2c6203fSMark Brown // 8f2c6203fSMark Brown // Author: Liam Girdwood <lrg@slimlogic.co.uk> 9414c70cbSLiam Girdwood 10414c70cbSLiam Girdwood #include <linux/kernel.h> 11414c70cbSLiam Girdwood #include <linux/init.h> 121130e5b3SMark Brown #include <linux/debugfs.h> 13414c70cbSLiam Girdwood #include <linux/device.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 15f21e0e81SMark Brown #include <linux/async.h> 16414c70cbSLiam Girdwood #include <linux/err.h> 17414c70cbSLiam Girdwood #include <linux/mutex.h> 18414c70cbSLiam Girdwood #include <linux/suspend.h> 1931aae2beSMark Brown #include <linux/delay.h> 20778b28b4SRussell King #include <linux/gpio/consumer.h> 2169511a45SRajendra Nayak #include <linux/of.h> 2265b19ce6SMark Brown #include <linux/regmap.h> 2369511a45SRajendra Nayak #include <linux/regulator/of_regulator.h> 24414c70cbSLiam Girdwood #include <linux/regulator/consumer.h> 25d8ca7d18SDmitry Osipenko #include <linux/regulator/coupler.h> 26414c70cbSLiam Girdwood #include <linux/regulator/driver.h> 27414c70cbSLiam Girdwood #include <linux/regulator/machine.h> 2865602c32SPaul Gortmaker #include <linux/module.h> 29414c70cbSLiam Girdwood 3002fa3ec0SMark Brown #define CREATE_TRACE_POINTS 3102fa3ec0SMark Brown #include <trace/events/regulator.h> 3202fa3ec0SMark Brown 3334abbd68SMark Brown #include "dummy.h" 340cdfcc0fSMark Brown #include "internal.h" 3534abbd68SMark Brown 36f8702f9eSDmitry Osipenko static DEFINE_WW_CLASS(regulator_ww_class); 37f8702f9eSDmitry Osipenko static DEFINE_MUTEX(regulator_nesting_mutex); 38414c70cbSLiam Girdwood static DEFINE_MUTEX(regulator_list_mutex); 39414c70cbSLiam Girdwood static LIST_HEAD(regulator_map_list); 40f19b00daSKim, Milo static LIST_HEAD(regulator_ena_gpio_list); 41a06ccd9cSCharles Keepax static LIST_HEAD(regulator_supply_alias_list); 42d8ca7d18SDmitry Osipenko static LIST_HEAD(regulator_coupler_list); 4321cf891aSMark Brown static bool has_full_constraints; 44414c70cbSLiam Girdwood 451130e5b3SMark Brown static struct dentry *debugfs_root; 461130e5b3SMark Brown 478dc5390dSMark Brown /* 48414c70cbSLiam Girdwood * struct regulator_map 49414c70cbSLiam Girdwood * 50414c70cbSLiam Girdwood * Used to provide symbolic supply names to devices. 51414c70cbSLiam Girdwood */ 52414c70cbSLiam Girdwood struct regulator_map { 53414c70cbSLiam Girdwood struct list_head list; 5440f9244fSMark Brown const char *dev_name; /* The dev_name() for the consumer */ 55414c70cbSLiam Girdwood const char *supply; 56a5766f11SLiam Girdwood struct regulator_dev *regulator; 57414c70cbSLiam Girdwood }; 58414c70cbSLiam Girdwood 59414c70cbSLiam Girdwood /* 60f19b00daSKim, Milo * struct regulator_enable_gpio 61f19b00daSKim, Milo * 62f19b00daSKim, Milo * Management for shared enable GPIO pin 63f19b00daSKim, Milo */ 64f19b00daSKim, Milo struct regulator_enable_gpio { 65f19b00daSKim, Milo struct list_head list; 66778b28b4SRussell King struct gpio_desc *gpiod; 67f19b00daSKim, Milo u32 enable_count; /* a number of enabled shared GPIO */ 68f19b00daSKim, Milo u32 request_count; /* a number of requested shared GPIO */ 69f19b00daSKim, Milo }; 70f19b00daSKim, Milo 71a06ccd9cSCharles Keepax /* 72a06ccd9cSCharles Keepax * struct regulator_supply_alias 73a06ccd9cSCharles Keepax * 74a06ccd9cSCharles Keepax * Used to map lookups for a supply onto an alternative device. 75a06ccd9cSCharles Keepax */ 76a06ccd9cSCharles Keepax struct regulator_supply_alias { 77a06ccd9cSCharles Keepax struct list_head list; 78a06ccd9cSCharles Keepax struct device *src_dev; 79a06ccd9cSCharles Keepax const char *src_supply; 80a06ccd9cSCharles Keepax struct device *alias_dev; 81a06ccd9cSCharles Keepax const char *alias_supply; 82a06ccd9cSCharles Keepax }; 83a06ccd9cSCharles Keepax 84414c70cbSLiam Girdwood static int _regulator_is_enabled(struct regulator_dev *rdev); 855451781dSDouglas Anderson static int _regulator_disable(struct regulator *regulator); 860f2d636eSZev Weiss static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags); 87414c70cbSLiam Girdwood static int _regulator_get_current_limit(struct regulator_dev *rdev); 88414c70cbSLiam Girdwood static unsigned int _regulator_get_mode(struct regulator_dev *rdev); 897179569aSHeiko Stübner static int _notifier_call_chain(struct regulator_dev *rdev, 90414c70cbSLiam Girdwood unsigned long event, void *data); 9175790251SMark Brown static int _regulator_do_set_voltage(struct regulator_dev *rdev, 9275790251SMark Brown int min_uV, int max_uV); 93c054c6c7SMaciej Purski static int regulator_balance_voltage(struct regulator_dev *rdev, 94c054c6c7SMaciej Purski suspend_state_t state); 953801b86aSMark Brown static struct regulator *create_regulator(struct regulator_dev *rdev, 963801b86aSMark Brown struct device *dev, 973801b86aSMark Brown const char *supply_name); 98e1794aa4SSaravana Kannan static void destroy_regulator(struct regulator *regulator); 9936a1f1b6SJavier Martinez Canillas static void _regulator_put(struct regulator *regulator); 100414c70cbSLiam Girdwood 101d22b85a1SDmitry Osipenko const char *rdev_get_name(struct regulator_dev *rdev) 1021083c393SMark Brown { 1031083c393SMark Brown if (rdev->constraints && rdev->constraints->name) 1041083c393SMark Brown return rdev->constraints->name; 1051083c393SMark Brown else if (rdev->desc->name) 1061083c393SMark Brown return rdev->desc->name; 1071083c393SMark Brown else 1081083c393SMark Brown return ""; 1091083c393SMark Brown } 110157d2230SMatti Vaittinen EXPORT_SYMBOL_GPL(rdev_get_name); 1111083c393SMark Brown 11287b28417SMark Brown static bool have_full_constraints(void) 11387b28417SMark Brown { 11475bc9641SMark Brown return has_full_constraints || of_have_populated_dt(); 11587b28417SMark Brown } 11687b28417SMark Brown 1178a34e979SWEN Pingbo static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) 1188a34e979SWEN Pingbo { 1198a34e979SWEN Pingbo if (!rdev->constraints) { 1208a34e979SWEN Pingbo rdev_err(rdev, "no constraints\n"); 1218a34e979SWEN Pingbo return false; 1228a34e979SWEN Pingbo } 1238a34e979SWEN Pingbo 1248a34e979SWEN Pingbo if (rdev->constraints->valid_ops_mask & ops) 1258a34e979SWEN Pingbo return true; 1268a34e979SWEN Pingbo 1278a34e979SWEN Pingbo return false; 1288a34e979SWEN Pingbo } 1298a34e979SWEN Pingbo 13069511a45SRajendra Nayak /** 13166cf9a7eSMaciej Purski * regulator_lock_nested - lock a single regulator 13266cf9a7eSMaciej Purski * @rdev: regulator source 133f8702f9eSDmitry Osipenko * @ww_ctx: w/w mutex acquire context 13466cf9a7eSMaciej Purski * 13566cf9a7eSMaciej Purski * This function can be called many times by one task on 13666cf9a7eSMaciej Purski * a single regulator and its mutex will be locked only 13766cf9a7eSMaciej Purski * once. If a task, which is calling this function is other 13866cf9a7eSMaciej Purski * than the one, which initially locked the mutex, it will 13966cf9a7eSMaciej Purski * wait on mutex. 14066cf9a7eSMaciej Purski */ 141f8702f9eSDmitry Osipenko static inline int regulator_lock_nested(struct regulator_dev *rdev, 142f8702f9eSDmitry Osipenko struct ww_acquire_ctx *ww_ctx) 14366cf9a7eSMaciej Purski { 144f8702f9eSDmitry Osipenko bool lock = false; 145f8702f9eSDmitry Osipenko int ret = 0; 146f8702f9eSDmitry Osipenko 147f8702f9eSDmitry Osipenko mutex_lock(®ulator_nesting_mutex); 148f8702f9eSDmitry Osipenko 14912235da8SMaarten Lankhorst if (!ww_mutex_trylock(&rdev->mutex, ww_ctx)) { 150f8702f9eSDmitry Osipenko if (rdev->mutex_owner == current) 15166cf9a7eSMaciej Purski rdev->ref_cnt++; 152f8702f9eSDmitry Osipenko else 153f8702f9eSDmitry Osipenko lock = true; 154f8702f9eSDmitry Osipenko 155f8702f9eSDmitry Osipenko if (lock) { 156f8702f9eSDmitry Osipenko mutex_unlock(®ulator_nesting_mutex); 157f8702f9eSDmitry Osipenko ret = ww_mutex_lock(&rdev->mutex, ww_ctx); 158f8702f9eSDmitry Osipenko mutex_lock(®ulator_nesting_mutex); 15966cf9a7eSMaciej Purski } 160f8702f9eSDmitry Osipenko } else { 161f8702f9eSDmitry Osipenko lock = true; 16266cf9a7eSMaciej Purski } 16366cf9a7eSMaciej Purski 164f8702f9eSDmitry Osipenko if (lock && ret != -EDEADLK) { 165f8702f9eSDmitry Osipenko rdev->ref_cnt++; 16666cf9a7eSMaciej Purski rdev->mutex_owner = current; 16766cf9a7eSMaciej Purski } 16866cf9a7eSMaciej Purski 169f8702f9eSDmitry Osipenko mutex_unlock(®ulator_nesting_mutex); 170f8702f9eSDmitry Osipenko 171f8702f9eSDmitry Osipenko return ret; 172f8702f9eSDmitry Osipenko } 173f8702f9eSDmitry Osipenko 174f8702f9eSDmitry Osipenko /** 175f8702f9eSDmitry Osipenko * regulator_lock - lock a single regulator 176f8702f9eSDmitry Osipenko * @rdev: regulator source 177f8702f9eSDmitry Osipenko * 178f8702f9eSDmitry Osipenko * This function can be called many times by one task on 179f8702f9eSDmitry Osipenko * a single regulator and its mutex will be locked only 180f8702f9eSDmitry Osipenko * once. If a task, which is calling this function is other 181f8702f9eSDmitry Osipenko * than the one, which initially locked the mutex, it will 182f8702f9eSDmitry Osipenko * wait on mutex. 183f8702f9eSDmitry Osipenko */ 1844c9db393SMichał Mirosław static void regulator_lock(struct regulator_dev *rdev) 18566cf9a7eSMaciej Purski { 186f8702f9eSDmitry Osipenko regulator_lock_nested(rdev, NULL); 18766cf9a7eSMaciej Purski } 18866cf9a7eSMaciej Purski 18966cf9a7eSMaciej Purski /** 19066cf9a7eSMaciej Purski * regulator_unlock - unlock a single regulator 19166cf9a7eSMaciej Purski * @rdev: regulator_source 19266cf9a7eSMaciej Purski * 19366cf9a7eSMaciej Purski * This function unlocks the mutex when the 19466cf9a7eSMaciej Purski * reference counter reaches 0. 19566cf9a7eSMaciej Purski */ 1964c9db393SMichał Mirosław static void regulator_unlock(struct regulator_dev *rdev) 19766cf9a7eSMaciej Purski { 198f8702f9eSDmitry Osipenko mutex_lock(®ulator_nesting_mutex); 19966cf9a7eSMaciej Purski 200f8702f9eSDmitry Osipenko if (--rdev->ref_cnt == 0) { 20166cf9a7eSMaciej Purski rdev->mutex_owner = NULL; 202f8702f9eSDmitry Osipenko ww_mutex_unlock(&rdev->mutex); 20366cf9a7eSMaciej Purski } 20466cf9a7eSMaciej Purski 205f8702f9eSDmitry Osipenko WARN_ON_ONCE(rdev->ref_cnt < 0); 206f8702f9eSDmitry Osipenko 207f8702f9eSDmitry Osipenko mutex_unlock(®ulator_nesting_mutex); 208f8702f9eSDmitry Osipenko } 209f8702f9eSDmitry Osipenko 210089e2cc2SDmitry Osipenko static bool regulator_supply_is_couple(struct regulator_dev *rdev) 2119f01cd4aSSascha Hauer { 212089e2cc2SDmitry Osipenko struct regulator_dev *c_rdev; 213fa731ac7SArnd Bergmann int i; 2149f01cd4aSSascha Hauer 215089e2cc2SDmitry Osipenko for (i = 1; i < rdev->coupling_desc.n_coupled; i++) { 216089e2cc2SDmitry Osipenko c_rdev = rdev->coupling_desc.coupled_rdevs[i]; 217089e2cc2SDmitry Osipenko 218089e2cc2SDmitry Osipenko if (rdev->supply->rdev == c_rdev) 219089e2cc2SDmitry Osipenko return true; 220089e2cc2SDmitry Osipenko } 221089e2cc2SDmitry Osipenko 222089e2cc2SDmitry Osipenko return false; 223089e2cc2SDmitry Osipenko } 224089e2cc2SDmitry Osipenko 225f8702f9eSDmitry Osipenko static void regulator_unlock_recursive(struct regulator_dev *rdev, 226f8702f9eSDmitry Osipenko unsigned int n_coupled) 227f8702f9eSDmitry Osipenko { 2280a7416f9SDmitry Osipenko struct regulator_dev *c_rdev, *supply_rdev; 2290a7416f9SDmitry Osipenko int i, supply_n_coupled; 230f8702f9eSDmitry Osipenko 231f8702f9eSDmitry Osipenko for (i = n_coupled; i > 0; i--) { 232f8702f9eSDmitry Osipenko c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1]; 233f8702f9eSDmitry Osipenko 234f8702f9eSDmitry Osipenko if (!c_rdev) 235f8702f9eSDmitry Osipenko continue; 236f8702f9eSDmitry Osipenko 2370a7416f9SDmitry Osipenko if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) { 2380a7416f9SDmitry Osipenko supply_rdev = c_rdev->supply->rdev; 2390a7416f9SDmitry Osipenko supply_n_coupled = supply_rdev->coupling_desc.n_coupled; 2400a7416f9SDmitry Osipenko 2410a7416f9SDmitry Osipenko regulator_unlock_recursive(supply_rdev, 2420a7416f9SDmitry Osipenko supply_n_coupled); 2430a7416f9SDmitry Osipenko } 244f8702f9eSDmitry Osipenko 245f8702f9eSDmitry Osipenko regulator_unlock(c_rdev); 246414c70cbSLiam Girdwood } 247414c70cbSLiam Girdwood } 248414c70cbSLiam Girdwood 2499243a195SMaciej Purski static int regulator_lock_recursive(struct regulator_dev *rdev, 250f8702f9eSDmitry Osipenko struct regulator_dev **new_contended_rdev, 251f8702f9eSDmitry Osipenko struct regulator_dev **old_contended_rdev, 252f8702f9eSDmitry Osipenko struct ww_acquire_ctx *ww_ctx) 2539f01cd4aSSascha Hauer { 2549243a195SMaciej Purski struct regulator_dev *c_rdev; 255f8702f9eSDmitry Osipenko int i, err; 2569f01cd4aSSascha Hauer 2579243a195SMaciej Purski for (i = 0; i < rdev->coupling_desc.n_coupled; i++) { 2589243a195SMaciej Purski c_rdev = rdev->coupling_desc.coupled_rdevs[i]; 2599243a195SMaciej Purski 2609243a195SMaciej Purski if (!c_rdev) 2619243a195SMaciej Purski continue; 2629243a195SMaciej Purski 263f8702f9eSDmitry Osipenko if (c_rdev != *old_contended_rdev) { 264f8702f9eSDmitry Osipenko err = regulator_lock_nested(c_rdev, ww_ctx); 265f8702f9eSDmitry Osipenko if (err) { 266f8702f9eSDmitry Osipenko if (err == -EDEADLK) { 267f8702f9eSDmitry Osipenko *new_contended_rdev = c_rdev; 268f8702f9eSDmitry Osipenko goto err_unlock; 2699243a195SMaciej Purski } 2709243a195SMaciej Purski 271f8702f9eSDmitry Osipenko /* shouldn't happen */ 272f8702f9eSDmitry Osipenko WARN_ON_ONCE(err != -EALREADY); 273f8702f9eSDmitry Osipenko } 274f8702f9eSDmitry Osipenko } else { 275f8702f9eSDmitry Osipenko *old_contended_rdev = NULL; 276f8702f9eSDmitry Osipenko } 277f8702f9eSDmitry Osipenko 278089e2cc2SDmitry Osipenko if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) { 279f8702f9eSDmitry Osipenko err = regulator_lock_recursive(c_rdev->supply->rdev, 280f8702f9eSDmitry Osipenko new_contended_rdev, 281f8702f9eSDmitry Osipenko old_contended_rdev, 282f8702f9eSDmitry Osipenko ww_ctx); 283f8702f9eSDmitry Osipenko if (err) { 284f8702f9eSDmitry Osipenko regulator_unlock(c_rdev); 285f8702f9eSDmitry Osipenko goto err_unlock; 286f8702f9eSDmitry Osipenko } 287f8702f9eSDmitry Osipenko } 288f8702f9eSDmitry Osipenko } 289f8702f9eSDmitry Osipenko 290f8702f9eSDmitry Osipenko return 0; 291f8702f9eSDmitry Osipenko 292f8702f9eSDmitry Osipenko err_unlock: 293f8702f9eSDmitry Osipenko regulator_unlock_recursive(rdev, i); 294f8702f9eSDmitry Osipenko 295f8702f9eSDmitry Osipenko return err; 2969f01cd4aSSascha Hauer } 2979f01cd4aSSascha Hauer 2989f01cd4aSSascha Hauer /** 2999243a195SMaciej Purski * regulator_unlock_dependent - unlock regulator's suppliers and coupled 3009243a195SMaciej Purski * regulators 3019f01cd4aSSascha Hauer * @rdev: regulator source 302f8702f9eSDmitry Osipenko * @ww_ctx: w/w mutex acquire context 3039243a195SMaciej Purski * 30448f1b4efSKrzysztof Kozlowski * Unlock all regulators related with rdev by coupling or supplying. 3059f01cd4aSSascha Hauer */ 306f8702f9eSDmitry Osipenko static void regulator_unlock_dependent(struct regulator_dev *rdev, 307f8702f9eSDmitry Osipenko struct ww_acquire_ctx *ww_ctx) 3089f01cd4aSSascha Hauer { 309f8702f9eSDmitry Osipenko regulator_unlock_recursive(rdev, rdev->coupling_desc.n_coupled); 310f8702f9eSDmitry Osipenko ww_acquire_fini(ww_ctx); 3119f01cd4aSSascha Hauer } 3129f01cd4aSSascha Hauer 3139f01cd4aSSascha Hauer /** 3149243a195SMaciej Purski * regulator_lock_dependent - lock regulator's suppliers and coupled regulators 3159243a195SMaciej Purski * @rdev: regulator source 316f8702f9eSDmitry Osipenko * @ww_ctx: w/w mutex acquire context 3179243a195SMaciej Purski * 3189243a195SMaciej Purski * This function as a wrapper on regulator_lock_recursive(), which locks 31948f1b4efSKrzysztof Kozlowski * all regulators related with rdev by coupling or supplying. 3209243a195SMaciej Purski */ 321f8702f9eSDmitry Osipenko static void regulator_lock_dependent(struct regulator_dev *rdev, 322f8702f9eSDmitry Osipenko struct ww_acquire_ctx *ww_ctx) 3239243a195SMaciej Purski { 324f8702f9eSDmitry Osipenko struct regulator_dev *new_contended_rdev = NULL; 325f8702f9eSDmitry Osipenko struct regulator_dev *old_contended_rdev = NULL; 326f8702f9eSDmitry Osipenko int err; 327f8702f9eSDmitry Osipenko 328f8702f9eSDmitry Osipenko mutex_lock(®ulator_list_mutex); 329f8702f9eSDmitry Osipenko 330f8702f9eSDmitry Osipenko ww_acquire_init(ww_ctx, ®ulator_ww_class); 331f8702f9eSDmitry Osipenko 332f8702f9eSDmitry Osipenko do { 333f8702f9eSDmitry Osipenko if (new_contended_rdev) { 334f8702f9eSDmitry Osipenko ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx); 335f8702f9eSDmitry Osipenko old_contended_rdev = new_contended_rdev; 336f8702f9eSDmitry Osipenko old_contended_rdev->ref_cnt++; 337f8702f9eSDmitry Osipenko } 338f8702f9eSDmitry Osipenko 339f8702f9eSDmitry Osipenko err = regulator_lock_recursive(rdev, 340f8702f9eSDmitry Osipenko &new_contended_rdev, 341f8702f9eSDmitry Osipenko &old_contended_rdev, 342f8702f9eSDmitry Osipenko ww_ctx); 343f8702f9eSDmitry Osipenko 344f8702f9eSDmitry Osipenko if (old_contended_rdev) 345f8702f9eSDmitry Osipenko regulator_unlock(old_contended_rdev); 346f8702f9eSDmitry Osipenko 347f8702f9eSDmitry Osipenko } while (err == -EDEADLK); 348f8702f9eSDmitry Osipenko 349f8702f9eSDmitry Osipenko ww_acquire_done(ww_ctx); 350f8702f9eSDmitry Osipenko 351f8702f9eSDmitry Osipenko mutex_unlock(®ulator_list_mutex); 352414c70cbSLiam Girdwood } 353414c70cbSLiam Girdwood 354414c70cbSLiam Girdwood /** 355fe06051dSzoro * of_get_child_regulator - get a child regulator device node 356fe06051dSzoro * based on supply name 357fe06051dSzoro * @parent: Parent device node 358fe06051dSzoro * @prop_name: Combination regulator supply name and "-supply" 359fe06051dSzoro * 360fe06051dSzoro * Traverse all child nodes. 361fe06051dSzoro * Extract the child regulator device node corresponding to the supply name. 362fe06051dSzoro * returns the device node corresponding to the regulator if found, else 363fe06051dSzoro * returns NULL. 364fe06051dSzoro */ 365fe06051dSzoro static struct device_node *of_get_child_regulator(struct device_node *parent, 366fe06051dSzoro const char *prop_name) 367fe06051dSzoro { 368fe06051dSzoro struct device_node *regnode = NULL; 369fe06051dSzoro struct device_node *child = NULL; 370fe06051dSzoro 371fe06051dSzoro for_each_child_of_node(parent, child) { 372fe06051dSzoro regnode = of_parse_phandle(child, prop_name, 0); 373fe06051dSzoro 374fe06051dSzoro if (!regnode) { 375fe06051dSzoro regnode = of_get_child_regulator(child, prop_name); 37681eeb0a3SNishka Dasgupta if (regnode) 37781eeb0a3SNishka Dasgupta goto err_node_put; 378fe06051dSzoro } else { 37981eeb0a3SNishka Dasgupta goto err_node_put; 380fe06051dSzoro } 381fe06051dSzoro } 382fe06051dSzoro return NULL; 38381eeb0a3SNishka Dasgupta 38481eeb0a3SNishka Dasgupta err_node_put: 38581eeb0a3SNishka Dasgupta of_node_put(child); 38681eeb0a3SNishka Dasgupta return regnode; 387fe06051dSzoro } 388fe06051dSzoro 389fe06051dSzoro /** 39069511a45SRajendra Nayak * of_get_regulator - get a regulator device node based on supply name 39169511a45SRajendra Nayak * @dev: Device pointer for the consumer (of regulator) device 39269511a45SRajendra Nayak * @supply: regulator supply name 39369511a45SRajendra Nayak * 39469511a45SRajendra Nayak * Extract the regulator device node corresponding to the supply name. 395167d41dcSMaxime Ripard * returns the device node corresponding to the regulator if found, else 39669511a45SRajendra Nayak * returns NULL. 39769511a45SRajendra Nayak */ 39869511a45SRajendra Nayak static struct device_node *of_get_regulator(struct device *dev, const char *supply) 39969511a45SRajendra Nayak { 40069511a45SRajendra Nayak struct device_node *regnode = NULL; 401e9bb4a06SAngeloGioacchino Del Regno char prop_name[64]; /* 64 is max size of property name */ 40269511a45SRajendra Nayak 40369511a45SRajendra Nayak dev_dbg(dev, "Looking up %s-supply from device tree\n", supply); 40469511a45SRajendra Nayak 405e9bb4a06SAngeloGioacchino Del Regno snprintf(prop_name, 64, "%s-supply", supply); 40669511a45SRajendra Nayak regnode = of_parse_phandle(dev->of_node, prop_name, 0); 40769511a45SRajendra Nayak 40869511a45SRajendra Nayak if (!regnode) { 409fe06051dSzoro regnode = of_get_child_regulator(dev->of_node, prop_name); 410fe06051dSzoro if (regnode) 411fe06051dSzoro return regnode; 412fe06051dSzoro 4137799167bSRob Herring dev_dbg(dev, "Looking up %s property in node %pOF failed\n", 4147799167bSRob Herring prop_name, dev->of_node); 41569511a45SRajendra Nayak return NULL; 41669511a45SRajendra Nayak } 41769511a45SRajendra Nayak return regnode; 41869511a45SRajendra Nayak } 41969511a45SRajendra Nayak 420414c70cbSLiam Girdwood /* Platform voltage constraint check */ 421d22b85a1SDmitry Osipenko int regulator_check_voltage(struct regulator_dev *rdev, 422414c70cbSLiam Girdwood int *min_uV, int *max_uV) 423414c70cbSLiam Girdwood { 424414c70cbSLiam Girdwood BUG_ON(*min_uV > *max_uV); 425414c70cbSLiam Girdwood 4268a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 4277ebcf26cSStephen Boyd rdev_err(rdev, "voltage operation not allowed\n"); 428414c70cbSLiam Girdwood return -EPERM; 429414c70cbSLiam Girdwood } 430414c70cbSLiam Girdwood 431414c70cbSLiam Girdwood if (*max_uV > rdev->constraints->max_uV) 432414c70cbSLiam Girdwood *max_uV = rdev->constraints->max_uV; 433414c70cbSLiam Girdwood if (*min_uV < rdev->constraints->min_uV) 434414c70cbSLiam Girdwood *min_uV = rdev->constraints->min_uV; 435414c70cbSLiam Girdwood 43689f425edSMark Brown if (*min_uV > *max_uV) { 43789f425edSMark Brown rdev_err(rdev, "unsupportable voltage range: %d-%duV\n", 43854abd335SMark Brown *min_uV, *max_uV); 439414c70cbSLiam Girdwood return -EINVAL; 44089f425edSMark Brown } 441414c70cbSLiam Girdwood 442414c70cbSLiam Girdwood return 0; 443414c70cbSLiam Girdwood } 444414c70cbSLiam Girdwood 445f7efad10SChunyan Zhang /* return 0 if the state is valid */ 446f7efad10SChunyan Zhang static int regulator_check_states(suspend_state_t state) 447f7efad10SChunyan Zhang { 448f7efad10SChunyan Zhang return (state > PM_SUSPEND_MAX || state == PM_SUSPEND_TO_IDLE); 449f7efad10SChunyan Zhang } 450f7efad10SChunyan Zhang 45105fda3b1SThomas Petazzoni /* Make sure we select a voltage that suits the needs of all 45205fda3b1SThomas Petazzoni * regulator consumers 45305fda3b1SThomas Petazzoni */ 454d22b85a1SDmitry Osipenko int regulator_check_consumers(struct regulator_dev *rdev, 455c360a6dfSChunyan Zhang int *min_uV, int *max_uV, 456c360a6dfSChunyan Zhang suspend_state_t state) 45705fda3b1SThomas Petazzoni { 45805fda3b1SThomas Petazzoni struct regulator *regulator; 459c360a6dfSChunyan Zhang struct regulator_voltage *voltage; 46005fda3b1SThomas Petazzoni 46105fda3b1SThomas Petazzoni list_for_each_entry(regulator, &rdev->consumer_list, list) { 462c360a6dfSChunyan Zhang voltage = ®ulator->voltage[state]; 4634aa922c0SMark Brown /* 4644aa922c0SMark Brown * Assume consumers that didn't say anything are OK 4654aa922c0SMark Brown * with anything in the constraint range. 4664aa922c0SMark Brown */ 467c360a6dfSChunyan Zhang if (!voltage->min_uV && !voltage->max_uV) 4684aa922c0SMark Brown continue; 4694aa922c0SMark Brown 470c360a6dfSChunyan Zhang if (*max_uV > voltage->max_uV) 471c360a6dfSChunyan Zhang *max_uV = voltage->max_uV; 472c360a6dfSChunyan Zhang if (*min_uV < voltage->min_uV) 473c360a6dfSChunyan Zhang *min_uV = voltage->min_uV; 47405fda3b1SThomas Petazzoni } 47505fda3b1SThomas Petazzoni 476dd8004afSMark Brown if (*min_uV > *max_uV) { 4779c7b4e8aSRuss Dill rdev_err(rdev, "Restricting voltage, %u-%uuV\n", 4789c7b4e8aSRuss Dill *min_uV, *max_uV); 47905fda3b1SThomas Petazzoni return -EINVAL; 480dd8004afSMark Brown } 48105fda3b1SThomas Petazzoni 48205fda3b1SThomas Petazzoni return 0; 48305fda3b1SThomas Petazzoni } 48405fda3b1SThomas Petazzoni 485414c70cbSLiam Girdwood /* current constraint check */ 486414c70cbSLiam Girdwood static int regulator_check_current_limit(struct regulator_dev *rdev, 487414c70cbSLiam Girdwood int *min_uA, int *max_uA) 488414c70cbSLiam Girdwood { 489414c70cbSLiam Girdwood BUG_ON(*min_uA > *max_uA); 490414c70cbSLiam Girdwood 4918a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_CURRENT)) { 4927ebcf26cSStephen Boyd rdev_err(rdev, "current operation not allowed\n"); 493414c70cbSLiam Girdwood return -EPERM; 494414c70cbSLiam Girdwood } 495414c70cbSLiam Girdwood 496414c70cbSLiam Girdwood if (*max_uA > rdev->constraints->max_uA) 497414c70cbSLiam Girdwood *max_uA = rdev->constraints->max_uA; 498414c70cbSLiam Girdwood if (*min_uA < rdev->constraints->min_uA) 499414c70cbSLiam Girdwood *min_uA = rdev->constraints->min_uA; 500414c70cbSLiam Girdwood 50189f425edSMark Brown if (*min_uA > *max_uA) { 50289f425edSMark Brown rdev_err(rdev, "unsupportable current range: %d-%duA\n", 50354abd335SMark Brown *min_uA, *max_uA); 504414c70cbSLiam Girdwood return -EINVAL; 50589f425edSMark Brown } 506414c70cbSLiam Girdwood 507414c70cbSLiam Girdwood return 0; 508414c70cbSLiam Girdwood } 509414c70cbSLiam Girdwood 510414c70cbSLiam Girdwood /* operating mode constraint check */ 511109c75afSCharles Keepax static int regulator_mode_constrain(struct regulator_dev *rdev, 512109c75afSCharles Keepax unsigned int *mode) 513414c70cbSLiam Girdwood { 5142c608234SMark Brown switch (*mode) { 515e573520bSDavid Brownell case REGULATOR_MODE_FAST: 516e573520bSDavid Brownell case REGULATOR_MODE_NORMAL: 517e573520bSDavid Brownell case REGULATOR_MODE_IDLE: 518e573520bSDavid Brownell case REGULATOR_MODE_STANDBY: 519e573520bSDavid Brownell break; 520e573520bSDavid Brownell default: 52189f425edSMark Brown rdev_err(rdev, "invalid mode %x specified\n", *mode); 522e573520bSDavid Brownell return -EINVAL; 523e573520bSDavid Brownell } 524e573520bSDavid Brownell 5258a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_MODE)) { 5267ebcf26cSStephen Boyd rdev_err(rdev, "mode operation not allowed\n"); 527414c70cbSLiam Girdwood return -EPERM; 528414c70cbSLiam Girdwood } 5292c608234SMark Brown 5302c608234SMark Brown /* The modes are bitmasks, the most power hungry modes having 5312c608234SMark Brown * the lowest values. If the requested mode isn't supported 53269b8821eSShubhankar Kuranagatti * try higher modes. 53369b8821eSShubhankar Kuranagatti */ 5342c608234SMark Brown while (*mode) { 5352c608234SMark Brown if (rdev->constraints->valid_modes_mask & *mode) 536414c70cbSLiam Girdwood return 0; 5372c608234SMark Brown *mode /= 2; 5382c608234SMark Brown } 5392c608234SMark Brown 5402c608234SMark Brown return -EINVAL; 541414c70cbSLiam Girdwood } 542414c70cbSLiam Girdwood 543f7efad10SChunyan Zhang static inline struct regulator_state * 544f7efad10SChunyan Zhang regulator_get_suspend_state(struct regulator_dev *rdev, suspend_state_t state) 545f7efad10SChunyan Zhang { 546f7efad10SChunyan Zhang if (rdev->constraints == NULL) 547f7efad10SChunyan Zhang return NULL; 548f7efad10SChunyan Zhang 549f7efad10SChunyan Zhang switch (state) { 550f7efad10SChunyan Zhang case PM_SUSPEND_STANDBY: 551f7efad10SChunyan Zhang return &rdev->constraints->state_standby; 552f7efad10SChunyan Zhang case PM_SUSPEND_MEM: 553f7efad10SChunyan Zhang return &rdev->constraints->state_mem; 554f7efad10SChunyan Zhang case PM_SUSPEND_MAX: 555f7efad10SChunyan Zhang return &rdev->constraints->state_disk; 556f7efad10SChunyan Zhang default: 557f7efad10SChunyan Zhang return NULL; 558f7efad10SChunyan Zhang } 559f7efad10SChunyan Zhang } 560f7efad10SChunyan Zhang 5610955f5beSStephen Boyd static const struct regulator_state * 5620955f5beSStephen Boyd regulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t state) 5630955f5beSStephen Boyd { 5640955f5beSStephen Boyd const struct regulator_state *rstate; 5650955f5beSStephen Boyd 5660955f5beSStephen Boyd rstate = regulator_get_suspend_state(rdev, state); 5670955f5beSStephen Boyd if (rstate == NULL) 5680955f5beSStephen Boyd return NULL; 5690955f5beSStephen Boyd 5700955f5beSStephen Boyd /* If we have no suspend mode configuration don't set anything; 5710955f5beSStephen Boyd * only warn if the driver implements set_suspend_voltage or 5720955f5beSStephen Boyd * set_suspend_mode callback. 5730955f5beSStephen Boyd */ 5740955f5beSStephen Boyd if (rstate->enabled != ENABLE_IN_SUSPEND && 5750955f5beSStephen Boyd rstate->enabled != DISABLE_IN_SUSPEND) { 5760955f5beSStephen Boyd if (rdev->desc->ops->set_suspend_voltage || 5770955f5beSStephen Boyd rdev->desc->ops->set_suspend_mode) 5780955f5beSStephen Boyd rdev_warn(rdev, "No configuration\n"); 5790955f5beSStephen Boyd return NULL; 5800955f5beSStephen Boyd } 5810955f5beSStephen Boyd 5820955f5beSStephen Boyd return rstate; 5830955f5beSStephen Boyd } 5840955f5beSStephen Boyd 585a277a262SYueHaibing static ssize_t microvolts_show(struct device *dev, 586414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 587414c70cbSLiam Girdwood { 588a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 589c82f27dfSH. Nikolaus Schaller int uV; 590414c70cbSLiam Girdwood 59166cf9a7eSMaciej Purski regulator_lock(rdev); 592c82f27dfSH. Nikolaus Schaller uV = regulator_get_voltage_rdev(rdev); 59366cf9a7eSMaciej Purski regulator_unlock(rdev); 594414c70cbSLiam Girdwood 595c82f27dfSH. Nikolaus Schaller if (uV < 0) 596c82f27dfSH. Nikolaus Schaller return uV; 597c82f27dfSH. Nikolaus Schaller return sprintf(buf, "%d\n", uV); 598414c70cbSLiam Girdwood } 599a277a262SYueHaibing static DEVICE_ATTR_RO(microvolts); 600414c70cbSLiam Girdwood 601a277a262SYueHaibing static ssize_t microamps_show(struct device *dev, 602414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 603414c70cbSLiam Girdwood { 604a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 605414c70cbSLiam Girdwood 606414c70cbSLiam Girdwood return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev)); 607414c70cbSLiam Girdwood } 608a277a262SYueHaibing static DEVICE_ATTR_RO(microamps); 609414c70cbSLiam Girdwood 610587cea27SGreg Kroah-Hartman static ssize_t name_show(struct device *dev, struct device_attribute *attr, 611587cea27SGreg Kroah-Hartman char *buf) 612bc558a60SMark Brown { 613bc558a60SMark Brown struct regulator_dev *rdev = dev_get_drvdata(dev); 614bc558a60SMark Brown 6151083c393SMark Brown return sprintf(buf, "%s\n", rdev_get_name(rdev)); 616bc558a60SMark Brown } 617587cea27SGreg Kroah-Hartman static DEVICE_ATTR_RO(name); 618bc558a60SMark Brown 61901de19d0SDouglas Anderson static const char *regulator_opmode_to_str(int mode) 620414c70cbSLiam Girdwood { 621414c70cbSLiam Girdwood switch (mode) { 622414c70cbSLiam Girdwood case REGULATOR_MODE_FAST: 62301de19d0SDouglas Anderson return "fast"; 624414c70cbSLiam Girdwood case REGULATOR_MODE_NORMAL: 62501de19d0SDouglas Anderson return "normal"; 626414c70cbSLiam Girdwood case REGULATOR_MODE_IDLE: 62701de19d0SDouglas Anderson return "idle"; 628414c70cbSLiam Girdwood case REGULATOR_MODE_STANDBY: 62901de19d0SDouglas Anderson return "standby"; 630414c70cbSLiam Girdwood } 63101de19d0SDouglas Anderson return "unknown"; 63201de19d0SDouglas Anderson } 63301de19d0SDouglas Anderson 63401de19d0SDouglas Anderson static ssize_t regulator_print_opmode(char *buf, int mode) 63501de19d0SDouglas Anderson { 63601de19d0SDouglas Anderson return sprintf(buf, "%s\n", regulator_opmode_to_str(mode)); 637414c70cbSLiam Girdwood } 638414c70cbSLiam Girdwood 639a277a262SYueHaibing static ssize_t opmode_show(struct device *dev, 640414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 641414c70cbSLiam Girdwood { 642a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 643414c70cbSLiam Girdwood 6444fca9545SDavid Brownell return regulator_print_opmode(buf, _regulator_get_mode(rdev)); 6454fca9545SDavid Brownell } 646a277a262SYueHaibing static DEVICE_ATTR_RO(opmode); 6474fca9545SDavid Brownell 6484fca9545SDavid Brownell static ssize_t regulator_print_state(char *buf, int state) 6494fca9545SDavid Brownell { 650414c70cbSLiam Girdwood if (state > 0) 651414c70cbSLiam Girdwood return sprintf(buf, "enabled\n"); 652414c70cbSLiam Girdwood else if (state == 0) 653414c70cbSLiam Girdwood return sprintf(buf, "disabled\n"); 654414c70cbSLiam Girdwood else 655414c70cbSLiam Girdwood return sprintf(buf, "unknown\n"); 656414c70cbSLiam Girdwood } 657414c70cbSLiam Girdwood 658a277a262SYueHaibing static ssize_t state_show(struct device *dev, 6594fca9545SDavid Brownell struct device_attribute *attr, char *buf) 6604fca9545SDavid Brownell { 6614fca9545SDavid Brownell struct regulator_dev *rdev = dev_get_drvdata(dev); 6629332546fSMark Brown ssize_t ret; 6634fca9545SDavid Brownell 66466cf9a7eSMaciej Purski regulator_lock(rdev); 6659332546fSMark Brown ret = regulator_print_state(buf, _regulator_is_enabled(rdev)); 66666cf9a7eSMaciej Purski regulator_unlock(rdev); 6679332546fSMark Brown 6689332546fSMark Brown return ret; 6694fca9545SDavid Brownell } 670a277a262SYueHaibing static DEVICE_ATTR_RO(state); 6714fca9545SDavid Brownell 672a277a262SYueHaibing static ssize_t status_show(struct device *dev, 673853116a1SDavid Brownell struct device_attribute *attr, char *buf) 674853116a1SDavid Brownell { 675853116a1SDavid Brownell struct regulator_dev *rdev = dev_get_drvdata(dev); 676853116a1SDavid Brownell int status; 677853116a1SDavid Brownell char *label; 678853116a1SDavid Brownell 679853116a1SDavid Brownell status = rdev->desc->ops->get_status(rdev); 680853116a1SDavid Brownell if (status < 0) 681853116a1SDavid Brownell return status; 682853116a1SDavid Brownell 683853116a1SDavid Brownell switch (status) { 684853116a1SDavid Brownell case REGULATOR_STATUS_OFF: 685853116a1SDavid Brownell label = "off"; 686853116a1SDavid Brownell break; 687853116a1SDavid Brownell case REGULATOR_STATUS_ON: 688853116a1SDavid Brownell label = "on"; 689853116a1SDavid Brownell break; 690853116a1SDavid Brownell case REGULATOR_STATUS_ERROR: 691853116a1SDavid Brownell label = "error"; 692853116a1SDavid Brownell break; 693853116a1SDavid Brownell case REGULATOR_STATUS_FAST: 694853116a1SDavid Brownell label = "fast"; 695853116a1SDavid Brownell break; 696853116a1SDavid Brownell case REGULATOR_STATUS_NORMAL: 697853116a1SDavid Brownell label = "normal"; 698853116a1SDavid Brownell break; 699853116a1SDavid Brownell case REGULATOR_STATUS_IDLE: 700853116a1SDavid Brownell label = "idle"; 701853116a1SDavid Brownell break; 702853116a1SDavid Brownell case REGULATOR_STATUS_STANDBY: 703853116a1SDavid Brownell label = "standby"; 704853116a1SDavid Brownell break; 705f59c8f9fSMark Brown case REGULATOR_STATUS_BYPASS: 706f59c8f9fSMark Brown label = "bypass"; 707f59c8f9fSMark Brown break; 7081beaf762SKrystian Garbaciak case REGULATOR_STATUS_UNDEFINED: 7091beaf762SKrystian Garbaciak label = "undefined"; 7101beaf762SKrystian Garbaciak break; 711853116a1SDavid Brownell default: 712853116a1SDavid Brownell return -ERANGE; 713853116a1SDavid Brownell } 714853116a1SDavid Brownell 715853116a1SDavid Brownell return sprintf(buf, "%s\n", label); 716853116a1SDavid Brownell } 717a277a262SYueHaibing static DEVICE_ATTR_RO(status); 718853116a1SDavid Brownell 719a277a262SYueHaibing static ssize_t min_microamps_show(struct device *dev, 720414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 721414c70cbSLiam Girdwood { 722a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 723414c70cbSLiam Girdwood 724414c70cbSLiam Girdwood if (!rdev->constraints) 725414c70cbSLiam Girdwood return sprintf(buf, "constraint not defined\n"); 726414c70cbSLiam Girdwood 727414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->min_uA); 728414c70cbSLiam Girdwood } 729a277a262SYueHaibing static DEVICE_ATTR_RO(min_microamps); 730414c70cbSLiam Girdwood 731a277a262SYueHaibing static ssize_t max_microamps_show(struct device *dev, 732414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 733414c70cbSLiam Girdwood { 734a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 735414c70cbSLiam Girdwood 736414c70cbSLiam Girdwood if (!rdev->constraints) 737414c70cbSLiam Girdwood return sprintf(buf, "constraint not defined\n"); 738414c70cbSLiam Girdwood 739414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->max_uA); 740414c70cbSLiam Girdwood } 741a277a262SYueHaibing static DEVICE_ATTR_RO(max_microamps); 742414c70cbSLiam Girdwood 743a277a262SYueHaibing static ssize_t min_microvolts_show(struct device *dev, 744414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 745414c70cbSLiam Girdwood { 746a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 747414c70cbSLiam Girdwood 748414c70cbSLiam Girdwood if (!rdev->constraints) 749414c70cbSLiam Girdwood return sprintf(buf, "constraint not defined\n"); 750414c70cbSLiam Girdwood 751414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->min_uV); 752414c70cbSLiam Girdwood } 753a277a262SYueHaibing static DEVICE_ATTR_RO(min_microvolts); 754414c70cbSLiam Girdwood 755a277a262SYueHaibing static ssize_t max_microvolts_show(struct device *dev, 756414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 757414c70cbSLiam Girdwood { 758a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 759414c70cbSLiam Girdwood 760414c70cbSLiam Girdwood if (!rdev->constraints) 761414c70cbSLiam Girdwood return sprintf(buf, "constraint not defined\n"); 762414c70cbSLiam Girdwood 763414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->max_uV); 764414c70cbSLiam Girdwood } 765a277a262SYueHaibing static DEVICE_ATTR_RO(max_microvolts); 766414c70cbSLiam Girdwood 767a277a262SYueHaibing static ssize_t requested_microamps_show(struct device *dev, 768414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 769414c70cbSLiam Girdwood { 770a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 771414c70cbSLiam Girdwood struct regulator *regulator; 772414c70cbSLiam Girdwood int uA = 0; 773414c70cbSLiam Girdwood 77466cf9a7eSMaciej Purski regulator_lock(rdev); 7755451781dSDouglas Anderson list_for_each_entry(regulator, &rdev->consumer_list, list) { 7765451781dSDouglas Anderson if (regulator->enable_count) 777414c70cbSLiam Girdwood uA += regulator->uA_load; 7785451781dSDouglas Anderson } 77966cf9a7eSMaciej Purski regulator_unlock(rdev); 780414c70cbSLiam Girdwood return sprintf(buf, "%d\n", uA); 781414c70cbSLiam Girdwood } 782a277a262SYueHaibing static DEVICE_ATTR_RO(requested_microamps); 783414c70cbSLiam Girdwood 784587cea27SGreg Kroah-Hartman static ssize_t num_users_show(struct device *dev, struct device_attribute *attr, 785587cea27SGreg Kroah-Hartman char *buf) 786414c70cbSLiam Girdwood { 787a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 788414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->use_count); 789414c70cbSLiam Girdwood } 790587cea27SGreg Kroah-Hartman static DEVICE_ATTR_RO(num_users); 791414c70cbSLiam Girdwood 792587cea27SGreg Kroah-Hartman static ssize_t type_show(struct device *dev, struct device_attribute *attr, 793587cea27SGreg Kroah-Hartman char *buf) 794414c70cbSLiam Girdwood { 795a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 796414c70cbSLiam Girdwood 797414c70cbSLiam Girdwood switch (rdev->desc->type) { 798414c70cbSLiam Girdwood case REGULATOR_VOLTAGE: 799414c70cbSLiam Girdwood return sprintf(buf, "voltage\n"); 800414c70cbSLiam Girdwood case REGULATOR_CURRENT: 801414c70cbSLiam Girdwood return sprintf(buf, "current\n"); 802414c70cbSLiam Girdwood } 803414c70cbSLiam Girdwood return sprintf(buf, "unknown\n"); 804414c70cbSLiam Girdwood } 805587cea27SGreg Kroah-Hartman static DEVICE_ATTR_RO(type); 806414c70cbSLiam Girdwood 807a277a262SYueHaibing static ssize_t suspend_mem_microvolts_show(struct device *dev, 808414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 809414c70cbSLiam Girdwood { 810a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 811414c70cbSLiam Girdwood 812414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV); 813414c70cbSLiam Girdwood } 814a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_mem_microvolts); 815414c70cbSLiam Girdwood 816a277a262SYueHaibing static ssize_t suspend_disk_microvolts_show(struct device *dev, 817414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 818414c70cbSLiam Girdwood { 819a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 820414c70cbSLiam Girdwood 821414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV); 822414c70cbSLiam Girdwood } 823a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_disk_microvolts); 824414c70cbSLiam Girdwood 825a277a262SYueHaibing static ssize_t suspend_standby_microvolts_show(struct device *dev, 826414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 827414c70cbSLiam Girdwood { 828a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 829414c70cbSLiam Girdwood 830414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); 831414c70cbSLiam Girdwood } 832a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_standby_microvolts); 833414c70cbSLiam Girdwood 834a277a262SYueHaibing static ssize_t suspend_mem_mode_show(struct device *dev, 835414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 836414c70cbSLiam Girdwood { 837a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 838414c70cbSLiam Girdwood 8394fca9545SDavid Brownell return regulator_print_opmode(buf, 8404fca9545SDavid Brownell rdev->constraints->state_mem.mode); 841414c70cbSLiam Girdwood } 842a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_mem_mode); 843414c70cbSLiam Girdwood 844a277a262SYueHaibing static ssize_t suspend_disk_mode_show(struct device *dev, 845414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 846414c70cbSLiam Girdwood { 847a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 848414c70cbSLiam Girdwood 8494fca9545SDavid Brownell return regulator_print_opmode(buf, 8504fca9545SDavid Brownell rdev->constraints->state_disk.mode); 851414c70cbSLiam Girdwood } 852a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_disk_mode); 853414c70cbSLiam Girdwood 854a277a262SYueHaibing static ssize_t suspend_standby_mode_show(struct device *dev, 855414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 856414c70cbSLiam Girdwood { 857a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 858414c70cbSLiam Girdwood 8594fca9545SDavid Brownell return regulator_print_opmode(buf, 8604fca9545SDavid Brownell rdev->constraints->state_standby.mode); 861414c70cbSLiam Girdwood } 862a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_standby_mode); 863414c70cbSLiam Girdwood 864a277a262SYueHaibing static ssize_t suspend_mem_state_show(struct device *dev, 865414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 866414c70cbSLiam Girdwood { 867a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 868414c70cbSLiam Girdwood 8694fca9545SDavid Brownell return regulator_print_state(buf, 8704fca9545SDavid Brownell rdev->constraints->state_mem.enabled); 871414c70cbSLiam Girdwood } 872a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_mem_state); 873414c70cbSLiam Girdwood 874a277a262SYueHaibing static ssize_t suspend_disk_state_show(struct device *dev, 875414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 876414c70cbSLiam Girdwood { 877a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 878414c70cbSLiam Girdwood 8794fca9545SDavid Brownell return regulator_print_state(buf, 8804fca9545SDavid Brownell rdev->constraints->state_disk.enabled); 881414c70cbSLiam Girdwood } 882a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_disk_state); 883414c70cbSLiam Girdwood 884a277a262SYueHaibing static ssize_t suspend_standby_state_show(struct device *dev, 885414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 886414c70cbSLiam Girdwood { 887a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 888414c70cbSLiam Girdwood 8894fca9545SDavid Brownell return regulator_print_state(buf, 8904fca9545SDavid Brownell rdev->constraints->state_standby.enabled); 891414c70cbSLiam Girdwood } 892a277a262SYueHaibing static DEVICE_ATTR_RO(suspend_standby_state); 893bc558a60SMark Brown 894a277a262SYueHaibing static ssize_t bypass_show(struct device *dev, 895f59c8f9fSMark Brown struct device_attribute *attr, char *buf) 896f59c8f9fSMark Brown { 897f59c8f9fSMark Brown struct regulator_dev *rdev = dev_get_drvdata(dev); 898f59c8f9fSMark Brown const char *report; 899f59c8f9fSMark Brown bool bypass; 900f59c8f9fSMark Brown int ret; 901f59c8f9fSMark Brown 902f59c8f9fSMark Brown ret = rdev->desc->ops->get_bypass(rdev, &bypass); 903f59c8f9fSMark Brown 904f59c8f9fSMark Brown if (ret != 0) 905f59c8f9fSMark Brown report = "unknown"; 906f59c8f9fSMark Brown else if (bypass) 907f59c8f9fSMark Brown report = "enabled"; 908f59c8f9fSMark Brown else 909f59c8f9fSMark Brown report = "disabled"; 910f59c8f9fSMark Brown 911f59c8f9fSMark Brown return sprintf(buf, "%s\n", report); 912f59c8f9fSMark Brown } 913a277a262SYueHaibing static DEVICE_ATTR_RO(bypass); 9147ad68e2fSDavid Brownell 9150f2d636eSZev Weiss #define REGULATOR_ERROR_ATTR(name, bit) \ 9160f2d636eSZev Weiss static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ 9170f2d636eSZev Weiss char *buf) \ 9180f2d636eSZev Weiss { \ 9190f2d636eSZev Weiss int ret; \ 9200f2d636eSZev Weiss unsigned int flags; \ 9210f2d636eSZev Weiss struct regulator_dev *rdev = dev_get_drvdata(dev); \ 9220f2d636eSZev Weiss ret = _regulator_get_error_flags(rdev, &flags); \ 9230f2d636eSZev Weiss if (ret) \ 9240f2d636eSZev Weiss return ret; \ 9250f2d636eSZev Weiss return sysfs_emit(buf, "%d\n", !!(flags & (bit))); \ 9260f2d636eSZev Weiss } \ 9270f2d636eSZev Weiss static DEVICE_ATTR_RO(name) 9280f2d636eSZev Weiss 9290f2d636eSZev Weiss REGULATOR_ERROR_ATTR(under_voltage, REGULATOR_ERROR_UNDER_VOLTAGE); 9300f2d636eSZev Weiss REGULATOR_ERROR_ATTR(over_current, REGULATOR_ERROR_OVER_CURRENT); 9310f2d636eSZev Weiss REGULATOR_ERROR_ATTR(regulation_out, REGULATOR_ERROR_REGULATION_OUT); 9320f2d636eSZev Weiss REGULATOR_ERROR_ATTR(fail, REGULATOR_ERROR_FAIL); 9330f2d636eSZev Weiss REGULATOR_ERROR_ATTR(over_temp, REGULATOR_ERROR_OVER_TEMP); 9340f2d636eSZev Weiss REGULATOR_ERROR_ATTR(under_voltage_warn, REGULATOR_ERROR_UNDER_VOLTAGE_WARN); 9350f2d636eSZev Weiss REGULATOR_ERROR_ATTR(over_current_warn, REGULATOR_ERROR_OVER_CURRENT_WARN); 9360f2d636eSZev Weiss REGULATOR_ERROR_ATTR(over_voltage_warn, REGULATOR_ERROR_OVER_VOLTAGE_WARN); 9370f2d636eSZev Weiss REGULATOR_ERROR_ATTR(over_temp_warn, REGULATOR_ERROR_OVER_TEMP_WARN); 9380f2d636eSZev Weiss 939414c70cbSLiam Girdwood /* Calculate the new optimum regulator operating mode based on the new total 94069b8821eSShubhankar Kuranagatti * consumer load. All locks held by caller 94169b8821eSShubhankar Kuranagatti */ 9428460ef38SBjorn Andersson static int drms_uA_update(struct regulator_dev *rdev) 943414c70cbSLiam Girdwood { 944414c70cbSLiam Girdwood struct regulator *sibling; 945414c70cbSLiam Girdwood int current_uA = 0, output_uV, input_uV, err; 946414c70cbSLiam Girdwood unsigned int mode; 947414c70cbSLiam Girdwood 9488460ef38SBjorn Andersson /* 9498460ef38SBjorn Andersson * first check to see if we can set modes at all, otherwise just 9508460ef38SBjorn Andersson * tell the consumer everything is OK. 9518460ef38SBjorn Andersson */ 95274a569eeSMarc Gonzalez if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) { 95374a569eeSMarc Gonzalez rdev_dbg(rdev, "DRMS operation not allowed\n"); 9548460ef38SBjorn Andersson return 0; 95574a569eeSMarc Gonzalez } 9568460ef38SBjorn Andersson 9578f4490e0SBjorn Andersson if (!rdev->desc->ops->get_optimum_mode && 9588f4490e0SBjorn Andersson !rdev->desc->ops->set_load) 9598460ef38SBjorn Andersson return 0; 9608460ef38SBjorn Andersson 9618f4490e0SBjorn Andersson if (!rdev->desc->ops->set_mode && 9628f4490e0SBjorn Andersson !rdev->desc->ops->set_load) 9638460ef38SBjorn Andersson return -EINVAL; 964414c70cbSLiam Girdwood 96557776617SJoonwoo Park /* calc total requested load */ 9665451781dSDouglas Anderson list_for_each_entry(sibling, &rdev->consumer_list, list) { 9675451781dSDouglas Anderson if (sibling->enable_count) 96857776617SJoonwoo Park current_uA += sibling->uA_load; 9695451781dSDouglas Anderson } 97057776617SJoonwoo Park 97157776617SJoonwoo Park current_uA += rdev->constraints->system_load; 97257776617SJoonwoo Park 97357776617SJoonwoo Park if (rdev->desc->ops->set_load) { 97457776617SJoonwoo Park /* set the optimum mode for our new total regulator load */ 97557776617SJoonwoo Park err = rdev->desc->ops->set_load(rdev, current_uA); 97657776617SJoonwoo Park if (err < 0) 97761aab5adSMichał Mirosław rdev_err(rdev, "failed to set load %d: %pe\n", 97861aab5adSMichał Mirosław current_uA, ERR_PTR(err)); 97957776617SJoonwoo Park } else { 98057919f4aSDouglas Anderson /* 98157919f4aSDouglas Anderson * Unfortunately in some cases the constraints->valid_ops has 98257919f4aSDouglas Anderson * REGULATOR_CHANGE_DRMS but there are no valid modes listed. 98357919f4aSDouglas Anderson * That's not really legit but we won't consider it a fatal 98457919f4aSDouglas Anderson * error here. We'll treat it as if REGULATOR_CHANGE_DRMS 98557919f4aSDouglas Anderson * wasn't set. 98657919f4aSDouglas Anderson */ 98757919f4aSDouglas Anderson if (!rdev->constraints->valid_modes_mask) { 98857919f4aSDouglas Anderson rdev_dbg(rdev, "Can change modes; but no valid mode\n"); 98957919f4aSDouglas Anderson return 0; 99057919f4aSDouglas Anderson } 99157919f4aSDouglas Anderson 992414c70cbSLiam Girdwood /* get output voltage */ 993d22b85a1SDmitry Osipenko output_uV = regulator_get_voltage_rdev(rdev); 99455841199SDouglas Anderson 99555841199SDouglas Anderson /* 99655841199SDouglas Anderson * Don't return an error; if regulator driver cares about 99755841199SDouglas Anderson * output_uV then it's up to the driver to validate. 99855841199SDouglas Anderson */ 99955841199SDouglas Anderson if (output_uV <= 0) 100055841199SDouglas Anderson rdev_dbg(rdev, "invalid output voltage found\n"); 1001414c70cbSLiam Girdwood 1002414c70cbSLiam Girdwood /* get input voltage */ 10031bf5a1f8SMark Brown input_uV = 0; 10041bf5a1f8SMark Brown if (rdev->supply) 10053f24f5adSAxel Lin input_uV = regulator_get_voltage(rdev->supply); 10061bf5a1f8SMark Brown if (input_uV <= 0) 1007414c70cbSLiam Girdwood input_uV = rdev->constraints->input_uV; 100855841199SDouglas Anderson 100955841199SDouglas Anderson /* 101055841199SDouglas Anderson * Don't return an error; if regulator driver cares about 101155841199SDouglas Anderson * input_uV then it's up to the driver to validate. 101255841199SDouglas Anderson */ 101355841199SDouglas Anderson if (input_uV <= 0) 101455841199SDouglas Anderson rdev_dbg(rdev, "invalid input voltage found\n"); 1015414c70cbSLiam Girdwood 1016414c70cbSLiam Girdwood /* now get the optimum mode for our new total regulator load */ 1017414c70cbSLiam Girdwood mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, 1018414c70cbSLiam Girdwood output_uV, current_uA); 1019414c70cbSLiam Girdwood 1020414c70cbSLiam Girdwood /* check the new mode is allowed */ 10212c608234SMark Brown err = regulator_mode_constrain(rdev, &mode); 10228460ef38SBjorn Andersson if (err < 0) { 102361aab5adSMichał Mirosław rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV: %pe\n", 102461aab5adSMichał Mirosław current_uA, input_uV, output_uV, ERR_PTR(err)); 10258460ef38SBjorn Andersson return err; 10268460ef38SBjorn Andersson } 10278460ef38SBjorn Andersson 10288460ef38SBjorn Andersson err = rdev->desc->ops->set_mode(rdev, mode); 10298460ef38SBjorn Andersson if (err < 0) 103061aab5adSMichał Mirosław rdev_err(rdev, "failed to set optimum mode %x: %pe\n", 103161aab5adSMichał Mirosław mode, ERR_PTR(err)); 10328f4490e0SBjorn Andersson } 10338460ef38SBjorn Andersson 10348460ef38SBjorn Andersson return err; 1035414c70cbSLiam Girdwood } 1036414c70cbSLiam Girdwood 10370955f5beSStephen Boyd static int __suspend_set_state(struct regulator_dev *rdev, 10380955f5beSStephen Boyd const struct regulator_state *rstate) 1039414c70cbSLiam Girdwood { 1040414c70cbSLiam Girdwood int ret = 0; 1041638f85c5SMark Brown 104272069f99SChunyan Zhang if (rstate->enabled == ENABLE_IN_SUSPEND && 104372069f99SChunyan Zhang rdev->desc->ops->set_suspend_enable) 1044414c70cbSLiam Girdwood ret = rdev->desc->ops->set_suspend_enable(rdev); 104572069f99SChunyan Zhang else if (rstate->enabled == DISABLE_IN_SUSPEND && 104672069f99SChunyan Zhang rdev->desc->ops->set_suspend_disable) 1047414c70cbSLiam Girdwood ret = rdev->desc->ops->set_suspend_disable(rdev); 10488ac0e95dSAxel Lin else /* OK if set_suspend_enable or set_suspend_disable is NULL */ 10498ac0e95dSAxel Lin ret = 0; 10508ac0e95dSAxel Lin 1051414c70cbSLiam Girdwood if (ret < 0) { 105261aab5adSMichał Mirosław rdev_err(rdev, "failed to enabled/disable: %pe\n", ERR_PTR(ret)); 1053414c70cbSLiam Girdwood return ret; 1054414c70cbSLiam Girdwood } 1055414c70cbSLiam Girdwood 1056414c70cbSLiam Girdwood if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { 1057414c70cbSLiam Girdwood ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); 1058414c70cbSLiam Girdwood if (ret < 0) { 105961aab5adSMichał Mirosław rdev_err(rdev, "failed to set voltage: %pe\n", ERR_PTR(ret)); 1060414c70cbSLiam Girdwood return ret; 1061414c70cbSLiam Girdwood } 1062414c70cbSLiam Girdwood } 1063414c70cbSLiam Girdwood 1064414c70cbSLiam Girdwood if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { 1065414c70cbSLiam Girdwood ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); 1066414c70cbSLiam Girdwood if (ret < 0) { 106761aab5adSMichał Mirosław rdev_err(rdev, "failed to set mode: %pe\n", ERR_PTR(ret)); 1068414c70cbSLiam Girdwood return ret; 1069414c70cbSLiam Girdwood } 1070414c70cbSLiam Girdwood } 1071f7efad10SChunyan Zhang 1072414c70cbSLiam Girdwood return ret; 1073414c70cbSLiam Girdwood } 1074414c70cbSLiam Girdwood 10750955f5beSStephen Boyd static int suspend_set_initial_state(struct regulator_dev *rdev) 10760955f5beSStephen Boyd { 10770955f5beSStephen Boyd const struct regulator_state *rstate; 10780955f5beSStephen Boyd 10790955f5beSStephen Boyd rstate = regulator_get_suspend_state_check(rdev, 10800955f5beSStephen Boyd rdev->constraints->initial_state); 10810955f5beSStephen Boyd if (!rstate) 10820955f5beSStephen Boyd return 0; 10830955f5beSStephen Boyd 10840955f5beSStephen Boyd return __suspend_set_state(rdev, rstate); 10850955f5beSStephen Boyd } 10860955f5beSStephen Boyd 1087c845f21aSGeert Uytterhoeven #if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) 1088c845f21aSGeert Uytterhoeven static void print_constraints_debug(struct regulator_dev *rdev) 1089414c70cbSLiam Girdwood { 1090414c70cbSLiam Girdwood struct regulation_constraints *constraints = rdev->constraints; 1091a7068e39SStefan Wahren char buf[160] = ""; 10925751a99fSStefan Wahren size_t len = sizeof(buf) - 1; 10938f031b48SMark Brown int count = 0; 10948f031b48SMark Brown int ret; 1095414c70cbSLiam Girdwood 10968f031b48SMark Brown if (constraints->min_uV && constraints->max_uV) { 1097414c70cbSLiam Girdwood if (constraints->min_uV == constraints->max_uV) 10985751a99fSStefan Wahren count += scnprintf(buf + count, len - count, "%d mV ", 1099414c70cbSLiam Girdwood constraints->min_uV / 1000); 1100414c70cbSLiam Girdwood else 11015751a99fSStefan Wahren count += scnprintf(buf + count, len - count, 11025751a99fSStefan Wahren "%d <--> %d mV ", 1103414c70cbSLiam Girdwood constraints->min_uV / 1000, 1104414c70cbSLiam Girdwood constraints->max_uV / 1000); 11058f031b48SMark Brown } 11068f031b48SMark Brown 11078f031b48SMark Brown if (!constraints->min_uV || 11088f031b48SMark Brown constraints->min_uV != constraints->max_uV) { 1109d22b85a1SDmitry Osipenko ret = regulator_get_voltage_rdev(rdev); 11108f031b48SMark Brown if (ret > 0) 11115751a99fSStefan Wahren count += scnprintf(buf + count, len - count, 11125751a99fSStefan Wahren "at %d mV ", ret / 1000); 11138f031b48SMark Brown } 11148f031b48SMark Brown 1115bf5892a8SMark Brown if (constraints->uV_offset) 11165751a99fSStefan Wahren count += scnprintf(buf + count, len - count, "%dmV offset ", 1117bf5892a8SMark Brown constraints->uV_offset / 1000); 1118bf5892a8SMark Brown 11198f031b48SMark Brown if (constraints->min_uA && constraints->max_uA) { 1120414c70cbSLiam Girdwood if (constraints->min_uA == constraints->max_uA) 11215751a99fSStefan Wahren count += scnprintf(buf + count, len - count, "%d mA ", 1122414c70cbSLiam Girdwood constraints->min_uA / 1000); 1123414c70cbSLiam Girdwood else 11245751a99fSStefan Wahren count += scnprintf(buf + count, len - count, 11255751a99fSStefan Wahren "%d <--> %d mA ", 1126414c70cbSLiam Girdwood constraints->min_uA / 1000, 1127414c70cbSLiam Girdwood constraints->max_uA / 1000); 1128414c70cbSLiam Girdwood } 11298f031b48SMark Brown 11308f031b48SMark Brown if (!constraints->min_uA || 11318f031b48SMark Brown constraints->min_uA != constraints->max_uA) { 11328f031b48SMark Brown ret = _regulator_get_current_limit(rdev); 11338f031b48SMark Brown if (ret > 0) 11345751a99fSStefan Wahren count += scnprintf(buf + count, len - count, 11355751a99fSStefan Wahren "at %d mA ", ret / 1000); 11368f031b48SMark Brown } 11378f031b48SMark Brown 1138414c70cbSLiam Girdwood if (constraints->valid_modes_mask & REGULATOR_MODE_FAST) 11395751a99fSStefan Wahren count += scnprintf(buf + count, len - count, "fast "); 1140414c70cbSLiam Girdwood if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL) 11415751a99fSStefan Wahren count += scnprintf(buf + count, len - count, "normal "); 1142414c70cbSLiam Girdwood if (constraints->valid_modes_mask & REGULATOR_MODE_IDLE) 11435751a99fSStefan Wahren count += scnprintf(buf + count, len - count, "idle "); 1144414c70cbSLiam Girdwood if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) 11455751a99fSStefan Wahren count += scnprintf(buf + count, len - count, "standby "); 1146414c70cbSLiam Girdwood 1147215b8b05SUwe Kleine-König if (!count) 114899ad5f6eSMichał Mirosław count = scnprintf(buf, len, "no parameters"); 114999ad5f6eSMichał Mirosław else 115099ad5f6eSMichał Mirosław --count; 115199ad5f6eSMichał Mirosław 115299ad5f6eSMichał Mirosław count += scnprintf(buf + count, len - count, ", %s", 115399ad5f6eSMichał Mirosław _regulator_is_enabled(rdev) ? "enabled" : "disabled"); 1154215b8b05SUwe Kleine-König 1155194dbaefSMark Brown rdev_dbg(rdev, "%s\n", buf); 1156c845f21aSGeert Uytterhoeven } 1157c845f21aSGeert Uytterhoeven #else /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */ 1158c845f21aSGeert Uytterhoeven static inline void print_constraints_debug(struct regulator_dev *rdev) {} 1159c845f21aSGeert Uytterhoeven #endif /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */ 1160c845f21aSGeert Uytterhoeven 1161c845f21aSGeert Uytterhoeven static void print_constraints(struct regulator_dev *rdev) 1162c845f21aSGeert Uytterhoeven { 1163c845f21aSGeert Uytterhoeven struct regulation_constraints *constraints = rdev->constraints; 1164c845f21aSGeert Uytterhoeven 1165c845f21aSGeert Uytterhoeven print_constraints_debug(rdev); 11664a682922SMark Brown 11674a682922SMark Brown if ((constraints->min_uV != constraints->max_uV) && 11688a34e979SWEN Pingbo !regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) 11694a682922SMark Brown rdev_warn(rdev, 11704a682922SMark Brown "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); 1171414c70cbSLiam Girdwood } 1172414c70cbSLiam Girdwood 1173e79055d6SMark Brown static int machine_constraints_voltage(struct regulator_dev *rdev, 11741083c393SMark Brown struct regulation_constraints *constraints) 1175e79055d6SMark Brown { 1176272e2315SGuodong Xu const struct regulator_ops *ops = rdev->desc->ops; 1177af5866c9SMark Brown int ret; 1178af5866c9SMark Brown 1179af5866c9SMark Brown /* do we need to apply the constraint voltage */ 1180af5866c9SMark Brown if (rdev->constraints->apply_uV && 1181fa93fd4eSMark Brown rdev->constraints->min_uV && rdev->constraints->max_uV) { 1182fa93fd4eSMark Brown int target_min, target_max; 1183d22b85a1SDmitry Osipenko int current_uV = regulator_get_voltage_rdev(rdev); 118484b3a7c9SDouglas Anderson 118584b3a7c9SDouglas Anderson if (current_uV == -ENOTRECOVERABLE) { 118648f1b4efSKrzysztof Kozlowski /* This regulator can't be read and must be initialized */ 118784b3a7c9SDouglas Anderson rdev_info(rdev, "Setting %d-%duV\n", 118884b3a7c9SDouglas Anderson rdev->constraints->min_uV, 118984b3a7c9SDouglas Anderson rdev->constraints->max_uV); 119084b3a7c9SDouglas Anderson _regulator_do_set_voltage(rdev, 119184b3a7c9SDouglas Anderson rdev->constraints->min_uV, 119284b3a7c9SDouglas Anderson rdev->constraints->max_uV); 1193d22b85a1SDmitry Osipenko current_uV = regulator_get_voltage_rdev(rdev); 119484b3a7c9SDouglas Anderson } 119584b3a7c9SDouglas Anderson 1196064d5cd1SAlban Bedel if (current_uV < 0) { 1197adea2831SBrian Norris if (current_uV != -EPROBE_DEFER) 119869d58839SNishanth Menon rdev_err(rdev, 119961aab5adSMichał Mirosław "failed to get the current voltage: %pe\n", 120061aab5adSMichał Mirosław ERR_PTR(current_uV)); 1201064d5cd1SAlban Bedel return current_uV; 1202064d5cd1SAlban Bedel } 1203fa93fd4eSMark Brown 1204fa93fd4eSMark Brown /* 1205fa93fd4eSMark Brown * If we're below the minimum voltage move up to the 1206fa93fd4eSMark Brown * minimum voltage, if we're above the maximum voltage 1207fa93fd4eSMark Brown * then move down to the maximum. 1208fa93fd4eSMark Brown */ 1209fa93fd4eSMark Brown target_min = current_uV; 1210fa93fd4eSMark Brown target_max = current_uV; 1211fa93fd4eSMark Brown 1212fa93fd4eSMark Brown if (current_uV < rdev->constraints->min_uV) { 1213fa93fd4eSMark Brown target_min = rdev->constraints->min_uV; 1214fa93fd4eSMark Brown target_max = rdev->constraints->min_uV; 1215fa93fd4eSMark Brown } 1216fa93fd4eSMark Brown 1217fa93fd4eSMark Brown if (current_uV > rdev->constraints->max_uV) { 1218fa93fd4eSMark Brown target_min = rdev->constraints->max_uV; 1219fa93fd4eSMark Brown target_max = rdev->constraints->max_uV; 1220fa93fd4eSMark Brown } 1221fa93fd4eSMark Brown 1222fa93fd4eSMark Brown if (target_min != current_uV || target_max != current_uV) { 122345a91e8fSMark Brown rdev_info(rdev, "Bringing %duV into %d-%duV\n", 122445a91e8fSMark Brown current_uV, target_min, target_max); 1225064d5cd1SAlban Bedel ret = _regulator_do_set_voltage( 1226fa93fd4eSMark Brown rdev, target_min, target_max); 1227af5866c9SMark Brown if (ret < 0) { 1228064d5cd1SAlban Bedel rdev_err(rdev, 122961aab5adSMichał Mirosław "failed to apply %d-%duV constraint: %pe\n", 123061aab5adSMichał Mirosław target_min, target_max, ERR_PTR(ret)); 1231af5866c9SMark Brown return ret; 1232af5866c9SMark Brown } 1233af5866c9SMark Brown } 1234064d5cd1SAlban Bedel } 1235e79055d6SMark Brown 1236e79055d6SMark Brown /* constrain machine-level voltage specs to fit 1237e79055d6SMark Brown * the actual range supported by this regulator. 1238e79055d6SMark Brown */ 1239e79055d6SMark Brown if (ops->list_voltage && rdev->desc->n_voltages) { 1240e79055d6SMark Brown int count = rdev->desc->n_voltages; 1241e79055d6SMark Brown int i; 1242e79055d6SMark Brown int min_uV = INT_MAX; 1243e79055d6SMark Brown int max_uV = INT_MIN; 1244e79055d6SMark Brown int cmin = constraints->min_uV; 1245e79055d6SMark Brown int cmax = constraints->max_uV; 1246e79055d6SMark Brown 1247e79055d6SMark Brown /* it's safe to autoconfigure fixed-voltage supplies 124869b8821eSShubhankar Kuranagatti * and the constraints are used by list_voltage. 124969b8821eSShubhankar Kuranagatti */ 1250e79055d6SMark Brown if (count == 1 && !cmin) { 1251e79055d6SMark Brown cmin = 1; 1252e79055d6SMark Brown cmax = INT_MAX; 1253e79055d6SMark Brown constraints->min_uV = cmin; 1254e79055d6SMark Brown constraints->max_uV = cmax; 1255e79055d6SMark Brown } 1256e79055d6SMark Brown 1257e79055d6SMark Brown /* voltage constraints are optional */ 1258e79055d6SMark Brown if ((cmin == 0) && (cmax == 0)) 1259e79055d6SMark Brown return 0; 1260e79055d6SMark Brown 1261e79055d6SMark Brown /* else require explicit machine-level constraints */ 1262e79055d6SMark Brown if (cmin <= 0 || cmax <= 0 || cmax < cmin) { 12635da84fd9SJoe Perches rdev_err(rdev, "invalid voltage constraints\n"); 1264e79055d6SMark Brown return -EINVAL; 1265e79055d6SMark Brown } 1266e79055d6SMark Brown 12676d30fc51SCristian Marussi /* no need to loop voltages if range is continuous */ 12686d30fc51SCristian Marussi if (rdev->desc->continuous_voltage_range) 12696d30fc51SCristian Marussi return 0; 12706d30fc51SCristian Marussi 1271e79055d6SMark Brown /* initial: [cmin..cmax] valid, [min_uV..max_uV] not */ 1272e79055d6SMark Brown for (i = 0; i < count; i++) { 1273e79055d6SMark Brown int value; 1274e79055d6SMark Brown 1275e79055d6SMark Brown value = ops->list_voltage(rdev, i); 1276e79055d6SMark Brown if (value <= 0) 1277e79055d6SMark Brown continue; 1278e79055d6SMark Brown 1279e79055d6SMark Brown /* maybe adjust [min_uV..max_uV] */ 1280e79055d6SMark Brown if (value >= cmin && value < min_uV) 1281e79055d6SMark Brown min_uV = value; 1282e79055d6SMark Brown if (value <= cmax && value > max_uV) 1283e79055d6SMark Brown max_uV = value; 1284e79055d6SMark Brown } 1285e79055d6SMark Brown 1286e79055d6SMark Brown /* final: [min_uV..max_uV] valid iff constraints valid */ 1287e79055d6SMark Brown if (max_uV < min_uV) { 1288fff15befSMark Brown rdev_err(rdev, 1289fff15befSMark Brown "unsupportable voltage constraints %u-%uuV\n", 1290fff15befSMark Brown min_uV, max_uV); 1291e79055d6SMark Brown return -EINVAL; 1292e79055d6SMark Brown } 1293e79055d6SMark Brown 1294e79055d6SMark Brown /* use regulator's subset of machine constraints */ 1295e79055d6SMark Brown if (constraints->min_uV < min_uV) { 12965da84fd9SJoe Perches rdev_dbg(rdev, "override min_uV, %d -> %d\n", 12975da84fd9SJoe Perches constraints->min_uV, min_uV); 1298e79055d6SMark Brown constraints->min_uV = min_uV; 1299e79055d6SMark Brown } 1300e79055d6SMark Brown if (constraints->max_uV > max_uV) { 13015da84fd9SJoe Perches rdev_dbg(rdev, "override max_uV, %d -> %d\n", 13025da84fd9SJoe Perches constraints->max_uV, max_uV); 1303e79055d6SMark Brown constraints->max_uV = max_uV; 1304e79055d6SMark Brown } 1305e79055d6SMark Brown } 1306e79055d6SMark Brown 1307e79055d6SMark Brown return 0; 1308e79055d6SMark Brown } 1309e79055d6SMark Brown 1310f8c1700dSLaxman Dewangan static int machine_constraints_current(struct regulator_dev *rdev, 1311f8c1700dSLaxman Dewangan struct regulation_constraints *constraints) 1312f8c1700dSLaxman Dewangan { 1313272e2315SGuodong Xu const struct regulator_ops *ops = rdev->desc->ops; 1314f8c1700dSLaxman Dewangan int ret; 1315f8c1700dSLaxman Dewangan 1316f8c1700dSLaxman Dewangan if (!constraints->min_uA && !constraints->max_uA) 1317f8c1700dSLaxman Dewangan return 0; 1318f8c1700dSLaxman Dewangan 1319f8c1700dSLaxman Dewangan if (constraints->min_uA > constraints->max_uA) { 1320f8c1700dSLaxman Dewangan rdev_err(rdev, "Invalid current constraints\n"); 1321f8c1700dSLaxman Dewangan return -EINVAL; 1322f8c1700dSLaxman Dewangan } 1323f8c1700dSLaxman Dewangan 1324f8c1700dSLaxman Dewangan if (!ops->set_current_limit || !ops->get_current_limit) { 1325f8c1700dSLaxman Dewangan rdev_warn(rdev, "Operation of current configuration missing\n"); 1326f8c1700dSLaxman Dewangan return 0; 1327f8c1700dSLaxman Dewangan } 1328f8c1700dSLaxman Dewangan 1329f8c1700dSLaxman Dewangan /* Set regulator current in constraints range */ 1330f8c1700dSLaxman Dewangan ret = ops->set_current_limit(rdev, constraints->min_uA, 1331f8c1700dSLaxman Dewangan constraints->max_uA); 1332f8c1700dSLaxman Dewangan if (ret < 0) { 1333f8c1700dSLaxman Dewangan rdev_err(rdev, "Failed to set current constraint, %d\n", ret); 1334f8c1700dSLaxman Dewangan return ret; 1335f8c1700dSLaxman Dewangan } 1336f8c1700dSLaxman Dewangan 1337f8c1700dSLaxman Dewangan return 0; 1338f8c1700dSLaxman Dewangan } 1339f8c1700dSLaxman Dewangan 134030c21971SMarkus Pargmann static int _regulator_do_enable(struct regulator_dev *rdev); 134130c21971SMarkus Pargmann 134289a6a5e5SMatti Vaittinen static int notif_set_limit(struct regulator_dev *rdev, 134389a6a5e5SMatti Vaittinen int (*set)(struct regulator_dev *, int, int, bool), 134489a6a5e5SMatti Vaittinen int limit, int severity) 134589a6a5e5SMatti Vaittinen { 134689a6a5e5SMatti Vaittinen bool enable; 134789a6a5e5SMatti Vaittinen 134889a6a5e5SMatti Vaittinen if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) { 134989a6a5e5SMatti Vaittinen enable = false; 135089a6a5e5SMatti Vaittinen limit = 0; 135189a6a5e5SMatti Vaittinen } else { 135289a6a5e5SMatti Vaittinen enable = true; 135389a6a5e5SMatti Vaittinen } 135489a6a5e5SMatti Vaittinen 135589a6a5e5SMatti Vaittinen if (limit == REGULATOR_NOTIF_LIMIT_ENABLE) 135689a6a5e5SMatti Vaittinen limit = 0; 135789a6a5e5SMatti Vaittinen 135889a6a5e5SMatti Vaittinen return set(rdev, limit, severity, enable); 135989a6a5e5SMatti Vaittinen } 136089a6a5e5SMatti Vaittinen 136189a6a5e5SMatti Vaittinen static int handle_notify_limits(struct regulator_dev *rdev, 136289a6a5e5SMatti Vaittinen int (*set)(struct regulator_dev *, int, int, bool), 136389a6a5e5SMatti Vaittinen struct notification_limit *limits) 136489a6a5e5SMatti Vaittinen { 136589a6a5e5SMatti Vaittinen int ret = 0; 136689a6a5e5SMatti Vaittinen 136789a6a5e5SMatti Vaittinen if (!set) 136889a6a5e5SMatti Vaittinen return -EOPNOTSUPP; 136989a6a5e5SMatti Vaittinen 137089a6a5e5SMatti Vaittinen if (limits->prot) 137189a6a5e5SMatti Vaittinen ret = notif_set_limit(rdev, set, limits->prot, 137289a6a5e5SMatti Vaittinen REGULATOR_SEVERITY_PROT); 137389a6a5e5SMatti Vaittinen if (ret) 137489a6a5e5SMatti Vaittinen return ret; 137589a6a5e5SMatti Vaittinen 137689a6a5e5SMatti Vaittinen if (limits->err) 137789a6a5e5SMatti Vaittinen ret = notif_set_limit(rdev, set, limits->err, 137889a6a5e5SMatti Vaittinen REGULATOR_SEVERITY_ERR); 137989a6a5e5SMatti Vaittinen if (ret) 138089a6a5e5SMatti Vaittinen return ret; 138189a6a5e5SMatti Vaittinen 138289a6a5e5SMatti Vaittinen if (limits->warn) 138389a6a5e5SMatti Vaittinen ret = notif_set_limit(rdev, set, limits->warn, 138489a6a5e5SMatti Vaittinen REGULATOR_SEVERITY_WARN); 138589a6a5e5SMatti Vaittinen 138689a6a5e5SMatti Vaittinen return ret; 138789a6a5e5SMatti Vaittinen } 1388a5766f11SLiam Girdwood /** 1389a5766f11SLiam Girdwood * set_machine_constraints - sets regulator constraints 139069279fb9SMark Brown * @rdev: regulator source 1391a5766f11SLiam Girdwood * 1392a5766f11SLiam Girdwood * Allows platform initialisation code to define and constrain 1393a5766f11SLiam Girdwood * regulator circuits e.g. valid voltage/current ranges, etc. NOTE: 1394a5766f11SLiam Girdwood * Constraints *must* be set by platform code in order for some 1395a5766f11SLiam Girdwood * regulator operations to proceed i.e. set_voltage, set_current_limit, 1396a5766f11SLiam Girdwood * set_mode. 1397a5766f11SLiam Girdwood */ 139857a6ad48SMichał Mirosław static int set_machine_constraints(struct regulator_dev *rdev) 1399a5766f11SLiam Girdwood { 1400a5766f11SLiam Girdwood int ret = 0; 1401272e2315SGuodong Xu const struct regulator_ops *ops = rdev->desc->ops; 1402e06f5b4fSMark Brown 1403f8c12fe3SMark Brown ret = machine_constraints_voltage(rdev, rdev->constraints); 1404e79055d6SMark Brown if (ret != 0) 14056333ef46SCharles Keepax return ret; 14063e2b9abdSMark Brown 1407f8c1700dSLaxman Dewangan ret = machine_constraints_current(rdev, rdev->constraints); 1408f8c1700dSLaxman Dewangan if (ret != 0) 14096333ef46SCharles Keepax return ret; 1410f8c1700dSLaxman Dewangan 141136e4f839SStephen Boyd if (rdev->constraints->ilim_uA && ops->set_input_current_limit) { 141236e4f839SStephen Boyd ret = ops->set_input_current_limit(rdev, 141336e4f839SStephen Boyd rdev->constraints->ilim_uA); 141436e4f839SStephen Boyd if (ret < 0) { 141561aab5adSMichał Mirosław rdev_err(rdev, "failed to set input limit: %pe\n", ERR_PTR(ret)); 14166333ef46SCharles Keepax return ret; 141736e4f839SStephen Boyd } 141836e4f839SStephen Boyd } 141936e4f839SStephen Boyd 1420a5766f11SLiam Girdwood /* do we need to setup our suspend state */ 14219a8f5e07SMark Brown if (rdev->constraints->initial_state) { 14220955f5beSStephen Boyd ret = suspend_set_initial_state(rdev); 1423e06f5b4fSMark Brown if (ret < 0) { 142461aab5adSMichał Mirosław rdev_err(rdev, "failed to set suspend state: %pe\n", ERR_PTR(ret)); 14256333ef46SCharles Keepax return ret; 1426e06f5b4fSMark Brown } 1427e06f5b4fSMark Brown } 1428a5766f11SLiam Girdwood 14299a8f5e07SMark Brown if (rdev->constraints->initial_mode) { 1430a308466cSMark Brown if (!ops->set_mode) { 14315da84fd9SJoe Perches rdev_err(rdev, "no set_mode operation\n"); 14326333ef46SCharles Keepax return -EINVAL; 1433a308466cSMark Brown } 1434a308466cSMark Brown 1435f8c12fe3SMark Brown ret = ops->set_mode(rdev, rdev->constraints->initial_mode); 1436a308466cSMark Brown if (ret < 0) { 143761aab5adSMichał Mirosław rdev_err(rdev, "failed to set initial mode: %pe\n", ERR_PTR(ret)); 14386333ef46SCharles Keepax return ret; 1439a308466cSMark Brown } 1440fa94e48eSDouglas Anderson } else if (rdev->constraints->system_load) { 1441fa94e48eSDouglas Anderson /* 1442fa94e48eSDouglas Anderson * We'll only apply the initial system load if an 1443fa94e48eSDouglas Anderson * initial mode wasn't specified. 1444fa94e48eSDouglas Anderson */ 1445fa94e48eSDouglas Anderson drms_uA_update(rdev); 1446a308466cSMark Brown } 1447a308466cSMark Brown 14481653ccf4SYadwinder Singh Brar if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable) 14491653ccf4SYadwinder Singh Brar && ops->set_ramp_delay) { 14506f0b2c69SYadwinder Singh Brar ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay); 14516f0b2c69SYadwinder Singh Brar if (ret < 0) { 145261aab5adSMichał Mirosław rdev_err(rdev, "failed to set ramp_delay: %pe\n", ERR_PTR(ret)); 14536333ef46SCharles Keepax return ret; 14546f0b2c69SYadwinder Singh Brar } 14556f0b2c69SYadwinder Singh Brar } 14566f0b2c69SYadwinder Singh Brar 145723c779b9SStephen Boyd if (rdev->constraints->pull_down && ops->set_pull_down) { 145823c779b9SStephen Boyd ret = ops->set_pull_down(rdev); 145923c779b9SStephen Boyd if (ret < 0) { 146061aab5adSMichał Mirosław rdev_err(rdev, "failed to set pull down: %pe\n", ERR_PTR(ret)); 14616333ef46SCharles Keepax return ret; 146223c779b9SStephen Boyd } 146323c779b9SStephen Boyd } 146423c779b9SStephen Boyd 146557f66b78SStephen Boyd if (rdev->constraints->soft_start && ops->set_soft_start) { 146657f66b78SStephen Boyd ret = ops->set_soft_start(rdev); 146757f66b78SStephen Boyd if (ret < 0) { 146861aab5adSMichał Mirosław rdev_err(rdev, "failed to set soft start: %pe\n", ERR_PTR(ret)); 14696333ef46SCharles Keepax return ret; 147057f66b78SStephen Boyd } 147157f66b78SStephen Boyd } 147257f66b78SStephen Boyd 147389a6a5e5SMatti Vaittinen /* 147489a6a5e5SMatti Vaittinen * Existing logic does not warn if over_current_protection is given as 147589a6a5e5SMatti Vaittinen * a constraint but driver does not support that. I think we should 147689a6a5e5SMatti Vaittinen * warn about this type of issues as it is possible someone changes 147789a6a5e5SMatti Vaittinen * PMIC on board to another type - and the another PMIC's driver does 147889a6a5e5SMatti Vaittinen * not support setting protection. Board composer may happily believe 147989a6a5e5SMatti Vaittinen * the DT limits are respected - especially if the new PMIC HW also 148089a6a5e5SMatti Vaittinen * supports protection but the driver does not. I won't change the logic 148189a6a5e5SMatti Vaittinen * without hearing more experienced opinion on this though. 148289a6a5e5SMatti Vaittinen * 148389a6a5e5SMatti Vaittinen * If warning is seen as a good idea then we can merge handling the 148489a6a5e5SMatti Vaittinen * over-curret protection and detection and get rid of this special 148589a6a5e5SMatti Vaittinen * handling. 148689a6a5e5SMatti Vaittinen */ 14873a003baeSStephen Boyd if (rdev->constraints->over_current_protection 14883a003baeSStephen Boyd && ops->set_over_current_protection) { 148989a6a5e5SMatti Vaittinen int lim = rdev->constraints->over_curr_limits.prot; 149089a6a5e5SMatti Vaittinen 149189a6a5e5SMatti Vaittinen ret = ops->set_over_current_protection(rdev, lim, 149289a6a5e5SMatti Vaittinen REGULATOR_SEVERITY_PROT, 149389a6a5e5SMatti Vaittinen true); 14943a003baeSStephen Boyd if (ret < 0) { 149561aab5adSMichał Mirosław rdev_err(rdev, "failed to set over current protection: %pe\n", 149661aab5adSMichał Mirosław ERR_PTR(ret)); 14976333ef46SCharles Keepax return ret; 14983a003baeSStephen Boyd } 14993a003baeSStephen Boyd } 15003a003baeSStephen Boyd 150189a6a5e5SMatti Vaittinen if (rdev->constraints->over_current_detection) 150289a6a5e5SMatti Vaittinen ret = handle_notify_limits(rdev, 150389a6a5e5SMatti Vaittinen ops->set_over_current_protection, 150489a6a5e5SMatti Vaittinen &rdev->constraints->over_curr_limits); 150589a6a5e5SMatti Vaittinen if (ret) { 150689a6a5e5SMatti Vaittinen if (ret != -EOPNOTSUPP) { 150789a6a5e5SMatti Vaittinen rdev_err(rdev, "failed to set over current limits: %pe\n", 150889a6a5e5SMatti Vaittinen ERR_PTR(ret)); 150989a6a5e5SMatti Vaittinen return ret; 151089a6a5e5SMatti Vaittinen } 151189a6a5e5SMatti Vaittinen rdev_warn(rdev, 151289a6a5e5SMatti Vaittinen "IC does not support requested over-current limits\n"); 151389a6a5e5SMatti Vaittinen } 151489a6a5e5SMatti Vaittinen 151589a6a5e5SMatti Vaittinen if (rdev->constraints->over_voltage_detection) 151689a6a5e5SMatti Vaittinen ret = handle_notify_limits(rdev, 151789a6a5e5SMatti Vaittinen ops->set_over_voltage_protection, 151889a6a5e5SMatti Vaittinen &rdev->constraints->over_voltage_limits); 151989a6a5e5SMatti Vaittinen if (ret) { 152089a6a5e5SMatti Vaittinen if (ret != -EOPNOTSUPP) { 152189a6a5e5SMatti Vaittinen rdev_err(rdev, "failed to set over voltage limits %pe\n", 152289a6a5e5SMatti Vaittinen ERR_PTR(ret)); 152389a6a5e5SMatti Vaittinen return ret; 152489a6a5e5SMatti Vaittinen } 152589a6a5e5SMatti Vaittinen rdev_warn(rdev, 152689a6a5e5SMatti Vaittinen "IC does not support requested over voltage limits\n"); 152789a6a5e5SMatti Vaittinen } 152889a6a5e5SMatti Vaittinen 152989a6a5e5SMatti Vaittinen if (rdev->constraints->under_voltage_detection) 153089a6a5e5SMatti Vaittinen ret = handle_notify_limits(rdev, 153189a6a5e5SMatti Vaittinen ops->set_under_voltage_protection, 153289a6a5e5SMatti Vaittinen &rdev->constraints->under_voltage_limits); 153389a6a5e5SMatti Vaittinen if (ret) { 153489a6a5e5SMatti Vaittinen if (ret != -EOPNOTSUPP) { 153589a6a5e5SMatti Vaittinen rdev_err(rdev, "failed to set under voltage limits %pe\n", 153689a6a5e5SMatti Vaittinen ERR_PTR(ret)); 153789a6a5e5SMatti Vaittinen return ret; 153889a6a5e5SMatti Vaittinen } 153989a6a5e5SMatti Vaittinen rdev_warn(rdev, 154089a6a5e5SMatti Vaittinen "IC does not support requested under voltage limits\n"); 154189a6a5e5SMatti Vaittinen } 154289a6a5e5SMatti Vaittinen 154389a6a5e5SMatti Vaittinen if (rdev->constraints->over_temp_detection) 154489a6a5e5SMatti Vaittinen ret = handle_notify_limits(rdev, 154589a6a5e5SMatti Vaittinen ops->set_thermal_protection, 154689a6a5e5SMatti Vaittinen &rdev->constraints->temp_limits); 154789a6a5e5SMatti Vaittinen if (ret) { 154889a6a5e5SMatti Vaittinen if (ret != -EOPNOTSUPP) { 154989a6a5e5SMatti Vaittinen rdev_err(rdev, "failed to set temperature limits %pe\n", 155089a6a5e5SMatti Vaittinen ERR_PTR(ret)); 155189a6a5e5SMatti Vaittinen return ret; 155289a6a5e5SMatti Vaittinen } 155389a6a5e5SMatti Vaittinen rdev_warn(rdev, 155489a6a5e5SMatti Vaittinen "IC does not support requested temperature limits\n"); 155589a6a5e5SMatti Vaittinen } 155689a6a5e5SMatti Vaittinen 1557670666b9SLaxman Dewangan if (rdev->constraints->active_discharge && ops->set_active_discharge) { 1558670666b9SLaxman Dewangan bool ad_state = (rdev->constraints->active_discharge == 1559670666b9SLaxman Dewangan REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false; 1560670666b9SLaxman Dewangan 1561670666b9SLaxman Dewangan ret = ops->set_active_discharge(rdev, ad_state); 1562670666b9SLaxman Dewangan if (ret < 0) { 156361aab5adSMichał Mirosław rdev_err(rdev, "failed to set active discharge: %pe\n", ERR_PTR(ret)); 1564670666b9SLaxman Dewangan return ret; 1565670666b9SLaxman Dewangan } 1566670666b9SLaxman Dewangan } 1567670666b9SLaxman Dewangan 1568261f0631SMark Brown /* 1569261f0631SMark Brown * If there is no mechanism for controlling the regulator then 1570261f0631SMark Brown * flag it as always_on so we don't end up duplicating checks 1571261f0631SMark Brown * for this so much. Note that we could control the state of 1572261f0631SMark Brown * a supply to control the output on a regulator that has no 1573261f0631SMark Brown * direct control. 1574261f0631SMark Brown */ 1575261f0631SMark Brown if (!rdev->ena_pin && !ops->enable) { 1576261f0631SMark Brown if (rdev->supply_name && !rdev->supply) 1577261f0631SMark Brown return -EPROBE_DEFER; 1578261f0631SMark Brown 1579261f0631SMark Brown if (rdev->supply) 1580261f0631SMark Brown rdev->constraints->always_on = 1581261f0631SMark Brown rdev->supply->rdev->constraints->always_on; 1582261f0631SMark Brown else 1583261f0631SMark Brown rdev->constraints->always_on = true; 1584261f0631SMark Brown } 1585261f0631SMark Brown 1586218320feSChristian Kohlschütter if (rdev->desc->off_on_delay) 1587218320feSChristian Kohlschütter rdev->last_off = ktime_get(); 1588218320feSChristian Kohlschütter 15892bb16663SOlliver Schinagl /* If the constraints say the regulator should be on at this point 15902bb16663SOlliver Schinagl * and we have control then make sure it is enabled. 15912bb16663SOlliver Schinagl */ 15922bb16663SOlliver Schinagl if (rdev->constraints->always_on || rdev->constraints->boot_on) { 159398e48cd9SDmitry Baryshkov /* If we want to enable this regulator, make sure that we know 159498e48cd9SDmitry Baryshkov * the supplying regulator. 159598e48cd9SDmitry Baryshkov */ 159698e48cd9SDmitry Baryshkov if (rdev->supply_name && !rdev->supply) 159798e48cd9SDmitry Baryshkov return -EPROBE_DEFER; 159898e48cd9SDmitry Baryshkov 15990591b14cSRui Zhang /* If supplying regulator has already been enabled, 16000591b14cSRui Zhang * it's not intended to have use_count increment 16010591b14cSRui Zhang * when rdev is only boot-on. 16020591b14cSRui Zhang */ 16030591b14cSRui Zhang if (rdev->supply && 16040591b14cSRui Zhang (rdev->constraints->always_on || 16050591b14cSRui Zhang !regulator_is_enabled(rdev->supply))) { 160605f224caSDouglas Anderson ret = regulator_enable(rdev->supply); 160705f224caSDouglas Anderson if (ret < 0) { 160805f224caSDouglas Anderson _regulator_put(rdev->supply); 160905f224caSDouglas Anderson rdev->supply = NULL; 161005f224caSDouglas Anderson return ret; 161105f224caSDouglas Anderson } 161205f224caSDouglas Anderson } 161305f224caSDouglas Anderson 16142bb16663SOlliver Schinagl ret = _regulator_do_enable(rdev); 16152bb16663SOlliver Schinagl if (ret < 0 && ret != -EINVAL) { 161661aab5adSMichał Mirosław rdev_err(rdev, "failed to enable: %pe\n", ERR_PTR(ret)); 16172bb16663SOlliver Schinagl return ret; 16182bb16663SOlliver Schinagl } 1619089b3f61SPascal Paillet 1620089b3f61SPascal Paillet if (rdev->constraints->always_on) 162105f224caSDouglas Anderson rdev->use_count++; 16222bb16663SOlliver Schinagl } 16232bb16663SOlliver Schinagl 1624a5766f11SLiam Girdwood print_constraints(rdev); 16251a6958e7SAxel Lin return 0; 1626a5766f11SLiam Girdwood } 1627a5766f11SLiam Girdwood 1628a5766f11SLiam Girdwood /** 1629a5766f11SLiam Girdwood * set_supply - set regulator supply regulator 163069279fb9SMark Brown * @rdev: regulator name 163169279fb9SMark Brown * @supply_rdev: supply regulator name 1632a5766f11SLiam Girdwood * 1633a5766f11SLiam Girdwood * Called by platform initialisation code to set the supply regulator for this 1634a5766f11SLiam Girdwood * regulator. This ensures that a regulators supply will also be enabled by the 1635a5766f11SLiam Girdwood * core if it's child is enabled. 1636a5766f11SLiam Girdwood */ 1637a5766f11SLiam Girdwood static int set_supply(struct regulator_dev *rdev, 1638a5766f11SLiam Girdwood struct regulator_dev *supply_rdev) 1639a5766f11SLiam Girdwood { 1640a5766f11SLiam Girdwood int err; 1641a5766f11SLiam Girdwood 164235d11469SMark Brown rdev_dbg(rdev, "supplied by %s\n", rdev_get_name(supply_rdev)); 16433801b86aSMark Brown 1644e2c09ae7SJavier Martinez Canillas if (!try_module_get(supply_rdev->owner)) 1645e2c09ae7SJavier Martinez Canillas return -ENODEV; 1646e2c09ae7SJavier Martinez Canillas 16473801b86aSMark Brown rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY"); 164832c78de8SAxel Lin if (rdev->supply == NULL) { 1649*da46ee19SYang Yingliang module_put(supply_rdev->owner); 165032c78de8SAxel Lin err = -ENOMEM; 1651a5766f11SLiam Girdwood return err; 1652a5766f11SLiam Girdwood } 165357ad526aSLaxman Dewangan supply_rdev->open_count++; 1654a5766f11SLiam Girdwood 16553801b86aSMark Brown return 0; 16563801b86aSMark Brown } 16573801b86aSMark Brown 1658a5766f11SLiam Girdwood /** 165906c63f93SRandy Dunlap * set_consumer_device_supply - Bind a regulator to a symbolic supply 166069279fb9SMark Brown * @rdev: regulator source 166140f9244fSMark Brown * @consumer_dev_name: dev_name() string for device supply applies to 1662a5766f11SLiam Girdwood * @supply: symbolic name for supply 1663a5766f11SLiam Girdwood * 1664a5766f11SLiam Girdwood * Allows platform initialisation code to map physical regulator 1665a5766f11SLiam Girdwood * sources to symbolic names for supplies for use by devices. Devices 1666a5766f11SLiam Girdwood * should use these symbolic names to request regulators, avoiding the 1667a5766f11SLiam Girdwood * need to provide board-specific regulator names as platform data. 1668a5766f11SLiam Girdwood */ 1669a5766f11SLiam Girdwood static int set_consumer_device_supply(struct regulator_dev *rdev, 1670737f360dSMark Brown const char *consumer_dev_name, 167140f9244fSMark Brown const char *supply) 1672a5766f11SLiam Girdwood { 16735c065401SMichał Mirosław struct regulator_map *node, *new_node; 16749ed2099eSMark Brown int has_dev; 1675a5766f11SLiam Girdwood 1676a5766f11SLiam Girdwood if (supply == NULL) 1677a5766f11SLiam Girdwood return -EINVAL; 1678a5766f11SLiam Girdwood 16799ed2099eSMark Brown if (consumer_dev_name != NULL) 16809ed2099eSMark Brown has_dev = 1; 16819ed2099eSMark Brown else 16829ed2099eSMark Brown has_dev = 0; 16839ed2099eSMark Brown 16845c065401SMichał Mirosław new_node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL); 16855c065401SMichał Mirosław if (new_node == NULL) 16865c065401SMichał Mirosław return -ENOMEM; 16875c065401SMichał Mirosław 16885c065401SMichał Mirosław new_node->regulator = rdev; 16895c065401SMichał Mirosław new_node->supply = supply; 16905c065401SMichał Mirosław 16915c065401SMichał Mirosław if (has_dev) { 16925c065401SMichał Mirosław new_node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL); 16935c065401SMichał Mirosław if (new_node->dev_name == NULL) { 16945c065401SMichał Mirosław kfree(new_node); 16955c065401SMichał Mirosław return -ENOMEM; 16965c065401SMichał Mirosław } 16975c065401SMichał Mirosław } 16985c065401SMichał Mirosław 16995c065401SMichał Mirosław mutex_lock(®ulator_list_mutex); 17006001e13cSDavid Brownell list_for_each_entry(node, ®ulator_map_list, list) { 170123b5cc2aSJani Nikula if (node->dev_name && consumer_dev_name) { 170223b5cc2aSJani Nikula if (strcmp(node->dev_name, consumer_dev_name) != 0) 17036001e13cSDavid Brownell continue; 170423b5cc2aSJani Nikula } else if (node->dev_name || consumer_dev_name) { 170523b5cc2aSJani Nikula continue; 170623b5cc2aSJani Nikula } 170723b5cc2aSJani Nikula 17086001e13cSDavid Brownell if (strcmp(node->supply, supply) != 0) 17096001e13cSDavid Brownell continue; 17106001e13cSDavid Brownell 1711737f360dSMark Brown pr_debug("%s: %s/%s is '%s' supply; fail %s/%s\n", 1712737f360dSMark Brown consumer_dev_name, 17136001e13cSDavid Brownell dev_name(&node->regulator->dev), 17146001e13cSDavid Brownell node->regulator->desc->name, 17156001e13cSDavid Brownell supply, 17161083c393SMark Brown dev_name(&rdev->dev), rdev_get_name(rdev)); 17175c065401SMichał Mirosław goto fail; 17186001e13cSDavid Brownell } 17196001e13cSDavid Brownell 17205c065401SMichał Mirosław list_add(&new_node->list, ®ulator_map_list); 17215c065401SMichał Mirosław mutex_unlock(®ulator_list_mutex); 1722a5766f11SLiam Girdwood 1723a5766f11SLiam Girdwood return 0; 17245c065401SMichał Mirosław 17255c065401SMichał Mirosław fail: 17265c065401SMichał Mirosław mutex_unlock(®ulator_list_mutex); 17275c065401SMichał Mirosław kfree(new_node->dev_name); 17285c065401SMichał Mirosław kfree(new_node); 17295c065401SMichał Mirosław return -EBUSY; 1730a5766f11SLiam Girdwood } 1731a5766f11SLiam Girdwood 17320f1d747bSMike Rapoport static void unset_regulator_supplies(struct regulator_dev *rdev) 17330f1d747bSMike Rapoport { 17340f1d747bSMike Rapoport struct regulator_map *node, *n; 17350f1d747bSMike Rapoport 17360f1d747bSMike Rapoport list_for_each_entry_safe(node, n, ®ulator_map_list, list) { 17370f1d747bSMike Rapoport if (rdev == node->regulator) { 17380f1d747bSMike Rapoport list_del(&node->list); 173940f9244fSMark Brown kfree(node->dev_name); 17400f1d747bSMike Rapoport kfree(node); 17410f1d747bSMike Rapoport } 17420f1d747bSMike Rapoport } 17430f1d747bSMike Rapoport } 17440f1d747bSMike Rapoport 17452d80a91bSRichard Fitzgerald #ifdef CONFIG_DEBUG_FS 17462d80a91bSRichard Fitzgerald static ssize_t constraint_flags_read_file(struct file *file, 17472d80a91bSRichard Fitzgerald char __user *user_buf, 17482d80a91bSRichard Fitzgerald size_t count, loff_t *ppos) 17492d80a91bSRichard Fitzgerald { 17502d80a91bSRichard Fitzgerald const struct regulator *regulator = file->private_data; 17512d80a91bSRichard Fitzgerald const struct regulation_constraints *c = regulator->rdev->constraints; 17522d80a91bSRichard Fitzgerald char *buf; 17532d80a91bSRichard Fitzgerald ssize_t ret; 17542d80a91bSRichard Fitzgerald 17552d80a91bSRichard Fitzgerald if (!c) 17562d80a91bSRichard Fitzgerald return 0; 17572d80a91bSRichard Fitzgerald 17582d80a91bSRichard Fitzgerald buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 17592d80a91bSRichard Fitzgerald if (!buf) 17602d80a91bSRichard Fitzgerald return -ENOMEM; 17612d80a91bSRichard Fitzgerald 17622d80a91bSRichard Fitzgerald ret = snprintf(buf, PAGE_SIZE, 17632d80a91bSRichard Fitzgerald "always_on: %u\n" 17642d80a91bSRichard Fitzgerald "boot_on: %u\n" 17652d80a91bSRichard Fitzgerald "apply_uV: %u\n" 17662d80a91bSRichard Fitzgerald "ramp_disable: %u\n" 17672d80a91bSRichard Fitzgerald "soft_start: %u\n" 17682d80a91bSRichard Fitzgerald "pull_down: %u\n" 17692d80a91bSRichard Fitzgerald "over_current_protection: %u\n", 17702d80a91bSRichard Fitzgerald c->always_on, 17712d80a91bSRichard Fitzgerald c->boot_on, 17722d80a91bSRichard Fitzgerald c->apply_uV, 17732d80a91bSRichard Fitzgerald c->ramp_disable, 17742d80a91bSRichard Fitzgerald c->soft_start, 17752d80a91bSRichard Fitzgerald c->pull_down, 17762d80a91bSRichard Fitzgerald c->over_current_protection); 17772d80a91bSRichard Fitzgerald 17782d80a91bSRichard Fitzgerald ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 17792d80a91bSRichard Fitzgerald kfree(buf); 17802d80a91bSRichard Fitzgerald 17812d80a91bSRichard Fitzgerald return ret; 17822d80a91bSRichard Fitzgerald } 17832d80a91bSRichard Fitzgerald 17842d80a91bSRichard Fitzgerald #endif 17852d80a91bSRichard Fitzgerald 17862d80a91bSRichard Fitzgerald static const struct file_operations constraint_flags_fops = { 17872d80a91bSRichard Fitzgerald #ifdef CONFIG_DEBUG_FS 17882d80a91bSRichard Fitzgerald .open = simple_open, 17892d80a91bSRichard Fitzgerald .read = constraint_flags_read_file, 17902d80a91bSRichard Fitzgerald .llseek = default_llseek, 17912d80a91bSRichard Fitzgerald #endif 17922d80a91bSRichard Fitzgerald }; 17932d80a91bSRichard Fitzgerald 1794f5726ae3SMark Brown #define REG_STR_SIZE 64 1795414c70cbSLiam Girdwood 1796414c70cbSLiam Girdwood static struct regulator *create_regulator(struct regulator_dev *rdev, 1797414c70cbSLiam Girdwood struct device *dev, 1798414c70cbSLiam Girdwood const char *supply_name) 1799414c70cbSLiam Girdwood { 1800414c70cbSLiam Girdwood struct regulator *regulator; 1801dbe954d8SHans de Goede int err = 0; 1802414c70cbSLiam Girdwood 180387fe29b6SMichał Mirosław if (dev) { 180487fe29b6SMichał Mirosław char buf[REG_STR_SIZE]; 180587fe29b6SMichał Mirosław int size; 180687fe29b6SMichał Mirosław 180787fe29b6SMichał Mirosław size = snprintf(buf, REG_STR_SIZE, "%s-%s", 180887fe29b6SMichał Mirosław dev->kobj.name, supply_name); 180987fe29b6SMichał Mirosław if (size >= REG_STR_SIZE) 1810414c70cbSLiam Girdwood return NULL; 1811414c70cbSLiam Girdwood 181287fe29b6SMichał Mirosław supply_name = kstrdup(buf, GFP_KERNEL); 181387fe29b6SMichał Mirosław if (supply_name == NULL) 181487fe29b6SMichał Mirosław return NULL; 181587fe29b6SMichał Mirosław } else { 181687fe29b6SMichał Mirosław supply_name = kstrdup_const(supply_name, GFP_KERNEL); 181787fe29b6SMichał Mirosław if (supply_name == NULL) 181887fe29b6SMichał Mirosław return NULL; 181987fe29b6SMichał Mirosław } 182087fe29b6SMichał Mirosław 182187fe29b6SMichał Mirosław regulator = kzalloc(sizeof(*regulator), GFP_KERNEL); 182287fe29b6SMichał Mirosław if (regulator == NULL) { 1823dc8d006dSWang ShaoBo kfree_const(supply_name); 182487fe29b6SMichał Mirosław return NULL; 182587fe29b6SMichał Mirosław } 182687fe29b6SMichał Mirosław 1827414c70cbSLiam Girdwood regulator->rdev = rdev; 182887fe29b6SMichał Mirosław regulator->supply_name = supply_name; 182987fe29b6SMichał Mirosław 183087fe29b6SMichał Mirosław regulator_lock(rdev); 1831414c70cbSLiam Girdwood list_add(®ulator->list, &rdev->consumer_list); 183287fe29b6SMichał Mirosław regulator_unlock(rdev); 1833414c70cbSLiam Girdwood 1834414c70cbSLiam Girdwood if (dev) { 1835e2c98eafSShawn Guo regulator->dev = dev; 1836e2c98eafSShawn Guo 1837222cc7b1SMark Brown /* Add a link to the device sysfs entry */ 1838ff268b56SStephen Boyd err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj, 183987fe29b6SMichał Mirosław supply_name); 1840414c70cbSLiam Girdwood if (err) { 184161aab5adSMichał Mirosław rdev_dbg(rdev, "could not add device link %s: %pe\n", 184261aab5adSMichał Mirosław dev->kobj.name, ERR_PTR(err)); 1843222cc7b1SMark Brown /* non-fatal */ 1844414c70cbSLiam Girdwood } 1845414c70cbSLiam Girdwood } 18465de70519SMark Brown 1847dbe954d8SHans de Goede if (err != -EEXIST) 1848dbe954d8SHans de Goede regulator->debugfs = debugfs_create_dir(supply_name, rdev->debugfs); 184924751434SStephen Boyd if (!regulator->debugfs) { 1850ad3a942bSStephen Boyd rdev_dbg(rdev, "Failed to create debugfs directory\n"); 18515de70519SMark Brown } else { 18525de70519SMark Brown debugfs_create_u32("uA_load", 0444, regulator->debugfs, 18535de70519SMark Brown ®ulator->uA_load); 18545de70519SMark Brown debugfs_create_u32("min_uV", 0444, regulator->debugfs, 1855c360a6dfSChunyan Zhang ®ulator->voltage[PM_SUSPEND_ON].min_uV); 18565de70519SMark Brown debugfs_create_u32("max_uV", 0444, regulator->debugfs, 1857c360a6dfSChunyan Zhang ®ulator->voltage[PM_SUSPEND_ON].max_uV); 18582d80a91bSRichard Fitzgerald debugfs_create_file("constraint_flags", 0444, 18592d80a91bSRichard Fitzgerald regulator->debugfs, regulator, 18602d80a91bSRichard Fitzgerald &constraint_flags_fops); 18615de70519SMark Brown } 18625de70519SMark Brown 18636492bc1bSMark Brown /* 18646492bc1bSMark Brown * Check now if the regulator is an always on regulator - if 18656492bc1bSMark Brown * it is then we don't need to do nearly so much work for 18666492bc1bSMark Brown * enable/disable calls. 18676492bc1bSMark Brown */ 18688a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS) && 18696492bc1bSMark Brown _regulator_is_enabled(rdev)) 18706492bc1bSMark Brown regulator->always_on = true; 18716492bc1bSMark Brown 1872414c70cbSLiam Girdwood return regulator; 1873414c70cbSLiam Girdwood } 1874414c70cbSLiam Girdwood 187531aae2beSMark Brown static int _regulator_get_enable_time(struct regulator_dev *rdev) 187631aae2beSMark Brown { 187700c877c6SLaxman Dewangan if (rdev->constraints && rdev->constraints->enable_time) 187800c877c6SLaxman Dewangan return rdev->constraints->enable_time; 187968ce3a44SAxel Lin if (rdev->desc->ops->enable_time) 188031aae2beSMark Brown return rdev->desc->ops->enable_time(rdev); 188168ce3a44SAxel Lin return rdev->desc->enable_time; 188231aae2beSMark Brown } 188331aae2beSMark Brown 1884a06ccd9cSCharles Keepax static struct regulator_supply_alias *regulator_find_supply_alias( 1885a06ccd9cSCharles Keepax struct device *dev, const char *supply) 1886a06ccd9cSCharles Keepax { 1887a06ccd9cSCharles Keepax struct regulator_supply_alias *map; 1888a06ccd9cSCharles Keepax 1889a06ccd9cSCharles Keepax list_for_each_entry(map, ®ulator_supply_alias_list, list) 1890a06ccd9cSCharles Keepax if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0) 1891a06ccd9cSCharles Keepax return map; 1892a06ccd9cSCharles Keepax 1893a06ccd9cSCharles Keepax return NULL; 1894a06ccd9cSCharles Keepax } 1895a06ccd9cSCharles Keepax 1896a06ccd9cSCharles Keepax static void regulator_supply_alias(struct device **dev, const char **supply) 1897a06ccd9cSCharles Keepax { 1898a06ccd9cSCharles Keepax struct regulator_supply_alias *map; 1899a06ccd9cSCharles Keepax 1900a06ccd9cSCharles Keepax map = regulator_find_supply_alias(*dev, *supply); 1901a06ccd9cSCharles Keepax if (map) { 1902a06ccd9cSCharles Keepax dev_dbg(*dev, "Mapping supply %s to %s,%s\n", 1903a06ccd9cSCharles Keepax *supply, map->alias_supply, 1904a06ccd9cSCharles Keepax dev_name(map->alias_dev)); 1905a06ccd9cSCharles Keepax *dev = map->alias_dev; 1906a06ccd9cSCharles Keepax *supply = map->alias_supply; 1907a06ccd9cSCharles Keepax } 1908a06ccd9cSCharles Keepax } 1909a06ccd9cSCharles Keepax 191085f3b431STomeu Vizoso static int regulator_match(struct device *dev, const void *data) 191185f3b431STomeu Vizoso { 191285f3b431STomeu Vizoso struct regulator_dev *r = dev_to_rdev(dev); 191385f3b431STomeu Vizoso 191485f3b431STomeu Vizoso return strcmp(rdev_get_name(r), data) == 0; 191585f3b431STomeu Vizoso } 191685f3b431STomeu Vizoso 191785f3b431STomeu Vizoso static struct regulator_dev *regulator_lookup_by_name(const char *name) 191885f3b431STomeu Vizoso { 191985f3b431STomeu Vizoso struct device *dev; 192085f3b431STomeu Vizoso 192185f3b431STomeu Vizoso dev = class_find_device(®ulator_class, NULL, name, regulator_match); 192285f3b431STomeu Vizoso 192385f3b431STomeu Vizoso return dev ? dev_to_rdev(dev) : NULL; 192485f3b431STomeu Vizoso } 192585f3b431STomeu Vizoso 192685f3b431STomeu Vizoso /** 192785f3b431STomeu Vizoso * regulator_dev_lookup - lookup a regulator device. 192885f3b431STomeu Vizoso * @dev: device for regulator "consumer". 192985f3b431STomeu Vizoso * @supply: Supply name or regulator ID. 193085f3b431STomeu Vizoso * 193185f3b431STomeu Vizoso * If successful, returns a struct regulator_dev that corresponds to the name 1932163478daSDmitry Torokhov * @supply and with the embedded struct device refcount incremented by one. 1933163478daSDmitry Torokhov * The refcount must be dropped by calling put_device(). 1934163478daSDmitry Torokhov * On failure one of the following ERR-PTR-encoded values is returned: 1935163478daSDmitry Torokhov * -ENODEV if lookup fails permanently, -EPROBE_DEFER if lookup could succeed 1936163478daSDmitry Torokhov * in the future. 193785f3b431STomeu Vizoso */ 193869511a45SRajendra Nayak static struct regulator_dev *regulator_dev_lookup(struct device *dev, 1939163478daSDmitry Torokhov const char *supply) 194069511a45SRajendra Nayak { 194106217197SCharles Keepax struct regulator_dev *r = NULL; 194269511a45SRajendra Nayak struct device_node *node; 1943576ca436SMark Brown struct regulator_map *map; 1944576ca436SMark Brown const char *devname = NULL; 194569511a45SRajendra Nayak 1946a06ccd9cSCharles Keepax regulator_supply_alias(&dev, &supply); 1947a06ccd9cSCharles Keepax 194869511a45SRajendra Nayak /* first do a dt based lookup */ 194969511a45SRajendra Nayak if (dev && dev->of_node) { 195069511a45SRajendra Nayak node = of_get_regulator(dev, supply); 19516d191a5fSMark Brown if (node) { 195285f3b431STomeu Vizoso r = of_find_regulator_by_node(node); 1953f2b41b74SYang Yingliang of_node_put(node); 195485f3b431STomeu Vizoso if (r) 195569511a45SRajendra Nayak return r; 1956163478daSDmitry Torokhov 19576d191a5fSMark Brown /* 1958163478daSDmitry Torokhov * We have a node, but there is no device. 1959163478daSDmitry Torokhov * assume it has not registered yet. 19606d191a5fSMark Brown */ 1961163478daSDmitry Torokhov return ERR_PTR(-EPROBE_DEFER); 19626d191a5fSMark Brown } 196369511a45SRajendra Nayak } 196469511a45SRajendra Nayak 196569511a45SRajendra Nayak /* if not found, try doing it non-dt way */ 1966576ca436SMark Brown if (dev) 1967576ca436SMark Brown devname = dev_name(dev); 1968576ca436SMark Brown 196985f3b431STomeu Vizoso mutex_lock(®ulator_list_mutex); 1970576ca436SMark Brown list_for_each_entry(map, ®ulator_map_list, list) { 1971576ca436SMark Brown /* If the mapping has a device set up it must match */ 1972576ca436SMark Brown if (map->dev_name && 1973576ca436SMark Brown (!devname || strcmp(map->dev_name, devname))) 1974576ca436SMark Brown continue; 1975576ca436SMark Brown 197685f3b431STomeu Vizoso if (strcmp(map->supply, supply) == 0 && 197785f3b431STomeu Vizoso get_device(&map->regulator->dev)) { 1978163478daSDmitry Torokhov r = map->regulator; 1979163478daSDmitry Torokhov break; 1980576ca436SMark Brown } 198185f3b431STomeu Vizoso } 198285f3b431STomeu Vizoso mutex_unlock(®ulator_list_mutex); 1983576ca436SMark Brown 1984163478daSDmitry Torokhov if (r) 1985163478daSDmitry Torokhov return r; 1986163478daSDmitry Torokhov 198706217197SCharles Keepax r = regulator_lookup_by_name(supply); 198806217197SCharles Keepax if (r) 198906217197SCharles Keepax return r; 199006217197SCharles Keepax 1991163478daSDmitry Torokhov return ERR_PTR(-ENODEV); 199269511a45SRajendra Nayak } 199369511a45SRajendra Nayak 19946261b06dSBjorn Andersson static int regulator_resolve_supply(struct regulator_dev *rdev) 19956261b06dSBjorn Andersson { 19966261b06dSBjorn Andersson struct regulator_dev *r; 19976261b06dSBjorn Andersson struct device *dev = rdev->dev.parent; 1998eaa7995cSDavid Collins int ret = 0; 19996261b06dSBjorn Andersson 200048f1b4efSKrzysztof Kozlowski /* No supply to resolve? */ 20016261b06dSBjorn Andersson if (!rdev->supply_name) 20026261b06dSBjorn Andersson return 0; 20036261b06dSBjorn Andersson 2004eaa7995cSDavid Collins /* Supply already resolved? (fast-path without locking contention) */ 20056261b06dSBjorn Andersson if (rdev->supply) 20066261b06dSBjorn Andersson return 0; 20076261b06dSBjorn Andersson 2008163478daSDmitry Torokhov r = regulator_dev_lookup(dev, rdev->supply_name); 2009163478daSDmitry Torokhov if (IS_ERR(r)) { 2010163478daSDmitry Torokhov ret = PTR_ERR(r); 2011163478daSDmitry Torokhov 201206423121SMark Brown /* Did the lookup explicitly defer for us? */ 201306423121SMark Brown if (ret == -EPROBE_DEFER) 2014eaa7995cSDavid Collins goto out; 201506423121SMark Brown 20169f7e25edSMark Brown if (have_full_constraints()) { 20179f7e25edSMark Brown r = dummy_regulator_rdev; 201885f3b431STomeu Vizoso get_device(&r->dev); 20199f7e25edSMark Brown } else { 20206261b06dSBjorn Andersson dev_err(dev, "Failed to resolve %s-supply for %s\n", 20216261b06dSBjorn Andersson rdev->supply_name, rdev->desc->name); 2022eaa7995cSDavid Collins ret = -EPROBE_DEFER; 2023eaa7995cSDavid Collins goto out; 20246261b06dSBjorn Andersson } 20259f7e25edSMark Brown } 20266261b06dSBjorn Andersson 20274b639e25SMichał Mirosław if (r == rdev) { 20284b639e25SMichał Mirosław dev_err(dev, "Supply for %s (%s) resolved to itself\n", 20294b639e25SMichał Mirosław rdev->desc->name, rdev->supply_name); 2030eaa7995cSDavid Collins if (!have_full_constraints()) { 2031eaa7995cSDavid Collins ret = -EINVAL; 2032eaa7995cSDavid Collins goto out; 2033eaa7995cSDavid Collins } 2034f5c042b2SMichał Mirosław r = dummy_regulator_rdev; 2035f5c042b2SMichał Mirosław get_device(&r->dev); 20364b639e25SMichał Mirosław } 20374b639e25SMichał Mirosław 203866d228a2SJon Hunter /* 203966d228a2SJon Hunter * If the supply's parent device is not the same as the 204066d228a2SJon Hunter * regulator's parent device, then ensure the parent device 204166d228a2SJon Hunter * is bound before we resolve the supply, in case the parent 204266d228a2SJon Hunter * device get probe deferred and unregisters the supply. 204366d228a2SJon Hunter */ 204466d228a2SJon Hunter if (r->dev.parent && r->dev.parent != rdev->dev.parent) { 204566d228a2SJon Hunter if (!device_is_bound(r->dev.parent)) { 204666d228a2SJon Hunter put_device(&r->dev); 2047eaa7995cSDavid Collins ret = -EPROBE_DEFER; 2048eaa7995cSDavid Collins goto out; 204966d228a2SJon Hunter } 205066d228a2SJon Hunter } 205166d228a2SJon Hunter 20526261b06dSBjorn Andersson /* Recursively resolve the supply of the supply */ 20536261b06dSBjorn Andersson ret = regulator_resolve_supply(r); 205485f3b431STomeu Vizoso if (ret < 0) { 205585f3b431STomeu Vizoso put_device(&r->dev); 2056eaa7995cSDavid Collins goto out; 205785f3b431STomeu Vizoso } 20586261b06dSBjorn Andersson 205914a71d50SMark Brown /* 206014a71d50SMark Brown * Recheck rdev->supply with rdev->mutex lock held to avoid a race 206114a71d50SMark Brown * between rdev->supply null check and setting rdev->supply in 206214a71d50SMark Brown * set_supply() from concurrent tasks. 206314a71d50SMark Brown */ 206414a71d50SMark Brown regulator_lock(rdev); 206514a71d50SMark Brown 206614a71d50SMark Brown /* Supply just resolved by a concurrent task? */ 206714a71d50SMark Brown if (rdev->supply) { 206814a71d50SMark Brown regulator_unlock(rdev); 206985f3b431STomeu Vizoso put_device(&r->dev); 2070eaa7995cSDavid Collins goto out; 207185f3b431STomeu Vizoso } 20726261b06dSBjorn Andersson 207314a71d50SMark Brown ret = set_supply(rdev, r); 207414a71d50SMark Brown if (ret < 0) { 207514a71d50SMark Brown regulator_unlock(rdev); 207614a71d50SMark Brown put_device(&r->dev); 207714a71d50SMark Brown goto out; 207814a71d50SMark Brown } 207914a71d50SMark Brown 208014a71d50SMark Brown regulator_unlock(rdev); 208114a71d50SMark Brown 208205f224caSDouglas Anderson /* 208305f224caSDouglas Anderson * In set_machine_constraints() we may have turned this regulator on 208405f224caSDouglas Anderson * but we couldn't propagate to the supply if it hadn't been resolved 208505f224caSDouglas Anderson * yet. Do it now. 208605f224caSDouglas Anderson */ 208705f224caSDouglas Anderson if (rdev->use_count) { 20886261b06dSBjorn Andersson ret = regulator_enable(rdev->supply); 208936a1f1b6SJavier Martinez Canillas if (ret < 0) { 209036a1f1b6SJavier Martinez Canillas _regulator_put(rdev->supply); 20918e5356a7SJon Hunter rdev->supply = NULL; 2092eaa7995cSDavid Collins goto out; 20936261b06dSBjorn Andersson } 209436a1f1b6SJavier Martinez Canillas } 20956261b06dSBjorn Andersson 2096eaa7995cSDavid Collins out: 2097eaa7995cSDavid Collins return ret; 20986261b06dSBjorn Andersson } 20996261b06dSBjorn Andersson 21005ffbd136SMark Brown /* Internal regulator request function */ 2101a8bd42a9SDmitry Torokhov struct regulator *_regulator_get(struct device *dev, const char *id, 2102a8bd42a9SDmitry Torokhov enum regulator_get_type get_type) 2103414c70cbSLiam Girdwood { 2104414c70cbSLiam Girdwood struct regulator_dev *rdev; 21057d245afaSDmitry Torokhov struct regulator *regulator; 2106b59b6544SSaravana Kannan struct device_link *link; 2107317b5684SMark Brown int ret; 2108414c70cbSLiam Girdwood 2109a8bd42a9SDmitry Torokhov if (get_type >= MAX_GET_TYPE) { 2110a8bd42a9SDmitry Torokhov dev_err(dev, "invalid type %d in %s\n", get_type, __func__); 2111a8bd42a9SDmitry Torokhov return ERR_PTR(-EINVAL); 2112a8bd42a9SDmitry Torokhov } 2113a8bd42a9SDmitry Torokhov 2114414c70cbSLiam Girdwood if (id == NULL) { 21155da84fd9SJoe Perches pr_err("get() with no identifier\n"); 2116043c998fSMark Brown return ERR_PTR(-EINVAL); 2117414c70cbSLiam Girdwood } 2118414c70cbSLiam Girdwood 2119163478daSDmitry Torokhov rdev = regulator_dev_lookup(dev, id); 2120a4d7641fSDmitry Torokhov if (IS_ERR(rdev)) { 2121163478daSDmitry Torokhov ret = PTR_ERR(rdev); 2122ef60abbbSMark Brown 21231e4b545cSNishanth Menon /* 2124a4d7641fSDmitry Torokhov * If regulator_dev_lookup() fails with error other 2125a4d7641fSDmitry Torokhov * than -ENODEV our job here is done, we simply return it. 21261e4b545cSNishanth Menon */ 2127a4d7641fSDmitry Torokhov if (ret != -ENODEV) 2128a4d7641fSDmitry Torokhov return ERR_PTR(ret); 21291e4b545cSNishanth Menon 2130a4d7641fSDmitry Torokhov if (!have_full_constraints()) { 2131a4d7641fSDmitry Torokhov dev_warn(dev, 2132a4d7641fSDmitry Torokhov "incomplete constraints, dummy supplies not allowed\n"); 2133a4d7641fSDmitry Torokhov return ERR_PTR(-ENODEV); 213434abbd68SMark Brown } 213534abbd68SMark Brown 2136a4d7641fSDmitry Torokhov switch (get_type) { 2137a4d7641fSDmitry Torokhov case NORMAL_GET: 2138a4d7641fSDmitry Torokhov /* 2139a4d7641fSDmitry Torokhov * Assume that a regulator is physically present and 2140a4d7641fSDmitry Torokhov * enabled, even if it isn't hooked up, and just 2141a4d7641fSDmitry Torokhov * provide a dummy. 2142a4d7641fSDmitry Torokhov */ 21436e5505cfSAndy Shevchenko dev_warn(dev, "supply %s not found, using dummy regulator\n", id); 2144a4d7641fSDmitry Torokhov rdev = dummy_regulator_rdev; 2145a4d7641fSDmitry Torokhov get_device(&rdev->dev); 2146a4d7641fSDmitry Torokhov break; 2147414c70cbSLiam Girdwood 2148a4d7641fSDmitry Torokhov case EXCLUSIVE_GET: 2149a4d7641fSDmitry Torokhov dev_warn(dev, 2150a4d7641fSDmitry Torokhov "dummy supplies not allowed for exclusive requests\n"); 2151df561f66SGustavo A. R. Silva fallthrough; 2152a4d7641fSDmitry Torokhov 2153a4d7641fSDmitry Torokhov default: 2154a4d7641fSDmitry Torokhov return ERR_PTR(-ENODEV); 2155a4d7641fSDmitry Torokhov } 2156a4d7641fSDmitry Torokhov } 2157a4d7641fSDmitry Torokhov 21585ffbd136SMark Brown if (rdev->exclusive) { 21595ffbd136SMark Brown regulator = ERR_PTR(-EPERM); 216085f3b431STomeu Vizoso put_device(&rdev->dev); 216185f3b431STomeu Vizoso return regulator; 21625ffbd136SMark Brown } 21635ffbd136SMark Brown 2164a8bd42a9SDmitry Torokhov if (get_type == EXCLUSIVE_GET && rdev->open_count) { 21655ffbd136SMark Brown regulator = ERR_PTR(-EBUSY); 216685f3b431STomeu Vizoso put_device(&rdev->dev); 216785f3b431STomeu Vizoso return regulator; 21685ffbd136SMark Brown } 21695ffbd136SMark Brown 217079d6f049SDmitry Osipenko mutex_lock(®ulator_list_mutex); 217179d6f049SDmitry Osipenko ret = (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled); 217279d6f049SDmitry Osipenko mutex_unlock(®ulator_list_mutex); 217379d6f049SDmitry Osipenko 217479d6f049SDmitry Osipenko if (ret != 0) { 217579d6f049SDmitry Osipenko regulator = ERR_PTR(-EPROBE_DEFER); 217679d6f049SDmitry Osipenko put_device(&rdev->dev); 217779d6f049SDmitry Osipenko return regulator; 217879d6f049SDmitry Osipenko } 217979d6f049SDmitry Osipenko 21806261b06dSBjorn Andersson ret = regulator_resolve_supply(rdev); 21816261b06dSBjorn Andersson if (ret < 0) { 21826261b06dSBjorn Andersson regulator = ERR_PTR(ret); 218385f3b431STomeu Vizoso put_device(&rdev->dev); 218485f3b431STomeu Vizoso return regulator; 21856261b06dSBjorn Andersson } 21866261b06dSBjorn Andersson 218785f3b431STomeu Vizoso if (!try_module_get(rdev->owner)) { 21887d245afaSDmitry Torokhov regulator = ERR_PTR(-EPROBE_DEFER); 218985f3b431STomeu Vizoso put_device(&rdev->dev); 219085f3b431STomeu Vizoso return regulator; 219185f3b431STomeu Vizoso } 2192a5766f11SLiam Girdwood 2193414c70cbSLiam Girdwood regulator = create_regulator(rdev, dev, id); 2194414c70cbSLiam Girdwood if (regulator == NULL) { 2195414c70cbSLiam Girdwood regulator = ERR_PTR(-ENOMEM); 2196414c70cbSLiam Girdwood module_put(rdev->owner); 21974affd79aSWen Yang put_device(&rdev->dev); 219885f3b431STomeu Vizoso return regulator; 2199414c70cbSLiam Girdwood } 2200414c70cbSLiam Girdwood 22015ffbd136SMark Brown rdev->open_count++; 2202a8bd42a9SDmitry Torokhov if (get_type == EXCLUSIVE_GET) { 22035ffbd136SMark Brown rdev->exclusive = 1; 22045ffbd136SMark Brown 22055ffbd136SMark Brown ret = _regulator_is_enabled(rdev); 2206c3e3ca05SZev Weiss if (ret > 0) { 22075ffbd136SMark Brown rdev->use_count = 1; 2208c3e3ca05SZev Weiss regulator->enable_count = 1; 2209c3e3ca05SZev Weiss } else { 22105ffbd136SMark Brown rdev->use_count = 0; 2211c3e3ca05SZev Weiss regulator->enable_count = 0; 2212c3e3ca05SZev Weiss } 22135ffbd136SMark Brown } 22145ffbd136SMark Brown 2215b59b6544SSaravana Kannan link = device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS); 2216b59b6544SSaravana Kannan if (!IS_ERR_OR_NULL(link)) 2217b59b6544SSaravana Kannan regulator->device_link = true; 2218ed1ae2ddSpascal paillet 2219414c70cbSLiam Girdwood return regulator; 2220414c70cbSLiam Girdwood } 22215ffbd136SMark Brown 22225ffbd136SMark Brown /** 22235ffbd136SMark Brown * regulator_get - lookup and obtain a reference to a regulator. 22245ffbd136SMark Brown * @dev: device for regulator "consumer" 22255ffbd136SMark Brown * @id: Supply name or regulator ID. 22265ffbd136SMark Brown * 22275ffbd136SMark Brown * Returns a struct regulator corresponding to the regulator producer, 22285ffbd136SMark Brown * or IS_ERR() condition containing errno. 22295ffbd136SMark Brown * 223090cf443dSDaniel Scally * Use of supply names configured via set_consumer_device_supply() is 22315ffbd136SMark Brown * strongly encouraged. It is recommended that the supply name used 22325ffbd136SMark Brown * should match the name used for the supply and/or the relevant 22335ffbd136SMark Brown * device pins in the datasheet. 22345ffbd136SMark Brown */ 22355ffbd136SMark Brown struct regulator *regulator_get(struct device *dev, const char *id) 22365ffbd136SMark Brown { 2237a8bd42a9SDmitry Torokhov return _regulator_get(dev, id, NORMAL_GET); 22385ffbd136SMark Brown } 2239414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get); 2240414c70cbSLiam Girdwood 2241070b9079SStephen Boyd /** 22425ffbd136SMark Brown * regulator_get_exclusive - obtain exclusive access to a regulator. 22435ffbd136SMark Brown * @dev: device for regulator "consumer" 22445ffbd136SMark Brown * @id: Supply name or regulator ID. 22455ffbd136SMark Brown * 22465ffbd136SMark Brown * Returns a struct regulator corresponding to the regulator producer, 22475ffbd136SMark Brown * or IS_ERR() condition containing errno. Other consumers will be 224869c3f723SStephen Boyd * unable to obtain this regulator while this reference is held and the 224969c3f723SStephen Boyd * use count for the regulator will be initialised to reflect the current 225069c3f723SStephen Boyd * state of the regulator. 22515ffbd136SMark Brown * 22525ffbd136SMark Brown * This is intended for use by consumers which cannot tolerate shared 22535ffbd136SMark Brown * use of the regulator such as those which need to force the 22545ffbd136SMark Brown * regulator off for correct operation of the hardware they are 22555ffbd136SMark Brown * controlling. 22565ffbd136SMark Brown * 225790cf443dSDaniel Scally * Use of supply names configured via set_consumer_device_supply() is 22585ffbd136SMark Brown * strongly encouraged. It is recommended that the supply name used 22595ffbd136SMark Brown * should match the name used for the supply and/or the relevant 22605ffbd136SMark Brown * device pins in the datasheet. 22615ffbd136SMark Brown */ 22625ffbd136SMark Brown struct regulator *regulator_get_exclusive(struct device *dev, const char *id) 22635ffbd136SMark Brown { 2264a8bd42a9SDmitry Torokhov return _regulator_get(dev, id, EXCLUSIVE_GET); 22655ffbd136SMark Brown } 22665ffbd136SMark Brown EXPORT_SYMBOL_GPL(regulator_get_exclusive); 22675ffbd136SMark Brown 2268de1dd9fdSMark Brown /** 2269de1dd9fdSMark Brown * regulator_get_optional - obtain optional access to a regulator. 2270de1dd9fdSMark Brown * @dev: device for regulator "consumer" 2271de1dd9fdSMark Brown * @id: Supply name or regulator ID. 2272de1dd9fdSMark Brown * 2273de1dd9fdSMark Brown * Returns a struct regulator corresponding to the regulator producer, 227469c3f723SStephen Boyd * or IS_ERR() condition containing errno. 2275de1dd9fdSMark Brown * 2276de1dd9fdSMark Brown * This is intended for use by consumers for devices which can have 2277de1dd9fdSMark Brown * some supplies unconnected in normal use, such as some MMC devices. 2278de1dd9fdSMark Brown * It can allow the regulator core to provide stub supplies for other 2279de1dd9fdSMark Brown * supplies requested using normal regulator_get() calls without 2280de1dd9fdSMark Brown * disrupting the operation of drivers that can handle absent 2281de1dd9fdSMark Brown * supplies. 2282de1dd9fdSMark Brown * 228390cf443dSDaniel Scally * Use of supply names configured via set_consumer_device_supply() is 2284de1dd9fdSMark Brown * strongly encouraged. It is recommended that the supply name used 2285de1dd9fdSMark Brown * should match the name used for the supply and/or the relevant 2286de1dd9fdSMark Brown * device pins in the datasheet. 2287de1dd9fdSMark Brown */ 2288de1dd9fdSMark Brown struct regulator *regulator_get_optional(struct device *dev, const char *id) 2289de1dd9fdSMark Brown { 2290a8bd42a9SDmitry Torokhov return _regulator_get(dev, id, OPTIONAL_GET); 2291de1dd9fdSMark Brown } 2292de1dd9fdSMark Brown EXPORT_SYMBOL_GPL(regulator_get_optional); 2293de1dd9fdSMark Brown 2294e1794aa4SSaravana Kannan static void destroy_regulator(struct regulator *regulator) 2295414c70cbSLiam Girdwood { 2296e1794aa4SSaravana Kannan struct regulator_dev *rdev = regulator->rdev; 2297414c70cbSLiam Girdwood 22985de70519SMark Brown debugfs_remove_recursive(regulator->debugfs); 22995de70519SMark Brown 2300ed1ae2ddSpascal paillet if (regulator->dev) { 2301b59b6544SSaravana Kannan if (regulator->device_link) 2302ed1ae2ddSpascal paillet device_link_remove(regulator->dev, &rdev->dev); 2303ed1ae2ddSpascal paillet 2304414c70cbSLiam Girdwood /* remove any sysfs entries */ 2305414c70cbSLiam Girdwood sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); 2306ed1ae2ddSpascal paillet } 2307ed1ae2ddSpascal paillet 230866cf9a7eSMaciej Purski regulator_lock(rdev); 2309414c70cbSLiam Girdwood list_del(®ulator->list); 2310414c70cbSLiam Girdwood 23115ffbd136SMark Brown rdev->open_count--; 23125ffbd136SMark Brown rdev->exclusive = 0; 231366cf9a7eSMaciej Purski regulator_unlock(rdev); 23145ffbd136SMark Brown 23150630b614SStephen Boyd kfree_const(regulator->supply_name); 23161768514eSMark Brown kfree(regulator); 2317e1794aa4SSaravana Kannan } 2318e1794aa4SSaravana Kannan 2319e1794aa4SSaravana Kannan /* regulator_list_mutex lock held by regulator_put() */ 2320e1794aa4SSaravana Kannan static void _regulator_put(struct regulator *regulator) 2321e1794aa4SSaravana Kannan { 2322e1794aa4SSaravana Kannan struct regulator_dev *rdev; 2323e1794aa4SSaravana Kannan 2324e1794aa4SSaravana Kannan if (IS_ERR_OR_NULL(regulator)) 2325e1794aa4SSaravana Kannan return; 2326e1794aa4SSaravana Kannan 2327e1794aa4SSaravana Kannan lockdep_assert_held_once(®ulator_list_mutex); 2328e1794aa4SSaravana Kannan 2329e1794aa4SSaravana Kannan /* Docs say you must disable before calling regulator_put() */ 2330e1794aa4SSaravana Kannan WARN_ON(regulator->enable_count); 2331e1794aa4SSaravana Kannan 2332e1794aa4SSaravana Kannan rdev = regulator->rdev; 2333e1794aa4SSaravana Kannan 2334e1794aa4SSaravana Kannan destroy_regulator(regulator); 23351768514eSMark Brown 2336414c70cbSLiam Girdwood module_put(rdev->owner); 23374affd79aSWen Yang put_device(&rdev->dev); 233823ff2f0fSCharles Keepax } 233923ff2f0fSCharles Keepax 234023ff2f0fSCharles Keepax /** 234123ff2f0fSCharles Keepax * regulator_put - "free" the regulator source 234223ff2f0fSCharles Keepax * @regulator: regulator source 234323ff2f0fSCharles Keepax * 234423ff2f0fSCharles Keepax * Note: drivers must ensure that all regulator_enable calls made on this 234523ff2f0fSCharles Keepax * regulator source are balanced by regulator_disable calls prior to calling 234623ff2f0fSCharles Keepax * this function. 234723ff2f0fSCharles Keepax */ 234823ff2f0fSCharles Keepax void regulator_put(struct regulator *regulator) 234923ff2f0fSCharles Keepax { 235023ff2f0fSCharles Keepax mutex_lock(®ulator_list_mutex); 235123ff2f0fSCharles Keepax _regulator_put(regulator); 2352414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 2353414c70cbSLiam Girdwood } 2354414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_put); 2355414c70cbSLiam Girdwood 2356a06ccd9cSCharles Keepax /** 2357a06ccd9cSCharles Keepax * regulator_register_supply_alias - Provide device alias for supply lookup 2358a06ccd9cSCharles Keepax * 2359a06ccd9cSCharles Keepax * @dev: device that will be given as the regulator "consumer" 2360a06ccd9cSCharles Keepax * @id: Supply name or regulator ID 2361a06ccd9cSCharles Keepax * @alias_dev: device that should be used to lookup the supply 2362a06ccd9cSCharles Keepax * @alias_id: Supply name or regulator ID that should be used to lookup the 2363a06ccd9cSCharles Keepax * supply 2364a06ccd9cSCharles Keepax * 2365a06ccd9cSCharles Keepax * All lookups for id on dev will instead be conducted for alias_id on 2366a06ccd9cSCharles Keepax * alias_dev. 2367a06ccd9cSCharles Keepax */ 2368a06ccd9cSCharles Keepax int regulator_register_supply_alias(struct device *dev, const char *id, 2369a06ccd9cSCharles Keepax struct device *alias_dev, 2370a06ccd9cSCharles Keepax const char *alias_id) 2371a06ccd9cSCharles Keepax { 2372a06ccd9cSCharles Keepax struct regulator_supply_alias *map; 2373a06ccd9cSCharles Keepax 2374a06ccd9cSCharles Keepax map = regulator_find_supply_alias(dev, id); 2375a06ccd9cSCharles Keepax if (map) 2376a06ccd9cSCharles Keepax return -EEXIST; 2377a06ccd9cSCharles Keepax 2378a06ccd9cSCharles Keepax map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); 2379a06ccd9cSCharles Keepax if (!map) 2380a06ccd9cSCharles Keepax return -ENOMEM; 2381a06ccd9cSCharles Keepax 2382a06ccd9cSCharles Keepax map->src_dev = dev; 2383a06ccd9cSCharles Keepax map->src_supply = id; 2384a06ccd9cSCharles Keepax map->alias_dev = alias_dev; 2385a06ccd9cSCharles Keepax map->alias_supply = alias_id; 2386a06ccd9cSCharles Keepax 2387a06ccd9cSCharles Keepax list_add(&map->list, ®ulator_supply_alias_list); 2388a06ccd9cSCharles Keepax 2389a06ccd9cSCharles Keepax pr_info("Adding alias for supply %s,%s -> %s,%s\n", 2390a06ccd9cSCharles Keepax id, dev_name(dev), alias_id, dev_name(alias_dev)); 2391a06ccd9cSCharles Keepax 2392a06ccd9cSCharles Keepax return 0; 2393a06ccd9cSCharles Keepax } 2394a06ccd9cSCharles Keepax EXPORT_SYMBOL_GPL(regulator_register_supply_alias); 2395a06ccd9cSCharles Keepax 2396a06ccd9cSCharles Keepax /** 2397a06ccd9cSCharles Keepax * regulator_unregister_supply_alias - Remove device alias 2398a06ccd9cSCharles Keepax * 2399a06ccd9cSCharles Keepax * @dev: device that will be given as the regulator "consumer" 2400a06ccd9cSCharles Keepax * @id: Supply name or regulator ID 2401a06ccd9cSCharles Keepax * 2402a06ccd9cSCharles Keepax * Remove a lookup alias if one exists for id on dev. 2403a06ccd9cSCharles Keepax */ 2404a06ccd9cSCharles Keepax void regulator_unregister_supply_alias(struct device *dev, const char *id) 2405a06ccd9cSCharles Keepax { 2406a06ccd9cSCharles Keepax struct regulator_supply_alias *map; 2407a06ccd9cSCharles Keepax 2408a06ccd9cSCharles Keepax map = regulator_find_supply_alias(dev, id); 2409a06ccd9cSCharles Keepax if (map) { 2410a06ccd9cSCharles Keepax list_del(&map->list); 2411a06ccd9cSCharles Keepax kfree(map); 2412a06ccd9cSCharles Keepax } 2413a06ccd9cSCharles Keepax } 2414a06ccd9cSCharles Keepax EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); 2415a06ccd9cSCharles Keepax 2416a06ccd9cSCharles Keepax /** 2417a06ccd9cSCharles Keepax * regulator_bulk_register_supply_alias - register multiple aliases 2418a06ccd9cSCharles Keepax * 2419a06ccd9cSCharles Keepax * @dev: device that will be given as the regulator "consumer" 2420a06ccd9cSCharles Keepax * @id: List of supply names or regulator IDs 2421a06ccd9cSCharles Keepax * @alias_dev: device that should be used to lookup the supply 2422a06ccd9cSCharles Keepax * @alias_id: List of supply names or regulator IDs that should be used to 2423a06ccd9cSCharles Keepax * lookup the supply 2424a06ccd9cSCharles Keepax * @num_id: Number of aliases to register 2425a06ccd9cSCharles Keepax * 2426a06ccd9cSCharles Keepax * @return 0 on success, an errno on failure. 2427a06ccd9cSCharles Keepax * 2428a06ccd9cSCharles Keepax * This helper function allows drivers to register several supply 2429a06ccd9cSCharles Keepax * aliases in one operation. If any of the aliases cannot be 2430a06ccd9cSCharles Keepax * registered any aliases that were registered will be removed 2431a06ccd9cSCharles Keepax * before returning to the caller. 2432a06ccd9cSCharles Keepax */ 24339f8c0fe9SLee Jones int regulator_bulk_register_supply_alias(struct device *dev, 24349f8c0fe9SLee Jones const char *const *id, 2435a06ccd9cSCharles Keepax struct device *alias_dev, 24369f8c0fe9SLee Jones const char *const *alias_id, 2437a06ccd9cSCharles Keepax int num_id) 2438a06ccd9cSCharles Keepax { 2439a06ccd9cSCharles Keepax int i; 2440a06ccd9cSCharles Keepax int ret; 2441a06ccd9cSCharles Keepax 2442a06ccd9cSCharles Keepax for (i = 0; i < num_id; ++i) { 2443a06ccd9cSCharles Keepax ret = regulator_register_supply_alias(dev, id[i], alias_dev, 2444a06ccd9cSCharles Keepax alias_id[i]); 2445a06ccd9cSCharles Keepax if (ret < 0) 2446a06ccd9cSCharles Keepax goto err; 2447a06ccd9cSCharles Keepax } 2448a06ccd9cSCharles Keepax 2449a06ccd9cSCharles Keepax return 0; 2450a06ccd9cSCharles Keepax 2451a06ccd9cSCharles Keepax err: 2452a06ccd9cSCharles Keepax dev_err(dev, 2453a06ccd9cSCharles Keepax "Failed to create supply alias %s,%s -> %s,%s\n", 2454a06ccd9cSCharles Keepax id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); 2455a06ccd9cSCharles Keepax 2456a06ccd9cSCharles Keepax while (--i >= 0) 2457a06ccd9cSCharles Keepax regulator_unregister_supply_alias(dev, id[i]); 2458a06ccd9cSCharles Keepax 2459a06ccd9cSCharles Keepax return ret; 2460a06ccd9cSCharles Keepax } 2461a06ccd9cSCharles Keepax EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias); 2462a06ccd9cSCharles Keepax 2463a06ccd9cSCharles Keepax /** 2464a06ccd9cSCharles Keepax * regulator_bulk_unregister_supply_alias - unregister multiple aliases 2465a06ccd9cSCharles Keepax * 2466a06ccd9cSCharles Keepax * @dev: device that will be given as the regulator "consumer" 2467a06ccd9cSCharles Keepax * @id: List of supply names or regulator IDs 2468a06ccd9cSCharles Keepax * @num_id: Number of aliases to unregister 2469a06ccd9cSCharles Keepax * 2470a06ccd9cSCharles Keepax * This helper function allows drivers to unregister several supply 2471a06ccd9cSCharles Keepax * aliases in one operation. 2472a06ccd9cSCharles Keepax */ 2473a06ccd9cSCharles Keepax void regulator_bulk_unregister_supply_alias(struct device *dev, 24749f8c0fe9SLee Jones const char *const *id, 2475a06ccd9cSCharles Keepax int num_id) 2476a06ccd9cSCharles Keepax { 2477a06ccd9cSCharles Keepax int i; 2478a06ccd9cSCharles Keepax 2479a06ccd9cSCharles Keepax for (i = 0; i < num_id; ++i) 2480a06ccd9cSCharles Keepax regulator_unregister_supply_alias(dev, id[i]); 2481a06ccd9cSCharles Keepax } 2482a06ccd9cSCharles Keepax EXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias); 2483a06ccd9cSCharles Keepax 2484a06ccd9cSCharles Keepax 2485f19b00daSKim, Milo /* Manage enable GPIO list. Same GPIO pin can be shared among regulators */ 2486f19b00daSKim, Milo static int regulator_ena_gpio_request(struct regulator_dev *rdev, 2487f19b00daSKim, Milo const struct regulator_config *config) 2488f19b00daSKim, Milo { 2489467bf301SMichał Mirosław struct regulator_enable_gpio *pin, *new_pin; 2490778b28b4SRussell King struct gpio_desc *gpiod; 2491f19b00daSKim, Milo 2492e45e290aSLinus Walleij gpiod = config->ena_gpiod; 2493467bf301SMichał Mirosław new_pin = kzalloc(sizeof(*new_pin), GFP_KERNEL); 2494467bf301SMichał Mirosław 2495467bf301SMichał Mirosław mutex_lock(®ulator_list_mutex); 2496778b28b4SRussell King 2497f19b00daSKim, Milo list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { 2498778b28b4SRussell King if (pin->gpiod == gpiod) { 2499541d052dSLinus Walleij rdev_dbg(rdev, "GPIO is already used\n"); 2500f19b00daSKim, Milo goto update_ena_gpio_to_rdev; 2501f19b00daSKim, Milo } 2502f19b00daSKim, Milo } 2503f19b00daSKim, Milo 2504467bf301SMichał Mirosław if (new_pin == NULL) { 2505467bf301SMichał Mirosław mutex_unlock(®ulator_list_mutex); 2506f19b00daSKim, Milo return -ENOMEM; 2507467bf301SMichał Mirosław } 2508467bf301SMichał Mirosław 2509467bf301SMichał Mirosław pin = new_pin; 2510467bf301SMichał Mirosław new_pin = NULL; 2511f19b00daSKim, Milo 2512778b28b4SRussell King pin->gpiod = gpiod; 2513f19b00daSKim, Milo list_add(&pin->list, ®ulator_ena_gpio_list); 2514f19b00daSKim, Milo 2515f19b00daSKim, Milo update_ena_gpio_to_rdev: 2516f19b00daSKim, Milo pin->request_count++; 2517f19b00daSKim, Milo rdev->ena_pin = pin; 2518467bf301SMichał Mirosław 2519467bf301SMichał Mirosław mutex_unlock(®ulator_list_mutex); 2520467bf301SMichał Mirosław kfree(new_pin); 2521467bf301SMichał Mirosław 2522f19b00daSKim, Milo return 0; 2523f19b00daSKim, Milo } 2524f19b00daSKim, Milo 2525f19b00daSKim, Milo static void regulator_ena_gpio_free(struct regulator_dev *rdev) 2526f19b00daSKim, Milo { 2527f19b00daSKim, Milo struct regulator_enable_gpio *pin, *n; 2528f19b00daSKim, Milo 2529f19b00daSKim, Milo if (!rdev->ena_pin) 2530f19b00daSKim, Milo return; 2531f19b00daSKim, Milo 2532f19b00daSKim, Milo /* Free the GPIO only in case of no use */ 2533f19b00daSKim, Milo list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { 25342dbf0855SMichał Mirosław if (pin != rdev->ena_pin) 25352dbf0855SMichał Mirosław continue; 25362dbf0855SMichał Mirosław 25372dbf0855SMichał Mirosław if (--pin->request_count) 25382dbf0855SMichał Mirosław break; 25392dbf0855SMichał Mirosław 254078927aa4SLinus Walleij gpiod_put(pin->gpiod); 2541f19b00daSKim, Milo list_del(&pin->list); 2542f19b00daSKim, Milo kfree(pin); 25432dbf0855SMichał Mirosław break; 25442dbf0855SMichał Mirosław } 25452dbf0855SMichał Mirosław 254660a2362fSSeung-Woo Kim rdev->ena_pin = NULL; 2547f19b00daSKim, Milo } 2548f19b00daSKim, Milo 2549967cfb18SKim, Milo /** 255031d6eebfSRobert P. J. Day * regulator_ena_gpio_ctrl - balance enable_count of each GPIO and actual GPIO pin control 255131d6eebfSRobert P. J. Day * @rdev: regulator_dev structure 255231d6eebfSRobert P. J. Day * @enable: enable GPIO at initial use? 255331d6eebfSRobert P. J. Day * 2554967cfb18SKim, Milo * GPIO is enabled in case of initial use. (enable_count is 0) 2555967cfb18SKim, Milo * GPIO is disabled when it is not shared any more. (enable_count <= 1) 2556967cfb18SKim, Milo */ 2557967cfb18SKim, Milo static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) 2558967cfb18SKim, Milo { 2559967cfb18SKim, Milo struct regulator_enable_gpio *pin = rdev->ena_pin; 2560967cfb18SKim, Milo 2561967cfb18SKim, Milo if (!pin) 2562967cfb18SKim, Milo return -EINVAL; 2563967cfb18SKim, Milo 2564967cfb18SKim, Milo if (enable) { 2565967cfb18SKim, Milo /* Enable GPIO at initial use */ 2566967cfb18SKim, Milo if (pin->enable_count == 0) 256701dc79cdSLinus Walleij gpiod_set_value_cansleep(pin->gpiod, 1); 2568967cfb18SKim, Milo 2569967cfb18SKim, Milo pin->enable_count++; 2570967cfb18SKim, Milo } else { 2571967cfb18SKim, Milo if (pin->enable_count > 1) { 2572967cfb18SKim, Milo pin->enable_count--; 2573967cfb18SKim, Milo return 0; 2574967cfb18SKim, Milo } 2575967cfb18SKim, Milo 2576967cfb18SKim, Milo /* Disable GPIO if not used */ 2577967cfb18SKim, Milo if (pin->enable_count <= 1) { 257801dc79cdSLinus Walleij gpiod_set_value_cansleep(pin->gpiod, 0); 2579967cfb18SKim, Milo pin->enable_count = 0; 2580967cfb18SKim, Milo } 2581967cfb18SKim, Milo } 2582967cfb18SKim, Milo 2583967cfb18SKim, Milo return 0; 2584967cfb18SKim, Milo } 2585967cfb18SKim, Milo 258679fd1141SGuodong Xu /** 2587a38dce4cSBrian Norris * _regulator_delay_helper - a delay helper function 258879fd1141SGuodong Xu * @delay: time to delay in microseconds 258979fd1141SGuodong Xu * 25905df529d4SThierry Reding * Delay for the requested amount of time as per the guidelines in: 25915df529d4SThierry Reding * 2592458f69efSMauro Carvalho Chehab * Documentation/timers/timers-howto.rst 25935df529d4SThierry Reding * 2594a38dce4cSBrian Norris * The assumption here is that these regulator operations will never used in 25955df529d4SThierry Reding * atomic context and therefore sleeping functions can be used. 25965df529d4SThierry Reding */ 2597a38dce4cSBrian Norris static void _regulator_delay_helper(unsigned int delay) 259879fd1141SGuodong Xu { 25995df529d4SThierry Reding unsigned int ms = delay / 1000; 26005df529d4SThierry Reding unsigned int us = delay % 1000; 26015df529d4SThierry Reding 26025df529d4SThierry Reding if (ms > 0) { 26035df529d4SThierry Reding /* 26045df529d4SThierry Reding * For small enough values, handle super-millisecond 26055df529d4SThierry Reding * delays in the usleep_range() call below. 26065df529d4SThierry Reding */ 26075df529d4SThierry Reding if (ms < 20) 26085df529d4SThierry Reding us += ms * 1000; 26095df529d4SThierry Reding else 26105df529d4SThierry Reding msleep(ms); 26115df529d4SThierry Reding } 26125df529d4SThierry Reding 26135df529d4SThierry Reding /* 26145df529d4SThierry Reding * Give the scheduler some room to coalesce with any other 26155df529d4SThierry Reding * wakeup sources. For delays shorter than 10 us, don't even 26165df529d4SThierry Reding * bother setting up high-resolution timers and just busy- 26175df529d4SThierry Reding * loop. 26185df529d4SThierry Reding */ 26195df529d4SThierry Reding if (us >= 10) 26205df529d4SThierry Reding usleep_range(us, us + 100); 26215df529d4SThierry Reding else 26225df529d4SThierry Reding udelay(us); 26235c5659d0SMark Brown } 26245c5659d0SMark Brown 2625f7d7ad42SSumit Semwal /** 2626f7d7ad42SSumit Semwal * _regulator_check_status_enabled 2627f7d7ad42SSumit Semwal * 2628f7d7ad42SSumit Semwal * A helper function to check if the regulator status can be interpreted 2629f7d7ad42SSumit Semwal * as 'regulator is enabled'. 2630f7d7ad42SSumit Semwal * @rdev: the regulator device to check 2631f7d7ad42SSumit Semwal * 2632f7d7ad42SSumit Semwal * Return: 2633f7d7ad42SSumit Semwal * * 1 - if status shows regulator is in enabled state 2634f7d7ad42SSumit Semwal * * 0 - if not enabled state 2635f7d7ad42SSumit Semwal * * Error Value - as received from ops->get_status() 2636f7d7ad42SSumit Semwal */ 2637f7d7ad42SSumit Semwal static inline int _regulator_check_status_enabled(struct regulator_dev *rdev) 2638f7d7ad42SSumit Semwal { 2639f7d7ad42SSumit Semwal int ret = rdev->desc->ops->get_status(rdev); 2640f7d7ad42SSumit Semwal 2641f7d7ad42SSumit Semwal if (ret < 0) { 2642f7d7ad42SSumit Semwal rdev_info(rdev, "get_status returned error: %d\n", ret); 2643f7d7ad42SSumit Semwal return ret; 2644f7d7ad42SSumit Semwal } 2645f7d7ad42SSumit Semwal 2646f7d7ad42SSumit Semwal switch (ret) { 2647f7d7ad42SSumit Semwal case REGULATOR_STATUS_OFF: 2648f7d7ad42SSumit Semwal case REGULATOR_STATUS_ERROR: 2649f7d7ad42SSumit Semwal case REGULATOR_STATUS_UNDEFINED: 2650f7d7ad42SSumit Semwal return 0; 2651f7d7ad42SSumit Semwal default: 2652f7d7ad42SSumit Semwal return 1; 2653f7d7ad42SSumit Semwal } 2654f7d7ad42SSumit Semwal } 2655f7d7ad42SSumit Semwal 26565c5659d0SMark Brown static int _regulator_do_enable(struct regulator_dev *rdev) 26575c5659d0SMark Brown { 26585c5659d0SMark Brown int ret, delay; 26595c5659d0SMark Brown 26605c5659d0SMark Brown /* Query before enabling in case configuration dependent. */ 26615c5659d0SMark Brown ret = _regulator_get_enable_time(rdev); 26625c5659d0SMark Brown if (ret >= 0) { 26635c5659d0SMark Brown delay = ret; 26645c5659d0SMark Brown } else { 266561aab5adSMichał Mirosław rdev_warn(rdev, "enable_time() failed: %pe\n", ERR_PTR(ret)); 2666414c70cbSLiam Girdwood delay = 0; 2667414c70cbSLiam Girdwood } 26685c5659d0SMark Brown 2669414c70cbSLiam Girdwood trace_regulator_enable(rdev_get_name(rdev)); 2670414c70cbSLiam Girdwood 2671a8ce7bd8SVincent Whitchurch if (rdev->desc->off_on_delay && rdev->last_off) { 2672871f5650SGuodong Xu /* if needed, keep a distance of off_on_delay from last time 2673871f5650SGuodong Xu * this regulator was disabled. 2674871f5650SGuodong Xu */ 2675a8ce7bd8SVincent Whitchurch ktime_t end = ktime_add_us(rdev->last_off, rdev->desc->off_on_delay); 2676a8ce7bd8SVincent Whitchurch s64 remaining = ktime_us_delta(end, ktime_get()); 2677871f5650SGuodong Xu 2678a8ce7bd8SVincent Whitchurch if (remaining > 0) 2679a38dce4cSBrian Norris _regulator_delay_helper(remaining); 2680871f5650SGuodong Xu } 2681871f5650SGuodong Xu 2682414c70cbSLiam Girdwood if (rdev->ena_pin) { 268329d62ec5SDoug Anderson if (!rdev->ena_gpio_state) { 26849a2372faSMark Brown ret = regulator_ena_gpio_ctrl(rdev, true); 2685414c70cbSLiam Girdwood if (ret < 0) 2686414c70cbSLiam Girdwood return ret; 26879a2372faSMark Brown rdev->ena_gpio_state = 1; 268829d62ec5SDoug Anderson } 26899a2372faSMark Brown } else if (rdev->desc->ops->enable) { 26909a2372faSMark Brown ret = rdev->desc->ops->enable(rdev); 26919a2372faSMark Brown if (ret < 0) 26929a2372faSMark Brown return ret; 26939a2372faSMark Brown } else { 26949a2372faSMark Brown return -EINVAL; 26955c5659d0SMark Brown } 26969a2372faSMark Brown 26979a2372faSMark Brown /* Allow the regulator to ramp; it would be useful to extend 269831aae2beSMark Brown * this for bulk operations so that the regulators can ramp 269969b8821eSShubhankar Kuranagatti * together. 270069b8821eSShubhankar Kuranagatti */ 27015da84fd9SJoe Perches trace_regulator_enable_delay(rdev_get_name(rdev)); 2702414c70cbSLiam Girdwood 2703f7d7ad42SSumit Semwal /* If poll_enabled_time is set, poll upto the delay calculated 2704f7d7ad42SSumit Semwal * above, delaying poll_enabled_time uS to check if the regulator 2705f7d7ad42SSumit Semwal * actually got enabled. 2706a38dce4cSBrian Norris * If the regulator isn't enabled after our delay helper has expired, 2707a38dce4cSBrian Norris * return -ETIMEDOUT. 2708f7d7ad42SSumit Semwal */ 2709f7d7ad42SSumit Semwal if (rdev->desc->poll_enabled_time) { 27108d8e1659SPatrick Rudolph int time_remaining = delay; 2711f7d7ad42SSumit Semwal 2712f7d7ad42SSumit Semwal while (time_remaining > 0) { 2713a38dce4cSBrian Norris _regulator_delay_helper(rdev->desc->poll_enabled_time); 2714f7d7ad42SSumit Semwal 2715f7d7ad42SSumit Semwal if (rdev->desc->ops->get_status) { 2716f7d7ad42SSumit Semwal ret = _regulator_check_status_enabled(rdev); 2717f7d7ad42SSumit Semwal if (ret < 0) 2718f7d7ad42SSumit Semwal return ret; 2719f7d7ad42SSumit Semwal else if (ret) 2720f7d7ad42SSumit Semwal break; 2721f7d7ad42SSumit Semwal } else if (rdev->desc->ops->is_enabled(rdev)) 2722f7d7ad42SSumit Semwal break; 2723f7d7ad42SSumit Semwal 2724f7d7ad42SSumit Semwal time_remaining -= rdev->desc->poll_enabled_time; 2725f7d7ad42SSumit Semwal } 2726f7d7ad42SSumit Semwal 2727f7d7ad42SSumit Semwal if (time_remaining <= 0) { 2728f7d7ad42SSumit Semwal rdev_err(rdev, "Enabled check timed out\n"); 2729f7d7ad42SSumit Semwal return -ETIMEDOUT; 2730f7d7ad42SSumit Semwal } 2731f7d7ad42SSumit Semwal } else { 2732a38dce4cSBrian Norris _regulator_delay_helper(delay); 2733f7d7ad42SSumit Semwal } 2734a7433cffSLinus Walleij 2735414c70cbSLiam Girdwood trace_regulator_enable_complete(rdev_get_name(rdev)); 2736414c70cbSLiam Girdwood 27379a2372faSMark Brown return 0; 27389a2372faSMark Brown } 27399a2372faSMark Brown 27405451781dSDouglas Anderson /** 27415451781dSDouglas Anderson * _regulator_handle_consumer_enable - handle that a consumer enabled 27425451781dSDouglas Anderson * @regulator: regulator source 27435451781dSDouglas Anderson * 27445451781dSDouglas Anderson * Some things on a regulator consumer (like the contribution towards total 27455451781dSDouglas Anderson * load on the regulator) only have an effect when the consumer wants the 27465451781dSDouglas Anderson * regulator enabled. Explained in example with two consumers of the same 27475451781dSDouglas Anderson * regulator: 27485451781dSDouglas Anderson * consumer A: set_load(100); => total load = 0 27495451781dSDouglas Anderson * consumer A: regulator_enable(); => total load = 100 27505451781dSDouglas Anderson * consumer B: set_load(1000); => total load = 100 27515451781dSDouglas Anderson * consumer B: regulator_enable(); => total load = 1100 27525451781dSDouglas Anderson * consumer A: regulator_disable(); => total_load = 1000 27535451781dSDouglas Anderson * 27545451781dSDouglas Anderson * This function (together with _regulator_handle_consumer_disable) is 27555451781dSDouglas Anderson * responsible for keeping track of the refcount for a given regulator consumer 27565451781dSDouglas Anderson * and applying / unapplying these things. 27575451781dSDouglas Anderson * 27585451781dSDouglas Anderson * Returns 0 upon no error; -error upon error. 27595451781dSDouglas Anderson */ 27605451781dSDouglas Anderson static int _regulator_handle_consumer_enable(struct regulator *regulator) 2761414c70cbSLiam Girdwood { 2762c32f1ebfSAndrew Halaney int ret; 27635451781dSDouglas Anderson struct regulator_dev *rdev = regulator->rdev; 27645451781dSDouglas Anderson 27655451781dSDouglas Anderson lockdep_assert_held_once(&rdev->mutex.base); 27665451781dSDouglas Anderson 27675451781dSDouglas Anderson regulator->enable_count++; 2768c32f1ebfSAndrew Halaney if (regulator->uA_load && regulator->enable_count == 1) { 2769c32f1ebfSAndrew Halaney ret = drms_uA_update(rdev); 2770c32f1ebfSAndrew Halaney if (ret) 2771c32f1ebfSAndrew Halaney regulator->enable_count--; 2772c32f1ebfSAndrew Halaney return ret; 2773c32f1ebfSAndrew Halaney } 27745451781dSDouglas Anderson 27755451781dSDouglas Anderson return 0; 27765451781dSDouglas Anderson } 27775451781dSDouglas Anderson 27785451781dSDouglas Anderson /** 27795451781dSDouglas Anderson * _regulator_handle_consumer_disable - handle that a consumer disabled 27805451781dSDouglas Anderson * @regulator: regulator source 27815451781dSDouglas Anderson * 27825451781dSDouglas Anderson * The opposite of _regulator_handle_consumer_enable(). 27835451781dSDouglas Anderson * 27845451781dSDouglas Anderson * Returns 0 upon no error; -error upon error. 27855451781dSDouglas Anderson */ 27865451781dSDouglas Anderson static int _regulator_handle_consumer_disable(struct regulator *regulator) 27875451781dSDouglas Anderson { 27885451781dSDouglas Anderson struct regulator_dev *rdev = regulator->rdev; 27895451781dSDouglas Anderson 27905451781dSDouglas Anderson lockdep_assert_held_once(&rdev->mutex.base); 27915451781dSDouglas Anderson 27925451781dSDouglas Anderson if (!regulator->enable_count) { 27935451781dSDouglas Anderson rdev_err(rdev, "Underflow of regulator enable count\n"); 27945451781dSDouglas Anderson return -EINVAL; 27955451781dSDouglas Anderson } 27965451781dSDouglas Anderson 27975451781dSDouglas Anderson regulator->enable_count--; 27985451781dSDouglas Anderson if (regulator->uA_load && regulator->enable_count == 0) 27995451781dSDouglas Anderson return drms_uA_update(rdev); 28005451781dSDouglas Anderson 28015451781dSDouglas Anderson return 0; 28025451781dSDouglas Anderson } 28035451781dSDouglas Anderson 28045451781dSDouglas Anderson /* locks held by regulator_enable() */ 28055451781dSDouglas Anderson static int _regulator_enable(struct regulator *regulator) 28065451781dSDouglas Anderson { 28075451781dSDouglas Anderson struct regulator_dev *rdev = regulator->rdev; 2808414c70cbSLiam Girdwood int ret; 2809414c70cbSLiam Girdwood 2810f8702f9eSDmitry Osipenko lockdep_assert_held_once(&rdev->mutex.base); 2811f8702f9eSDmitry Osipenko 28121fc12b05SDouglas Anderson if (rdev->use_count == 0 && rdev->supply) { 28135451781dSDouglas Anderson ret = _regulator_enable(rdev->supply); 2814f8702f9eSDmitry Osipenko if (ret < 0) 2815f8702f9eSDmitry Osipenko return ret; 2816f8702f9eSDmitry Osipenko } 2817f8702f9eSDmitry Osipenko 2818f8702f9eSDmitry Osipenko /* balance only if there are regulators coupled */ 2819f8702f9eSDmitry Osipenko if (rdev->coupling_desc.n_coupled > 1) { 2820f8702f9eSDmitry Osipenko ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 2821f8702f9eSDmitry Osipenko if (ret < 0) 2822f8702f9eSDmitry Osipenko goto err_disable_supply; 2823f8702f9eSDmitry Osipenko } 282470cfef26SKrzysztof Kozlowski 28255451781dSDouglas Anderson ret = _regulator_handle_consumer_enable(regulator); 28265451781dSDouglas Anderson if (ret < 0) 28275451781dSDouglas Anderson goto err_disable_supply; 2828cf7bbcdfSMark Brown 2829414c70cbSLiam Girdwood if (rdev->use_count == 0) { 283072241e31SSebastian Fricke /* 283172241e31SSebastian Fricke * The regulator may already be enabled if it's not switchable 283272241e31SSebastian Fricke * or was left on 283372241e31SSebastian Fricke */ 2834414c70cbSLiam Girdwood ret = _regulator_is_enabled(rdev); 2835414c70cbSLiam Girdwood if (ret == -EINVAL || ret == 0) { 28368a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, 2837f8702f9eSDmitry Osipenko REGULATOR_CHANGE_STATUS)) { 2838f8702f9eSDmitry Osipenko ret = -EPERM; 28395451781dSDouglas Anderson goto err_consumer_disable; 2840f8702f9eSDmitry Osipenko } 2841412aec61SDavid Brownell 2842414c70cbSLiam Girdwood ret = _regulator_do_enable(rdev); 2843412aec61SDavid Brownell if (ret < 0) 28445451781dSDouglas Anderson goto err_consumer_disable; 2845414c70cbSLiam Girdwood 2846264b88c9SHarald Geyer _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE, 2847264b88c9SHarald Geyer NULL); 2848414c70cbSLiam Girdwood } else if (ret < 0) { 284961aab5adSMichał Mirosław rdev_err(rdev, "is_enabled() failed: %pe\n", ERR_PTR(ret)); 28505451781dSDouglas Anderson goto err_consumer_disable; 2851414c70cbSLiam Girdwood } 2852414c70cbSLiam Girdwood /* Fallthrough on positive return values - already enabled */ 2853414c70cbSLiam Girdwood } 2854414c70cbSLiam Girdwood 2855414c70cbSLiam Girdwood rdev->use_count++; 2856414c70cbSLiam Girdwood 2857414c70cbSLiam Girdwood return 0; 2858f8702f9eSDmitry Osipenko 28595451781dSDouglas Anderson err_consumer_disable: 28605451781dSDouglas Anderson _regulator_handle_consumer_disable(regulator); 28615451781dSDouglas Anderson 2862f8702f9eSDmitry Osipenko err_disable_supply: 28631fc12b05SDouglas Anderson if (rdev->use_count == 0 && rdev->supply) 28645451781dSDouglas Anderson _regulator_disable(rdev->supply); 2865f8702f9eSDmitry Osipenko 2866f8702f9eSDmitry Osipenko return ret; 2867414c70cbSLiam Girdwood } 2868414c70cbSLiam Girdwood 2869414c70cbSLiam Girdwood /** 2870414c70cbSLiam Girdwood * regulator_enable - enable regulator output 2871414c70cbSLiam Girdwood * @regulator: regulator source 2872414c70cbSLiam Girdwood * 2873414c70cbSLiam Girdwood * Request that the regulator be enabled with the regulator output at 2874414c70cbSLiam Girdwood * the predefined voltage or current value. Calls to regulator_enable() 2875414c70cbSLiam Girdwood * must be balanced with calls to regulator_disable(). 2876414c70cbSLiam Girdwood * 2877414c70cbSLiam Girdwood * NOTE: the output value can be set by other drivers, boot loader or may be 2878414c70cbSLiam Girdwood * hardwired in the regulator. 2879414c70cbSLiam Girdwood */ 2880414c70cbSLiam Girdwood int regulator_enable(struct regulator *regulator) 2881414c70cbSLiam Girdwood { 2882414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 2883f8702f9eSDmitry Osipenko struct ww_acquire_ctx ww_ctx; 28845451781dSDouglas Anderson int ret; 28856492bc1bSMark Brown 2886f8702f9eSDmitry Osipenko regulator_lock_dependent(rdev, &ww_ctx); 28875451781dSDouglas Anderson ret = _regulator_enable(regulator); 2888f8702f9eSDmitry Osipenko regulator_unlock_dependent(rdev, &ww_ctx); 28893801b86aSMark Brown 2890414c70cbSLiam Girdwood return ret; 2891414c70cbSLiam Girdwood } 2892414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_enable); 2893414c70cbSLiam Girdwood 28945c5659d0SMark Brown static int _regulator_do_disable(struct regulator_dev *rdev) 28955c5659d0SMark Brown { 28965c5659d0SMark Brown int ret; 28975c5659d0SMark Brown 28985c5659d0SMark Brown trace_regulator_disable(rdev_get_name(rdev)); 28995c5659d0SMark Brown 2900967cfb18SKim, Milo if (rdev->ena_pin) { 290129d62ec5SDoug Anderson if (rdev->ena_gpio_state) { 2902967cfb18SKim, Milo ret = regulator_ena_gpio_ctrl(rdev, false); 2903967cfb18SKim, Milo if (ret < 0) 2904967cfb18SKim, Milo return ret; 29055c5659d0SMark Brown rdev->ena_gpio_state = 0; 290629d62ec5SDoug Anderson } 29075c5659d0SMark Brown 29085c5659d0SMark Brown } else if (rdev->desc->ops->disable) { 29095c5659d0SMark Brown ret = rdev->desc->ops->disable(rdev); 29105c5659d0SMark Brown if (ret != 0) 29115c5659d0SMark Brown return ret; 29125c5659d0SMark Brown } 29135c5659d0SMark Brown 2914871f5650SGuodong Xu if (rdev->desc->off_on_delay) 2915a8ce7bd8SVincent Whitchurch rdev->last_off = ktime_get(); 2916871f5650SGuodong Xu 29175c5659d0SMark Brown trace_regulator_disable_complete(rdev_get_name(rdev)); 29185c5659d0SMark Brown 29195c5659d0SMark Brown return 0; 29205c5659d0SMark Brown } 29215c5659d0SMark Brown 2922414c70cbSLiam Girdwood /* locks held by regulator_disable() */ 29235451781dSDouglas Anderson static int _regulator_disable(struct regulator *regulator) 2924414c70cbSLiam Girdwood { 29255451781dSDouglas Anderson struct regulator_dev *rdev = regulator->rdev; 2926414c70cbSLiam Girdwood int ret = 0; 2927414c70cbSLiam Girdwood 2928f8702f9eSDmitry Osipenko lockdep_assert_held_once(&rdev->mutex.base); 292970cfef26SKrzysztof Kozlowski 2930cd94b505SDavid Brownell if (WARN(rdev->use_count <= 0, 293143e7ee33SJoe Perches "unbalanced disables for %s\n", rdev_get_name(rdev))) 2932cd94b505SDavid Brownell return -EIO; 2933cd94b505SDavid Brownell 2934414c70cbSLiam Girdwood /* are we the last user and permitted to disable ? */ 293560ef66fcSMark Brown if (rdev->use_count == 1 && 293660ef66fcSMark Brown (rdev->constraints && !rdev->constraints->always_on)) { 2937414c70cbSLiam Girdwood 2938414c70cbSLiam Girdwood /* we are last user */ 29398a34e979SWEN Pingbo if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { 2940a1c8a551SRichard Fitzgerald ret = _notifier_call_chain(rdev, 2941a1c8a551SRichard Fitzgerald REGULATOR_EVENT_PRE_DISABLE, 2942a1c8a551SRichard Fitzgerald NULL); 2943a1c8a551SRichard Fitzgerald if (ret & NOTIFY_STOP_MASK) 2944a1c8a551SRichard Fitzgerald return -EINVAL; 2945a1c8a551SRichard Fitzgerald 29465c5659d0SMark Brown ret = _regulator_do_disable(rdev); 2947414c70cbSLiam Girdwood if (ret < 0) { 294861aab5adSMichał Mirosław rdev_err(rdev, "failed to disable: %pe\n", ERR_PTR(ret)); 2949a1c8a551SRichard Fitzgerald _notifier_call_chain(rdev, 2950a1c8a551SRichard Fitzgerald REGULATOR_EVENT_ABORT_DISABLE, 2951a1c8a551SRichard Fitzgerald NULL); 2952414c70cbSLiam Girdwood return ret; 2953414c70cbSLiam Girdwood } 295466fda75fSMarkus Pargmann _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, 295566fda75fSMarkus Pargmann NULL); 2956414c70cbSLiam Girdwood } 2957414c70cbSLiam Girdwood 2958414c70cbSLiam Girdwood rdev->use_count = 0; 2959414c70cbSLiam Girdwood } else if (rdev->use_count > 1) { 2960414c70cbSLiam Girdwood rdev->use_count--; 2961414c70cbSLiam Girdwood } 29623801b86aSMark Brown 29635451781dSDouglas Anderson if (ret == 0) 29645451781dSDouglas Anderson ret = _regulator_handle_consumer_disable(regulator); 29655451781dSDouglas Anderson 2966f8702f9eSDmitry Osipenko if (ret == 0 && rdev->coupling_desc.n_coupled > 1) 2967f8702f9eSDmitry Osipenko ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 2968f8702f9eSDmitry Osipenko 29691fc12b05SDouglas Anderson if (ret == 0 && rdev->use_count == 0 && rdev->supply) 29705451781dSDouglas Anderson ret = _regulator_disable(rdev->supply); 2971f8702f9eSDmitry Osipenko 2972414c70cbSLiam Girdwood return ret; 2973414c70cbSLiam Girdwood } 2974414c70cbSLiam Girdwood 2975414c70cbSLiam Girdwood /** 2976414c70cbSLiam Girdwood * regulator_disable - disable regulator output 2977414c70cbSLiam Girdwood * @regulator: regulator source 2978414c70cbSLiam Girdwood * 2979cf7bbcdfSMark Brown * Disable the regulator output voltage or current. Calls to 2980cf7bbcdfSMark Brown * regulator_enable() must be balanced with calls to 2981cf7bbcdfSMark Brown * regulator_disable(). 298269279fb9SMark Brown * 2983414c70cbSLiam Girdwood * NOTE: this will only disable the regulator output if no other consumer 2984cf7bbcdfSMark Brown * devices have it enabled, the regulator device supports disabling and 2985cf7bbcdfSMark Brown * machine constraints permit this operation. 2986414c70cbSLiam Girdwood */ 2987414c70cbSLiam Girdwood int regulator_disable(struct regulator *regulator) 2988414c70cbSLiam Girdwood { 2989412aec61SDavid Brownell struct regulator_dev *rdev = regulator->rdev; 2990f8702f9eSDmitry Osipenko struct ww_acquire_ctx ww_ctx; 29915451781dSDouglas Anderson int ret; 29926492bc1bSMark Brown 2993f8702f9eSDmitry Osipenko regulator_lock_dependent(rdev, &ww_ctx); 29945451781dSDouglas Anderson ret = _regulator_disable(regulator); 2995f8702f9eSDmitry Osipenko regulator_unlock_dependent(rdev, &ww_ctx); 29968cbf811dSJeffrey Carlyle 2997414c70cbSLiam Girdwood return ret; 2998414c70cbSLiam Girdwood } 2999414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_disable); 3000414c70cbSLiam Girdwood 3001414c70cbSLiam Girdwood /* locks held by regulator_force_disable() */ 30023801b86aSMark Brown static int _regulator_force_disable(struct regulator_dev *rdev) 3003414c70cbSLiam Girdwood { 3004414c70cbSLiam Girdwood int ret = 0; 3005414c70cbSLiam Girdwood 3006f8702f9eSDmitry Osipenko lockdep_assert_held_once(&rdev->mutex.base); 300770cfef26SKrzysztof Kozlowski 3008a1c8a551SRichard Fitzgerald ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 3009a1c8a551SRichard Fitzgerald REGULATOR_EVENT_PRE_DISABLE, NULL); 3010a1c8a551SRichard Fitzgerald if (ret & NOTIFY_STOP_MASK) 3011a1c8a551SRichard Fitzgerald return -EINVAL; 3012a1c8a551SRichard Fitzgerald 301366fda75fSMarkus Pargmann ret = _regulator_do_disable(rdev); 3014414c70cbSLiam Girdwood if (ret < 0) { 301561aab5adSMichał Mirosław rdev_err(rdev, "failed to force disable: %pe\n", ERR_PTR(ret)); 3016a1c8a551SRichard Fitzgerald _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 3017a1c8a551SRichard Fitzgerald REGULATOR_EVENT_ABORT_DISABLE, NULL); 3018414c70cbSLiam Girdwood return ret; 3019414c70cbSLiam Girdwood } 302066fda75fSMarkus Pargmann 302184b68263SMark Brown _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 302284b68263SMark Brown REGULATOR_EVENT_DISABLE, NULL); 3023414c70cbSLiam Girdwood 302466fda75fSMarkus Pargmann return 0; 3025414c70cbSLiam Girdwood } 3026414c70cbSLiam Girdwood 3027414c70cbSLiam Girdwood /** 3028414c70cbSLiam Girdwood * regulator_force_disable - force disable regulator output 3029414c70cbSLiam Girdwood * @regulator: regulator source 3030414c70cbSLiam Girdwood * 3031414c70cbSLiam Girdwood * Forcibly disable the regulator output voltage or current. 3032414c70cbSLiam Girdwood * NOTE: this *will* disable the regulator output even if other consumer 3033414c70cbSLiam Girdwood * devices have it enabled. This should be used for situations when device 3034414c70cbSLiam Girdwood * damage will likely occur if the regulator is not disabled (e.g. over temp). 3035414c70cbSLiam Girdwood */ 3036414c70cbSLiam Girdwood int regulator_force_disable(struct regulator *regulator) 3037414c70cbSLiam Girdwood { 303882d15839SMark Brown struct regulator_dev *rdev = regulator->rdev; 3039f8702f9eSDmitry Osipenko struct ww_acquire_ctx ww_ctx; 3040414c70cbSLiam Girdwood int ret; 3041414c70cbSLiam Girdwood 3042f8702f9eSDmitry Osipenko regulator_lock_dependent(rdev, &ww_ctx); 30435451781dSDouglas Anderson 30443801b86aSMark Brown ret = _regulator_force_disable(regulator->rdev); 30455451781dSDouglas Anderson 30469243a195SMaciej Purski if (rdev->coupling_desc.n_coupled > 1) 30479243a195SMaciej Purski regulator_balance_voltage(rdev, PM_SUSPEND_ON); 30485451781dSDouglas Anderson 30495451781dSDouglas Anderson if (regulator->uA_load) { 30505451781dSDouglas Anderson regulator->uA_load = 0; 30515451781dSDouglas Anderson ret = drms_uA_update(rdev); 30525451781dSDouglas Anderson } 30535451781dSDouglas Anderson 30541fc12b05SDouglas Anderson if (rdev->use_count != 0 && rdev->supply) 30551fc12b05SDouglas Anderson _regulator_disable(rdev->supply); 30568cbf811dSJeffrey Carlyle 30571fc12b05SDouglas Anderson regulator_unlock_dependent(rdev, &ww_ctx); 30588cbf811dSJeffrey Carlyle 3059414c70cbSLiam Girdwood return ret; 3060414c70cbSLiam Girdwood } 3061414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_force_disable); 3062414c70cbSLiam Girdwood 3063da07ecd9SMark Brown static void regulator_disable_work(struct work_struct *work) 3064da07ecd9SMark Brown { 3065da07ecd9SMark Brown struct regulator_dev *rdev = container_of(work, struct regulator_dev, 3066da07ecd9SMark Brown disable_work.work); 3067f8702f9eSDmitry Osipenko struct ww_acquire_ctx ww_ctx; 3068da07ecd9SMark Brown int count, i, ret; 30695451781dSDouglas Anderson struct regulator *regulator; 30705451781dSDouglas Anderson int total_count = 0; 3071da07ecd9SMark Brown 3072f8702f9eSDmitry Osipenko regulator_lock_dependent(rdev, &ww_ctx); 3073da07ecd9SMark Brown 3074c9ccaa0cSTirupathi Reddy /* 3075c9ccaa0cSTirupathi Reddy * Workqueue functions queue the new work instance while the previous 3076c9ccaa0cSTirupathi Reddy * work instance is being processed. Cancel the queued work instance 3077c9ccaa0cSTirupathi Reddy * as the work instance under processing does the job of the queued 3078c9ccaa0cSTirupathi Reddy * work instance. 3079c9ccaa0cSTirupathi Reddy */ 3080c9ccaa0cSTirupathi Reddy cancel_delayed_work(&rdev->disable_work); 3081c9ccaa0cSTirupathi Reddy 30825451781dSDouglas Anderson list_for_each_entry(regulator, &rdev->consumer_list, list) { 30835451781dSDouglas Anderson count = regulator->deferred_disables; 30845451781dSDouglas Anderson 30855451781dSDouglas Anderson if (!count) 30865451781dSDouglas Anderson continue; 30875451781dSDouglas Anderson 30885451781dSDouglas Anderson total_count += count; 30895451781dSDouglas Anderson regulator->deferred_disables = 0; 30905451781dSDouglas Anderson 3091da07ecd9SMark Brown for (i = 0; i < count; i++) { 30925451781dSDouglas Anderson ret = _regulator_disable(regulator); 3093da07ecd9SMark Brown if (ret != 0) 309461aab5adSMichał Mirosław rdev_err(rdev, "Deferred disable failed: %pe\n", 309561aab5adSMichał Mirosław ERR_PTR(ret)); 3096da07ecd9SMark Brown } 30975451781dSDouglas Anderson } 30985451781dSDouglas Anderson WARN_ON(!total_count); 3099da07ecd9SMark Brown 3100f8702f9eSDmitry Osipenko if (rdev->coupling_desc.n_coupled > 1) 3101f8702f9eSDmitry Osipenko regulator_balance_voltage(rdev, PM_SUSPEND_ON); 3102f8702f9eSDmitry Osipenko 3103f8702f9eSDmitry Osipenko regulator_unlock_dependent(rdev, &ww_ctx); 3104da07ecd9SMark Brown } 3105da07ecd9SMark Brown 3106da07ecd9SMark Brown /** 3107da07ecd9SMark Brown * regulator_disable_deferred - disable regulator output with delay 3108da07ecd9SMark Brown * @regulator: regulator source 310948f1b4efSKrzysztof Kozlowski * @ms: milliseconds until the regulator is disabled 3110da07ecd9SMark Brown * 3111da07ecd9SMark Brown * Execute regulator_disable() on the regulator after a delay. This 3112da07ecd9SMark Brown * is intended for use with devices that require some time to quiesce. 3113da07ecd9SMark Brown * 3114da07ecd9SMark Brown * NOTE: this will only disable the regulator output if no other consumer 3115da07ecd9SMark Brown * devices have it enabled, the regulator device supports disabling and 3116da07ecd9SMark Brown * machine constraints permit this operation. 3117da07ecd9SMark Brown */ 3118da07ecd9SMark Brown int regulator_disable_deferred(struct regulator *regulator, int ms) 3119da07ecd9SMark Brown { 3120da07ecd9SMark Brown struct regulator_dev *rdev = regulator->rdev; 3121da07ecd9SMark Brown 31222b5a24a0SMark Brown if (!ms) 31232b5a24a0SMark Brown return regulator_disable(regulator); 31242b5a24a0SMark Brown 312566cf9a7eSMaciej Purski regulator_lock(rdev); 31265451781dSDouglas Anderson regulator->deferred_disables++; 3127c9ccaa0cSTirupathi Reddy mod_delayed_work(system_power_efficient_wq, &rdev->disable_work, 3128c9ccaa0cSTirupathi Reddy msecs_to_jiffies(ms)); 312966cf9a7eSMaciej Purski regulator_unlock(rdev); 3130da07ecd9SMark Brown 3131aa59802dSMark Brown return 0; 3132da07ecd9SMark Brown } 3133da07ecd9SMark Brown EXPORT_SYMBOL_GPL(regulator_disable_deferred); 3134da07ecd9SMark Brown 3135414c70cbSLiam Girdwood static int _regulator_is_enabled(struct regulator_dev *rdev) 3136414c70cbSLiam Girdwood { 313765f73508SMark Brown /* A GPIO control always takes precedence */ 31387b74d149SKim, Milo if (rdev->ena_pin) 313965f73508SMark Brown return rdev->ena_gpio_state; 314065f73508SMark Brown 31419a7f6a4cSMark Brown /* If we don't know then assume that the regulator is always on */ 31429332546fSMark Brown if (!rdev->desc->ops->is_enabled) 31439a7f6a4cSMark Brown return 1; 3144414c70cbSLiam Girdwood 31459332546fSMark Brown return rdev->desc->ops->is_enabled(rdev); 3146414c70cbSLiam Girdwood } 3147414c70cbSLiam Girdwood 31483d67fe95SMaciej Purski static int _regulator_list_voltage(struct regulator_dev *rdev, 31493a40cfc3SSascha Hauer unsigned selector, int lock) 31503a40cfc3SSascha Hauer { 31513a40cfc3SSascha Hauer const struct regulator_ops *ops = rdev->desc->ops; 31523a40cfc3SSascha Hauer int ret; 31533a40cfc3SSascha Hauer 31543a40cfc3SSascha Hauer if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) 31553a40cfc3SSascha Hauer return rdev->desc->fixed_uV; 31563a40cfc3SSascha Hauer 31573a40cfc3SSascha Hauer if (ops->list_voltage) { 31583a40cfc3SSascha Hauer if (selector >= rdev->desc->n_voltages) 31593a40cfc3SSascha Hauer return -EINVAL; 316055cca739SClaudiu Beznea if (selector < rdev->desc->linear_min_sel) 316155cca739SClaudiu Beznea return 0; 31623a40cfc3SSascha Hauer if (lock) 316366cf9a7eSMaciej Purski regulator_lock(rdev); 31643a40cfc3SSascha Hauer ret = ops->list_voltage(rdev, selector); 31653a40cfc3SSascha Hauer if (lock) 316666cf9a7eSMaciej Purski regulator_unlock(rdev); 3167fd086045SMatthias Kaehlcke } else if (rdev->is_switch && rdev->supply) { 31683d67fe95SMaciej Purski ret = _regulator_list_voltage(rdev->supply->rdev, 31693d67fe95SMaciej Purski selector, lock); 31703a40cfc3SSascha Hauer } else { 31713a40cfc3SSascha Hauer return -EINVAL; 31723a40cfc3SSascha Hauer } 31733a40cfc3SSascha Hauer 31743a40cfc3SSascha Hauer if (ret > 0) { 31753a40cfc3SSascha Hauer if (ret < rdev->constraints->min_uV) 31763a40cfc3SSascha Hauer ret = 0; 31773a40cfc3SSascha Hauer else if (ret > rdev->constraints->max_uV) 31783a40cfc3SSascha Hauer ret = 0; 31793a40cfc3SSascha Hauer } 31803a40cfc3SSascha Hauer 31813a40cfc3SSascha Hauer return ret; 31823a40cfc3SSascha Hauer } 31833a40cfc3SSascha Hauer 3184414c70cbSLiam Girdwood /** 3185414c70cbSLiam Girdwood * regulator_is_enabled - is the regulator output enabled 3186414c70cbSLiam Girdwood * @regulator: regulator source 3187414c70cbSLiam Girdwood * 3188412aec61SDavid Brownell * Returns positive if the regulator driver backing the source/client 3189412aec61SDavid Brownell * has requested that the device be enabled, zero if it hasn't, else a 3190412aec61SDavid Brownell * negative errno code. 3191412aec61SDavid Brownell * 3192412aec61SDavid Brownell * Note that the device backing this regulator handle can have multiple 3193412aec61SDavid Brownell * users, so it might be enabled even if regulator_enable() was never 3194412aec61SDavid Brownell * called for this particular source. 3195414c70cbSLiam Girdwood */ 3196414c70cbSLiam Girdwood int regulator_is_enabled(struct regulator *regulator) 3197414c70cbSLiam Girdwood { 31989332546fSMark Brown int ret; 31999332546fSMark Brown 32006492bc1bSMark Brown if (regulator->always_on) 32016492bc1bSMark Brown return 1; 32026492bc1bSMark Brown 3203f8702f9eSDmitry Osipenko regulator_lock(regulator->rdev); 32049332546fSMark Brown ret = _regulator_is_enabled(regulator->rdev); 3205f8702f9eSDmitry Osipenko regulator_unlock(regulator->rdev); 32069332546fSMark Brown 32079332546fSMark Brown return ret; 3208414c70cbSLiam Girdwood } 3209414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_is_enabled); 3210414c70cbSLiam Girdwood 3211414c70cbSLiam Girdwood /** 32124367cfdcSDavid Brownell * regulator_count_voltages - count regulator_list_voltage() selectors 32134367cfdcSDavid Brownell * @regulator: regulator source 32144367cfdcSDavid Brownell * 32154367cfdcSDavid Brownell * Returns number of selectors, or negative errno. Selectors are 32164367cfdcSDavid Brownell * numbered starting at zero, and typically correspond to bitfields 32174367cfdcSDavid Brownell * in hardware registers. 32184367cfdcSDavid Brownell */ 32194367cfdcSDavid Brownell int regulator_count_voltages(struct regulator *regulator) 32204367cfdcSDavid Brownell { 32214367cfdcSDavid Brownell struct regulator_dev *rdev = regulator->rdev; 32224367cfdcSDavid Brownell 322326988efeSJavier Martinez Canillas if (rdev->desc->n_voltages) 322426988efeSJavier Martinez Canillas return rdev->desc->n_voltages; 322526988efeSJavier Martinez Canillas 3226fd086045SMatthias Kaehlcke if (!rdev->is_switch || !rdev->supply) 322726988efeSJavier Martinez Canillas return -EINVAL; 322826988efeSJavier Martinez Canillas 322926988efeSJavier Martinez Canillas return regulator_count_voltages(rdev->supply); 32304367cfdcSDavid Brownell } 32314367cfdcSDavid Brownell EXPORT_SYMBOL_GPL(regulator_count_voltages); 32324367cfdcSDavid Brownell 32334367cfdcSDavid Brownell /** 32344367cfdcSDavid Brownell * regulator_list_voltage - enumerate supported voltages 32354367cfdcSDavid Brownell * @regulator: regulator source 32364367cfdcSDavid Brownell * @selector: identify voltage to list 32374367cfdcSDavid Brownell * Context: can sleep 32384367cfdcSDavid Brownell * 32394367cfdcSDavid Brownell * Returns a voltage that can be passed to @regulator_set_voltage(), 324088393161SThomas Weber * zero if this selector code can't be used on this system, or a 32414367cfdcSDavid Brownell * negative errno. 32424367cfdcSDavid Brownell */ 32434367cfdcSDavid Brownell int regulator_list_voltage(struct regulator *regulator, unsigned selector) 32444367cfdcSDavid Brownell { 32453d67fe95SMaciej Purski return _regulator_list_voltage(regulator->rdev, selector, 1); 32464367cfdcSDavid Brownell } 32474367cfdcSDavid Brownell EXPORT_SYMBOL_GPL(regulator_list_voltage); 32484367cfdcSDavid Brownell 32494367cfdcSDavid Brownell /** 325004eca28cSTuomas Tynkkynen * regulator_get_regmap - get the regulator's register map 325104eca28cSTuomas Tynkkynen * @regulator: regulator source 325204eca28cSTuomas Tynkkynen * 325304eca28cSTuomas Tynkkynen * Returns the register map for the given regulator, or an ERR_PTR value 325404eca28cSTuomas Tynkkynen * if the regulator doesn't use regmap. 325504eca28cSTuomas Tynkkynen */ 325604eca28cSTuomas Tynkkynen struct regmap *regulator_get_regmap(struct regulator *regulator) 325704eca28cSTuomas Tynkkynen { 325804eca28cSTuomas Tynkkynen struct regmap *map = regulator->rdev->regmap; 325904eca28cSTuomas Tynkkynen 326004eca28cSTuomas Tynkkynen return map ? map : ERR_PTR(-EOPNOTSUPP); 326104eca28cSTuomas Tynkkynen } 326204eca28cSTuomas Tynkkynen 326304eca28cSTuomas Tynkkynen /** 326404eca28cSTuomas Tynkkynen * regulator_get_hardware_vsel_register - get the HW voltage selector register 326504eca28cSTuomas Tynkkynen * @regulator: regulator source 326604eca28cSTuomas Tynkkynen * @vsel_reg: voltage selector register, output parameter 326704eca28cSTuomas Tynkkynen * @vsel_mask: mask for voltage selector bitfield, output parameter 326804eca28cSTuomas Tynkkynen * 326904eca28cSTuomas Tynkkynen * Returns the hardware register offset and bitmask used for setting the 327004eca28cSTuomas Tynkkynen * regulator voltage. This might be useful when configuring voltage-scaling 327104eca28cSTuomas Tynkkynen * hardware or firmware that can make I2C requests behind the kernel's back, 327204eca28cSTuomas Tynkkynen * for example. 327304eca28cSTuomas Tynkkynen * 327404eca28cSTuomas Tynkkynen * On success, the output parameters @vsel_reg and @vsel_mask are filled in 327504eca28cSTuomas Tynkkynen * and 0 is returned, otherwise a negative errno is returned. 327604eca28cSTuomas Tynkkynen */ 327704eca28cSTuomas Tynkkynen int regulator_get_hardware_vsel_register(struct regulator *regulator, 327804eca28cSTuomas Tynkkynen unsigned *vsel_reg, 327904eca28cSTuomas Tynkkynen unsigned *vsel_mask) 328004eca28cSTuomas Tynkkynen { 328104eca28cSTuomas Tynkkynen struct regulator_dev *rdev = regulator->rdev; 328239f5460dSGuodong Xu const struct regulator_ops *ops = rdev->desc->ops; 328304eca28cSTuomas Tynkkynen 328404eca28cSTuomas Tynkkynen if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) 328504eca28cSTuomas Tynkkynen return -EOPNOTSUPP; 328604eca28cSTuomas Tynkkynen 328704eca28cSTuomas Tynkkynen *vsel_reg = rdev->desc->vsel_reg; 328804eca28cSTuomas Tynkkynen *vsel_mask = rdev->desc->vsel_mask; 328904eca28cSTuomas Tynkkynen 329004eca28cSTuomas Tynkkynen return 0; 329104eca28cSTuomas Tynkkynen } 329204eca28cSTuomas Tynkkynen EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); 329304eca28cSTuomas Tynkkynen 329404eca28cSTuomas Tynkkynen /** 329504eca28cSTuomas Tynkkynen * regulator_list_hardware_vsel - get the HW-specific register value for a selector 329604eca28cSTuomas Tynkkynen * @regulator: regulator source 329704eca28cSTuomas Tynkkynen * @selector: identify voltage to list 329804eca28cSTuomas Tynkkynen * 329904eca28cSTuomas Tynkkynen * Converts the selector to a hardware-specific voltage selector that can be 330004eca28cSTuomas Tynkkynen * directly written to the regulator registers. The address of the voltage 330104eca28cSTuomas Tynkkynen * register can be determined by calling @regulator_get_hardware_vsel_register. 330204eca28cSTuomas Tynkkynen * 330304eca28cSTuomas Tynkkynen * On error a negative errno is returned. 330404eca28cSTuomas Tynkkynen */ 330504eca28cSTuomas Tynkkynen int regulator_list_hardware_vsel(struct regulator *regulator, 330604eca28cSTuomas Tynkkynen unsigned selector) 330704eca28cSTuomas Tynkkynen { 330804eca28cSTuomas Tynkkynen struct regulator_dev *rdev = regulator->rdev; 330939f5460dSGuodong Xu const struct regulator_ops *ops = rdev->desc->ops; 331004eca28cSTuomas Tynkkynen 331104eca28cSTuomas Tynkkynen if (selector >= rdev->desc->n_voltages) 331204eca28cSTuomas Tynkkynen return -EINVAL; 331355cca739SClaudiu Beznea if (selector < rdev->desc->linear_min_sel) 331455cca739SClaudiu Beznea return 0; 331504eca28cSTuomas Tynkkynen if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) 331604eca28cSTuomas Tynkkynen return -EOPNOTSUPP; 331704eca28cSTuomas Tynkkynen 331804eca28cSTuomas Tynkkynen return selector; 331904eca28cSTuomas Tynkkynen } 332004eca28cSTuomas Tynkkynen EXPORT_SYMBOL_GPL(regulator_list_hardware_vsel); 332104eca28cSTuomas Tynkkynen 332204eca28cSTuomas Tynkkynen /** 33232a668a8bSPaul Walmsley * regulator_get_linear_step - return the voltage step size between VSEL values 33242a668a8bSPaul Walmsley * @regulator: regulator source 33252a668a8bSPaul Walmsley * 33262a668a8bSPaul Walmsley * Returns the voltage step size between VSEL values for linear 33272a668a8bSPaul Walmsley * regulators, or return 0 if the regulator isn't a linear regulator. 33282a668a8bSPaul Walmsley */ 33292a668a8bSPaul Walmsley unsigned int regulator_get_linear_step(struct regulator *regulator) 33302a668a8bSPaul Walmsley { 33312a668a8bSPaul Walmsley struct regulator_dev *rdev = regulator->rdev; 33322a668a8bSPaul Walmsley 33332a668a8bSPaul Walmsley return rdev->desc->uV_step; 33342a668a8bSPaul Walmsley } 33352a668a8bSPaul Walmsley EXPORT_SYMBOL_GPL(regulator_get_linear_step); 33362a668a8bSPaul Walmsley 33372a668a8bSPaul Walmsley /** 3338a7a1ad90SMark Brown * regulator_is_supported_voltage - check if a voltage range can be supported 3339a7a1ad90SMark Brown * 3340a7a1ad90SMark Brown * @regulator: Regulator to check. 3341a7a1ad90SMark Brown * @min_uV: Minimum required voltage in uV. 3342a7a1ad90SMark Brown * @max_uV: Maximum required voltage in uV. 3343a7a1ad90SMark Brown * 334449820944SJorge Ramirez-Ortiz * Returns a boolean. 3345a7a1ad90SMark Brown */ 3346a7a1ad90SMark Brown int regulator_is_supported_voltage(struct regulator *regulator, 3347a7a1ad90SMark Brown int min_uV, int max_uV) 3348a7a1ad90SMark Brown { 3349c5f3939bSMark Brown struct regulator_dev *rdev = regulator->rdev; 3350a7a1ad90SMark Brown int i, voltages, ret; 3351a7a1ad90SMark Brown 3352c5f3939bSMark Brown /* If we can't change voltage check the current voltage */ 33538a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 3354c5f3939bSMark Brown ret = regulator_get_voltage(regulator); 3355c5f3939bSMark Brown if (ret >= 0) 33560d25d09dSJingoo Han return min_uV <= ret && ret <= max_uV; 3357c5f3939bSMark Brown else 3358c5f3939bSMark Brown return ret; 3359c5f3939bSMark Brown } 3360c5f3939bSMark Brown 3361bd7a2b60SPawel Moll /* Any voltage within constrains range is fine? */ 3362bd7a2b60SPawel Moll if (rdev->desc->continuous_voltage_range) 3363bd7a2b60SPawel Moll return min_uV >= rdev->constraints->min_uV && 3364bd7a2b60SPawel Moll max_uV <= rdev->constraints->max_uV; 3365bd7a2b60SPawel Moll 3366a7a1ad90SMark Brown ret = regulator_count_voltages(regulator); 3367a7a1ad90SMark Brown if (ret < 0) 336849820944SJorge Ramirez-Ortiz return 0; 3369a7a1ad90SMark Brown voltages = ret; 3370a7a1ad90SMark Brown 3371a7a1ad90SMark Brown for (i = 0; i < voltages; i++) { 3372a7a1ad90SMark Brown ret = regulator_list_voltage(regulator, i); 3373a7a1ad90SMark Brown 3374a7a1ad90SMark Brown if (ret >= min_uV && ret <= max_uV) 3375a7a1ad90SMark Brown return 1; 3376a7a1ad90SMark Brown } 3377a7a1ad90SMark Brown 3378a7a1ad90SMark Brown return 0; 3379a7a1ad90SMark Brown } 3380a398eaa2SMark Brown EXPORT_SYMBOL_GPL(regulator_is_supported_voltage); 3381a7a1ad90SMark Brown 3382a204f41eSSascha Hauer static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV, 3383a204f41eSSascha Hauer int max_uV) 3384a204f41eSSascha Hauer { 3385a204f41eSSascha Hauer const struct regulator_desc *desc = rdev->desc; 3386a204f41eSSascha Hauer 3387a204f41eSSascha Hauer if (desc->ops->map_voltage) 3388a204f41eSSascha Hauer return desc->ops->map_voltage(rdev, min_uV, max_uV); 3389a204f41eSSascha Hauer 3390a204f41eSSascha Hauer if (desc->ops->list_voltage == regulator_list_voltage_linear) 3391a204f41eSSascha Hauer return regulator_map_voltage_linear(rdev, min_uV, max_uV); 3392a204f41eSSascha Hauer 3393a204f41eSSascha Hauer if (desc->ops->list_voltage == regulator_list_voltage_linear_range) 3394a204f41eSSascha Hauer return regulator_map_voltage_linear_range(rdev, min_uV, max_uV); 3395a204f41eSSascha Hauer 339618e4b55fSMatti Vaittinen if (desc->ops->list_voltage == 339718e4b55fSMatti Vaittinen regulator_list_voltage_pickable_linear_range) 339818e4b55fSMatti Vaittinen return regulator_map_voltage_pickable_linear_range(rdev, 339918e4b55fSMatti Vaittinen min_uV, max_uV); 340018e4b55fSMatti Vaittinen 3401a204f41eSSascha Hauer return regulator_map_voltage_iterate(rdev, min_uV, max_uV); 3402a204f41eSSascha Hauer } 3403a204f41eSSascha Hauer 34047179569aSHeiko Stübner static int _regulator_call_set_voltage(struct regulator_dev *rdev, 34057179569aSHeiko Stübner int min_uV, int max_uV, 34067179569aSHeiko Stübner unsigned *selector) 34077179569aSHeiko Stübner { 34087179569aSHeiko Stübner struct pre_voltage_change_data data; 34097179569aSHeiko Stübner int ret; 34107179569aSHeiko Stübner 3411d22b85a1SDmitry Osipenko data.old_uV = regulator_get_voltage_rdev(rdev); 34127179569aSHeiko Stübner data.min_uV = min_uV; 34137179569aSHeiko Stübner data.max_uV = max_uV; 34147179569aSHeiko Stübner ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, 34157179569aSHeiko Stübner &data); 34167179569aSHeiko Stübner if (ret & NOTIFY_STOP_MASK) 34177179569aSHeiko Stübner return -EINVAL; 34187179569aSHeiko Stübner 34197179569aSHeiko Stübner ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, selector); 34207179569aSHeiko Stübner if (ret >= 0) 34217179569aSHeiko Stübner return ret; 34227179569aSHeiko Stübner 34237179569aSHeiko Stübner _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE, 34247179569aSHeiko Stübner (void *)data.old_uV); 34257179569aSHeiko Stübner 34267179569aSHeiko Stübner return ret; 34277179569aSHeiko Stübner } 34287179569aSHeiko Stübner 34297179569aSHeiko Stübner static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, 34307179569aSHeiko Stübner int uV, unsigned selector) 34317179569aSHeiko Stübner { 34327179569aSHeiko Stübner struct pre_voltage_change_data data; 34337179569aSHeiko Stübner int ret; 34347179569aSHeiko Stübner 3435d22b85a1SDmitry Osipenko data.old_uV = regulator_get_voltage_rdev(rdev); 34367179569aSHeiko Stübner data.min_uV = uV; 34377179569aSHeiko Stübner data.max_uV = uV; 34387179569aSHeiko Stübner ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, 34397179569aSHeiko Stübner &data); 34407179569aSHeiko Stübner if (ret & NOTIFY_STOP_MASK) 34417179569aSHeiko Stübner return -EINVAL; 34427179569aSHeiko Stübner 34437179569aSHeiko Stübner ret = rdev->desc->ops->set_voltage_sel(rdev, selector); 34447179569aSHeiko Stübner if (ret >= 0) 34457179569aSHeiko Stübner return ret; 34467179569aSHeiko Stübner 34477179569aSHeiko Stübner _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE, 34487179569aSHeiko Stübner (void *)data.old_uV); 34497179569aSHeiko Stübner 34507179569aSHeiko Stübner return ret; 34517179569aSHeiko Stübner } 34527179569aSHeiko Stübner 34532da8d947SBartosz Golaszewski static int _regulator_set_voltage_sel_step(struct regulator_dev *rdev, 34542da8d947SBartosz Golaszewski int uV, int new_selector) 34552da8d947SBartosz Golaszewski { 34562da8d947SBartosz Golaszewski const struct regulator_ops *ops = rdev->desc->ops; 34572da8d947SBartosz Golaszewski int diff, old_sel, curr_sel, ret; 34582da8d947SBartosz Golaszewski 34592da8d947SBartosz Golaszewski /* Stepping is only needed if the regulator is enabled. */ 34602da8d947SBartosz Golaszewski if (!_regulator_is_enabled(rdev)) 34612da8d947SBartosz Golaszewski goto final_set; 34622da8d947SBartosz Golaszewski 34632da8d947SBartosz Golaszewski if (!ops->get_voltage_sel) 34642da8d947SBartosz Golaszewski return -EINVAL; 34652da8d947SBartosz Golaszewski 34662da8d947SBartosz Golaszewski old_sel = ops->get_voltage_sel(rdev); 34672da8d947SBartosz Golaszewski if (old_sel < 0) 34682da8d947SBartosz Golaszewski return old_sel; 34692da8d947SBartosz Golaszewski 34702da8d947SBartosz Golaszewski diff = new_selector - old_sel; 34712da8d947SBartosz Golaszewski if (diff == 0) 34722da8d947SBartosz Golaszewski return 0; /* No change needed. */ 34732da8d947SBartosz Golaszewski 34742da8d947SBartosz Golaszewski if (diff > 0) { 34752da8d947SBartosz Golaszewski /* Stepping up. */ 34762da8d947SBartosz Golaszewski for (curr_sel = old_sel + rdev->desc->vsel_step; 34772da8d947SBartosz Golaszewski curr_sel < new_selector; 34782da8d947SBartosz Golaszewski curr_sel += rdev->desc->vsel_step) { 34792da8d947SBartosz Golaszewski /* 34802da8d947SBartosz Golaszewski * Call the callback directly instead of using 34812da8d947SBartosz Golaszewski * _regulator_call_set_voltage_sel() as we don't 34822da8d947SBartosz Golaszewski * want to notify anyone yet. Same in the branch 34832da8d947SBartosz Golaszewski * below. 34842da8d947SBartosz Golaszewski */ 34852da8d947SBartosz Golaszewski ret = ops->set_voltage_sel(rdev, curr_sel); 34862da8d947SBartosz Golaszewski if (ret) 34872da8d947SBartosz Golaszewski goto try_revert; 34882da8d947SBartosz Golaszewski } 34892da8d947SBartosz Golaszewski } else { 34902da8d947SBartosz Golaszewski /* Stepping down. */ 34912da8d947SBartosz Golaszewski for (curr_sel = old_sel - rdev->desc->vsel_step; 34922da8d947SBartosz Golaszewski curr_sel > new_selector; 34932da8d947SBartosz Golaszewski curr_sel -= rdev->desc->vsel_step) { 34942da8d947SBartosz Golaszewski ret = ops->set_voltage_sel(rdev, curr_sel); 34952da8d947SBartosz Golaszewski if (ret) 34962da8d947SBartosz Golaszewski goto try_revert; 34972da8d947SBartosz Golaszewski } 34982da8d947SBartosz Golaszewski } 34992da8d947SBartosz Golaszewski 35002da8d947SBartosz Golaszewski final_set: 35012da8d947SBartosz Golaszewski /* The final selector will trigger the notifiers. */ 35022da8d947SBartosz Golaszewski return _regulator_call_set_voltage_sel(rdev, uV, new_selector); 35032da8d947SBartosz Golaszewski 35042da8d947SBartosz Golaszewski try_revert: 35052da8d947SBartosz Golaszewski /* 35062da8d947SBartosz Golaszewski * At least try to return to the previous voltage if setting a new 35072da8d947SBartosz Golaszewski * one failed. 35082da8d947SBartosz Golaszewski */ 35092da8d947SBartosz Golaszewski (void)ops->set_voltage_sel(rdev, old_sel); 35102da8d947SBartosz Golaszewski return ret; 35112da8d947SBartosz Golaszewski } 35122da8d947SBartosz Golaszewski 351373e705bfSMatthias Kaehlcke static int _regulator_set_voltage_time(struct regulator_dev *rdev, 351473e705bfSMatthias Kaehlcke int old_uV, int new_uV) 351573e705bfSMatthias Kaehlcke { 351673e705bfSMatthias Kaehlcke unsigned int ramp_delay = 0; 351773e705bfSMatthias Kaehlcke 351873e705bfSMatthias Kaehlcke if (rdev->constraints->ramp_delay) 351973e705bfSMatthias Kaehlcke ramp_delay = rdev->constraints->ramp_delay; 352073e705bfSMatthias Kaehlcke else if (rdev->desc->ramp_delay) 352173e705bfSMatthias Kaehlcke ramp_delay = rdev->desc->ramp_delay; 3522d6c1dc3fSLaxman Dewangan else if (rdev->constraints->settling_time) 3523d6c1dc3fSLaxman Dewangan return rdev->constraints->settling_time; 35243ffad468SMatthias Kaehlcke else if (rdev->constraints->settling_time_up && 35253ffad468SMatthias Kaehlcke (new_uV > old_uV)) 35263ffad468SMatthias Kaehlcke return rdev->constraints->settling_time_up; 35273ffad468SMatthias Kaehlcke else if (rdev->constraints->settling_time_down && 35283ffad468SMatthias Kaehlcke (new_uV < old_uV)) 35293ffad468SMatthias Kaehlcke return rdev->constraints->settling_time_down; 353073e705bfSMatthias Kaehlcke 35310739ce4cSChristian Kohlschütter if (ramp_delay == 0) 353273e705bfSMatthias Kaehlcke return 0; 353373e705bfSMatthias Kaehlcke 353473e705bfSMatthias Kaehlcke return DIV_ROUND_UP(abs(new_uV - old_uV), ramp_delay); 353573e705bfSMatthias Kaehlcke } 353673e705bfSMatthias Kaehlcke 353775790251SMark Brown static int _regulator_do_set_voltage(struct regulator_dev *rdev, 353875790251SMark Brown int min_uV, int max_uV) 353975790251SMark Brown { 354075790251SMark Brown int ret; 354177af1b26SLinus Walleij int delay = 0; 3542e113d792SMark Brown int best_val = 0; 354375790251SMark Brown unsigned int selector; 3544eba41a5eSAxel Lin int old_selector = -1; 354557995a48SMatthias Kaehlcke const struct regulator_ops *ops = rdev->desc->ops; 3546d22b85a1SDmitry Osipenko int old_uV = regulator_get_voltage_rdev(rdev); 354775790251SMark Brown 354875790251SMark Brown trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); 354975790251SMark Brown 3550bf5892a8SMark Brown min_uV += rdev->constraints->uV_offset; 3551bf5892a8SMark Brown max_uV += rdev->constraints->uV_offset; 3552bf5892a8SMark Brown 355377af1b26SLinus Walleij /* 355477af1b26SLinus Walleij * If we can't obtain the old selector there is not enough 355577af1b26SLinus Walleij * info to call set_voltage_time_sel(). 355677af1b26SLinus Walleij */ 35578b7485efSAxel Lin if (_regulator_is_enabled(rdev) && 355857995a48SMatthias Kaehlcke ops->set_voltage_time_sel && ops->get_voltage_sel) { 355957995a48SMatthias Kaehlcke old_selector = ops->get_voltage_sel(rdev); 3560eba41a5eSAxel Lin if (old_selector < 0) 3561eba41a5eSAxel Lin return old_selector; 3562eba41a5eSAxel Lin } 356377af1b26SLinus Walleij 356457995a48SMatthias Kaehlcke if (ops->set_voltage) { 35657179569aSHeiko Stübner ret = _regulator_call_set_voltage(rdev, min_uV, max_uV, 356675790251SMark Brown &selector); 3567e113d792SMark Brown 3568e113d792SMark Brown if (ret >= 0) { 356957995a48SMatthias Kaehlcke if (ops->list_voltage) 357057995a48SMatthias Kaehlcke best_val = ops->list_voltage(rdev, 3571e113d792SMark Brown selector); 3572e113d792SMark Brown else 3573d22b85a1SDmitry Osipenko best_val = regulator_get_voltage_rdev(rdev); 3574e113d792SMark Brown } 3575e113d792SMark Brown 357657995a48SMatthias Kaehlcke } else if (ops->set_voltage_sel) { 3577a204f41eSSascha Hauer ret = regulator_map_voltage(rdev, min_uV, max_uV); 3578e843fc46SMark Brown if (ret >= 0) { 357957995a48SMatthias Kaehlcke best_val = ops->list_voltage(rdev, ret); 3580e113d792SMark Brown if (min_uV <= best_val && max_uV >= best_val) { 3581e843fc46SMark Brown selector = ret; 3582c66a566aSAxel Lin if (old_selector == selector) 3583c66a566aSAxel Lin ret = 0; 35842da8d947SBartosz Golaszewski else if (rdev->desc->vsel_step) 35852da8d947SBartosz Golaszewski ret = _regulator_set_voltage_sel_step( 35862da8d947SBartosz Golaszewski rdev, best_val, selector); 3587c66a566aSAxel Lin else 35887179569aSHeiko Stübner ret = _regulator_call_set_voltage_sel( 35897179569aSHeiko Stübner rdev, best_val, selector); 3590e113d792SMark Brown } else { 3591e113d792SMark Brown ret = -EINVAL; 3592e113d792SMark Brown } 3593e843fc46SMark Brown } 3594e8eef82bSMark Brown } else { 3595e8eef82bSMark Brown ret = -EINVAL; 3596e8eef82bSMark Brown } 3597e8eef82bSMark Brown 359831dfe686SMatthias Kaehlcke if (ret) 359931dfe686SMatthias Kaehlcke goto out; 3600eba41a5eSAxel Lin 360173e705bfSMatthias Kaehlcke if (ops->set_voltage_time_sel) { 360273e705bfSMatthias Kaehlcke /* 360373e705bfSMatthias Kaehlcke * Call set_voltage_time_sel if successfully obtained 360473e705bfSMatthias Kaehlcke * old_selector 360573e705bfSMatthias Kaehlcke */ 360673e705bfSMatthias Kaehlcke if (old_selector >= 0 && old_selector != selector) 360773e705bfSMatthias Kaehlcke delay = ops->set_voltage_time_sel(rdev, old_selector, 360873e705bfSMatthias Kaehlcke selector); 360973e705bfSMatthias Kaehlcke } else { 361073e705bfSMatthias Kaehlcke if (old_uV != best_val) { 361173e705bfSMatthias Kaehlcke if (ops->set_voltage_time) 361273e705bfSMatthias Kaehlcke delay = ops->set_voltage_time(rdev, old_uV, 361373e705bfSMatthias Kaehlcke best_val); 361473e705bfSMatthias Kaehlcke else 361573e705bfSMatthias Kaehlcke delay = _regulator_set_voltage_time(rdev, 361673e705bfSMatthias Kaehlcke old_uV, 361773e705bfSMatthias Kaehlcke best_val); 361873e705bfSMatthias Kaehlcke } 361973e705bfSMatthias Kaehlcke } 362073e705bfSMatthias Kaehlcke 3621eba41a5eSAxel Lin if (delay < 0) { 362261aab5adSMichał Mirosław rdev_warn(rdev, "failed to get delay: %pe\n", ERR_PTR(delay)); 3623eba41a5eSAxel Lin delay = 0; 3624e8eef82bSMark Brown } 362575790251SMark Brown 362677af1b26SLinus Walleij /* Insert any necessary delays */ 3627062920d2SBrian Norris _regulator_delay_helper(delay); 362877af1b26SLinus Walleij 362931dfe686SMatthias Kaehlcke if (best_val >= 0) { 36302f6c797fSAxel Lin unsigned long data = best_val; 36312f6c797fSAxel Lin 3632ded06a52SMark Brown _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, 36332f6c797fSAxel Lin (void *)data); 36342f6c797fSAxel Lin } 3635ded06a52SMark Brown 363631dfe686SMatthias Kaehlcke out: 3637eba41a5eSAxel Lin trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); 363875790251SMark Brown 363975790251SMark Brown return ret; 364075790251SMark Brown } 364175790251SMark Brown 3642f7efad10SChunyan Zhang static int _regulator_do_set_suspend_voltage(struct regulator_dev *rdev, 3643f7efad10SChunyan Zhang int min_uV, int max_uV, suspend_state_t state) 3644f7efad10SChunyan Zhang { 3645f7efad10SChunyan Zhang struct regulator_state *rstate; 3646f7efad10SChunyan Zhang int uV, sel; 3647f7efad10SChunyan Zhang 3648f7efad10SChunyan Zhang rstate = regulator_get_suspend_state(rdev, state); 3649f7efad10SChunyan Zhang if (rstate == NULL) 3650f7efad10SChunyan Zhang return -EINVAL; 3651f7efad10SChunyan Zhang 3652f7efad10SChunyan Zhang if (min_uV < rstate->min_uV) 3653f7efad10SChunyan Zhang min_uV = rstate->min_uV; 3654f7efad10SChunyan Zhang if (max_uV > rstate->max_uV) 3655f7efad10SChunyan Zhang max_uV = rstate->max_uV; 3656f7efad10SChunyan Zhang 3657f7efad10SChunyan Zhang sel = regulator_map_voltage(rdev, min_uV, max_uV); 3658f7efad10SChunyan Zhang if (sel < 0) 3659f7efad10SChunyan Zhang return sel; 3660f7efad10SChunyan Zhang 3661f7efad10SChunyan Zhang uV = rdev->desc->ops->list_voltage(rdev, sel); 3662f7efad10SChunyan Zhang if (uV >= min_uV && uV <= max_uV) 3663f7efad10SChunyan Zhang rstate->uV = uV; 3664f7efad10SChunyan Zhang 3665f7efad10SChunyan Zhang return 0; 3666f7efad10SChunyan Zhang } 3667f7efad10SChunyan Zhang 3668a9f226bcSSascha Hauer static int regulator_set_voltage_unlocked(struct regulator *regulator, 3669c360a6dfSChunyan Zhang int min_uV, int max_uV, 3670c360a6dfSChunyan Zhang suspend_state_t state) 3671414c70cbSLiam Girdwood { 3672414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 3673c360a6dfSChunyan Zhang struct regulator_voltage *voltage = ®ulator->voltage[state]; 367495a3c23aSMark Brown int ret = 0; 367592d7a558SPaolo Pisati int old_min_uV, old_max_uV; 3676c00dc359SBjorn Andersson int current_uV; 3677414c70cbSLiam Girdwood 367895a3c23aSMark Brown /* If we're setting the same range as last time the change 367995a3c23aSMark Brown * should be a noop (some cpufreq implementations use the same 368095a3c23aSMark Brown * voltage for multiple frequencies, for example). 368195a3c23aSMark Brown */ 3682c360a6dfSChunyan Zhang if (voltage->min_uV == min_uV && voltage->max_uV == max_uV) 368395a3c23aSMark Brown goto out; 368495a3c23aSMark Brown 3685c00dc359SBjorn Andersson /* If we're trying to set a range that overlaps the current voltage, 3686d3fb9800SViresh Kumar * return successfully even though the regulator does not support 3687c00dc359SBjorn Andersson * changing the voltage. 3688c00dc359SBjorn Andersson */ 36898a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 3690d22b85a1SDmitry Osipenko current_uV = regulator_get_voltage_rdev(rdev); 3691c00dc359SBjorn Andersson if (min_uV <= current_uV && current_uV <= max_uV) { 3692c360a6dfSChunyan Zhang voltage->min_uV = min_uV; 3693c360a6dfSChunyan Zhang voltage->max_uV = max_uV; 3694c00dc359SBjorn Andersson goto out; 3695c00dc359SBjorn Andersson } 3696c00dc359SBjorn Andersson } 3697c00dc359SBjorn Andersson 3698414c70cbSLiam Girdwood /* sanity check */ 3699e8eef82bSMark Brown if (!rdev->desc->ops->set_voltage && 3700e8eef82bSMark Brown !rdev->desc->ops->set_voltage_sel) { 3701414c70cbSLiam Girdwood ret = -EINVAL; 3702414c70cbSLiam Girdwood goto out; 3703414c70cbSLiam Girdwood } 3704414c70cbSLiam Girdwood 3705414c70cbSLiam Girdwood /* constraints check */ 3706414c70cbSLiam Girdwood ret = regulator_check_voltage(rdev, &min_uV, &max_uV); 3707414c70cbSLiam Girdwood if (ret < 0) 3708414c70cbSLiam Girdwood goto out; 370992d7a558SPaolo Pisati 371092d7a558SPaolo Pisati /* restore original values in case of error */ 3711c360a6dfSChunyan Zhang old_min_uV = voltage->min_uV; 3712c360a6dfSChunyan Zhang old_max_uV = voltage->max_uV; 3713c360a6dfSChunyan Zhang voltage->min_uV = min_uV; 3714c360a6dfSChunyan Zhang voltage->max_uV = max_uV; 37153a93f2a9SMark Brown 37169243a195SMaciej Purski /* for not coupled regulators this will just set the voltage */ 37179243a195SMaciej Purski ret = regulator_balance_voltage(rdev, state); 371870b46491SSteve Twiss if (ret < 0) { 37199243a195SMaciej Purski voltage->min_uV = old_min_uV; 37209243a195SMaciej Purski voltage->max_uV = old_max_uV; 372170b46491SSteve Twiss } 37229243a195SMaciej Purski 372370b46491SSteve Twiss out: 37249243a195SMaciej Purski return ret; 37259243a195SMaciej Purski } 37269243a195SMaciej Purski 3727d22b85a1SDmitry Osipenko int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, 37289243a195SMaciej Purski int max_uV, suspend_state_t state) 37299243a195SMaciej Purski { 37309243a195SMaciej Purski int best_supply_uV = 0; 37319243a195SMaciej Purski int supply_change_uV = 0; 37329243a195SMaciej Purski int ret; 37339243a195SMaciej Purski 373443fc99f2SMark Brown if (rdev->supply && 373543fc99f2SMark Brown regulator_ops_is_valid(rdev->supply->rdev, 373643fc99f2SMark Brown REGULATOR_CHANGE_VOLTAGE) && 37372c2874b1STirupathi Reddy (rdev->desc->min_dropout_uV || !(rdev->desc->ops->get_voltage || 37382c2874b1STirupathi Reddy rdev->desc->ops->get_voltage_sel))) { 3739fc42112cSSascha Hauer int current_supply_uV; 3740fc42112cSSascha Hauer int selector; 3741fc42112cSSascha Hauer 3742fc42112cSSascha Hauer selector = regulator_map_voltage(rdev, min_uV, max_uV); 3743fc42112cSSascha Hauer if (selector < 0) { 3744fc42112cSSascha Hauer ret = selector; 37459243a195SMaciej Purski goto out; 3746fc42112cSSascha Hauer } 3747fc42112cSSascha Hauer 374800cb9f4fSMark Brown best_supply_uV = _regulator_list_voltage(rdev, selector, 0); 3749fc42112cSSascha Hauer if (best_supply_uV < 0) { 3750fc42112cSSascha Hauer ret = best_supply_uV; 37519243a195SMaciej Purski goto out; 3752fc42112cSSascha Hauer } 3753fc42112cSSascha Hauer 3754fc42112cSSascha Hauer best_supply_uV += rdev->desc->min_dropout_uV; 3755fc42112cSSascha Hauer 3756d22b85a1SDmitry Osipenko current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev); 3757fc42112cSSascha Hauer if (current_supply_uV < 0) { 3758fc42112cSSascha Hauer ret = current_supply_uV; 37599243a195SMaciej Purski goto out; 3760fc42112cSSascha Hauer } 3761fc42112cSSascha Hauer 3762fc42112cSSascha Hauer supply_change_uV = best_supply_uV - current_supply_uV; 3763fc42112cSSascha Hauer } 3764fc42112cSSascha Hauer 3765fc42112cSSascha Hauer if (supply_change_uV > 0) { 3766fc42112cSSascha Hauer ret = regulator_set_voltage_unlocked(rdev->supply, 3767c360a6dfSChunyan Zhang best_supply_uV, INT_MAX, state); 3768fc42112cSSascha Hauer if (ret) { 376961aab5adSMichał Mirosław dev_err(&rdev->dev, "Failed to increase supply voltage: %pe\n", 377061aab5adSMichał Mirosław ERR_PTR(ret)); 37719243a195SMaciej Purski goto out; 3772fc42112cSSascha Hauer } 3773fc42112cSSascha Hauer } 3774fc42112cSSascha Hauer 3775f7efad10SChunyan Zhang if (state == PM_SUSPEND_ON) 377675790251SMark Brown ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 3777f7efad10SChunyan Zhang else 3778f7efad10SChunyan Zhang ret = _regulator_do_set_suspend_voltage(rdev, min_uV, 3779f7efad10SChunyan Zhang max_uV, state); 378092d7a558SPaolo Pisati if (ret < 0) 37819243a195SMaciej Purski goto out; 378202fa3ec0SMark Brown 3783fc42112cSSascha Hauer if (supply_change_uV < 0) { 3784fc42112cSSascha Hauer ret = regulator_set_voltage_unlocked(rdev->supply, 3785c360a6dfSChunyan Zhang best_supply_uV, INT_MAX, state); 3786fc42112cSSascha Hauer if (ret) 378761aab5adSMichał Mirosław dev_warn(&rdev->dev, "Failed to decrease supply voltage: %pe\n", 378861aab5adSMichał Mirosław ERR_PTR(ret)); 3789fc42112cSSascha Hauer /* No need to fail here */ 3790fc42112cSSascha Hauer ret = 0; 3791fc42112cSSascha Hauer } 3792fc42112cSSascha Hauer 3793414c70cbSLiam Girdwood out: 3794414c70cbSLiam Girdwood return ret; 379569686176SMaciej Purski } 37963d7610e8SEnric Balletbo i Serra EXPORT_SYMBOL_GPL(regulator_set_voltage_rdev); 379769686176SMaciej Purski 379885254bcfSDmitry Osipenko static int regulator_limit_voltage_step(struct regulator_dev *rdev, 379985254bcfSDmitry Osipenko int *current_uV, int *min_uV) 380085254bcfSDmitry Osipenko { 380185254bcfSDmitry Osipenko struct regulation_constraints *constraints = rdev->constraints; 380285254bcfSDmitry Osipenko 380385254bcfSDmitry Osipenko /* Limit voltage change only if necessary */ 380485254bcfSDmitry Osipenko if (!constraints->max_uV_step || !_regulator_is_enabled(rdev)) 380585254bcfSDmitry Osipenko return 1; 380685254bcfSDmitry Osipenko 380785254bcfSDmitry Osipenko if (*current_uV < 0) { 3808d22b85a1SDmitry Osipenko *current_uV = regulator_get_voltage_rdev(rdev); 380985254bcfSDmitry Osipenko 381085254bcfSDmitry Osipenko if (*current_uV < 0) 381185254bcfSDmitry Osipenko return *current_uV; 381285254bcfSDmitry Osipenko } 381385254bcfSDmitry Osipenko 381485254bcfSDmitry Osipenko if (abs(*current_uV - *min_uV) <= constraints->max_uV_step) 381585254bcfSDmitry Osipenko return 1; 381685254bcfSDmitry Osipenko 381785254bcfSDmitry Osipenko /* Clamp target voltage within the given step */ 381885254bcfSDmitry Osipenko if (*current_uV < *min_uV) 381985254bcfSDmitry Osipenko *min_uV = min(*current_uV + constraints->max_uV_step, 382085254bcfSDmitry Osipenko *min_uV); 382185254bcfSDmitry Osipenko else 382285254bcfSDmitry Osipenko *min_uV = max(*current_uV - constraints->max_uV_step, 382385254bcfSDmitry Osipenko *min_uV); 382485254bcfSDmitry Osipenko 382585254bcfSDmitry Osipenko return 0; 382685254bcfSDmitry Osipenko } 382785254bcfSDmitry Osipenko 3828c054c6c7SMaciej Purski static int regulator_get_optimal_voltage(struct regulator_dev *rdev, 3829c054c6c7SMaciej Purski int *current_uV, 3830c054c6c7SMaciej Purski int *min_uV, int *max_uV, 3831c054c6c7SMaciej Purski suspend_state_t state, 3832c054c6c7SMaciej Purski int n_coupled) 3833c054c6c7SMaciej Purski { 3834c054c6c7SMaciej Purski struct coupling_desc *c_desc = &rdev->coupling_desc; 3835c054c6c7SMaciej Purski struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; 3836c054c6c7SMaciej Purski struct regulation_constraints *constraints = rdev->constraints; 3837c054c6c7SMaciej Purski int desired_min_uV = 0, desired_max_uV = INT_MAX; 3838c054c6c7SMaciej Purski int max_current_uV = 0, min_current_uV = INT_MAX; 3839c054c6c7SMaciej Purski int highest_min_uV = 0, target_uV, possible_uV; 3840d8ca7d18SDmitry Osipenko int i, ret, max_spread; 3841c054c6c7SMaciej Purski bool done; 3842c054c6c7SMaciej Purski 3843c054c6c7SMaciej Purski *current_uV = -1; 3844c054c6c7SMaciej Purski 3845c054c6c7SMaciej Purski /* 3846c054c6c7SMaciej Purski * If there are no coupled regulators, simply set the voltage 3847c054c6c7SMaciej Purski * demanded by consumers. 3848c054c6c7SMaciej Purski */ 3849c054c6c7SMaciej Purski if (n_coupled == 1) { 3850c054c6c7SMaciej Purski /* 3851c054c6c7SMaciej Purski * If consumers don't provide any demands, set voltage 3852c054c6c7SMaciej Purski * to min_uV 3853c054c6c7SMaciej Purski */ 3854c054c6c7SMaciej Purski desired_min_uV = constraints->min_uV; 3855c054c6c7SMaciej Purski desired_max_uV = constraints->max_uV; 3856c054c6c7SMaciej Purski 3857c054c6c7SMaciej Purski ret = regulator_check_consumers(rdev, 3858c054c6c7SMaciej Purski &desired_min_uV, 3859c054c6c7SMaciej Purski &desired_max_uV, state); 3860c054c6c7SMaciej Purski if (ret < 0) 3861c054c6c7SMaciej Purski return ret; 3862c054c6c7SMaciej Purski 3863c054c6c7SMaciej Purski possible_uV = desired_min_uV; 3864c054c6c7SMaciej Purski done = true; 3865c054c6c7SMaciej Purski 3866c054c6c7SMaciej Purski goto finish; 3867c054c6c7SMaciej Purski } 3868c054c6c7SMaciej Purski 3869c054c6c7SMaciej Purski /* Find highest min desired voltage */ 3870c054c6c7SMaciej Purski for (i = 0; i < n_coupled; i++) { 3871c054c6c7SMaciej Purski int tmp_min = 0; 3872c054c6c7SMaciej Purski int tmp_max = INT_MAX; 3873c054c6c7SMaciej Purski 3874f8702f9eSDmitry Osipenko lockdep_assert_held_once(&c_rdevs[i]->mutex.base); 3875c054c6c7SMaciej Purski 3876c054c6c7SMaciej Purski ret = regulator_check_consumers(c_rdevs[i], 3877c054c6c7SMaciej Purski &tmp_min, 3878c054c6c7SMaciej Purski &tmp_max, state); 3879c054c6c7SMaciej Purski if (ret < 0) 3880c054c6c7SMaciej Purski return ret; 3881c054c6c7SMaciej Purski 3882c054c6c7SMaciej Purski ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max); 3883c054c6c7SMaciej Purski if (ret < 0) 3884c054c6c7SMaciej Purski return ret; 3885c054c6c7SMaciej Purski 3886c054c6c7SMaciej Purski highest_min_uV = max(highest_min_uV, tmp_min); 3887c054c6c7SMaciej Purski 3888c054c6c7SMaciej Purski if (i == 0) { 3889c054c6c7SMaciej Purski desired_min_uV = tmp_min; 3890c054c6c7SMaciej Purski desired_max_uV = tmp_max; 3891c054c6c7SMaciej Purski } 3892c054c6c7SMaciej Purski } 3893c054c6c7SMaciej Purski 3894d8ca7d18SDmitry Osipenko max_spread = constraints->max_spread[0]; 3895d8ca7d18SDmitry Osipenko 3896c054c6c7SMaciej Purski /* 3897c054c6c7SMaciej Purski * Let target_uV be equal to the desired one if possible. 3898c054c6c7SMaciej Purski * If not, set it to minimum voltage, allowed by other coupled 3899c054c6c7SMaciej Purski * regulators. 3900c054c6c7SMaciej Purski */ 3901c054c6c7SMaciej Purski target_uV = max(desired_min_uV, highest_min_uV - max_spread); 3902c054c6c7SMaciej Purski 3903c054c6c7SMaciej Purski /* 3904c054c6c7SMaciej Purski * Find min and max voltages, which currently aren't violating 3905c054c6c7SMaciej Purski * max_spread. 3906c054c6c7SMaciej Purski */ 3907c054c6c7SMaciej Purski for (i = 1; i < n_coupled; i++) { 3908c054c6c7SMaciej Purski int tmp_act; 3909c054c6c7SMaciej Purski 3910c054c6c7SMaciej Purski if (!_regulator_is_enabled(c_rdevs[i])) 3911c054c6c7SMaciej Purski continue; 3912c054c6c7SMaciej Purski 3913d22b85a1SDmitry Osipenko tmp_act = regulator_get_voltage_rdev(c_rdevs[i]); 3914c054c6c7SMaciej Purski if (tmp_act < 0) 3915c054c6c7SMaciej Purski return tmp_act; 3916c054c6c7SMaciej Purski 3917c054c6c7SMaciej Purski min_current_uV = min(tmp_act, min_current_uV); 3918c054c6c7SMaciej Purski max_current_uV = max(tmp_act, max_current_uV); 3919c054c6c7SMaciej Purski } 3920c054c6c7SMaciej Purski 3921c054c6c7SMaciej Purski /* There aren't any other regulators enabled */ 3922c054c6c7SMaciej Purski if (max_current_uV == 0) { 3923c054c6c7SMaciej Purski possible_uV = target_uV; 3924c054c6c7SMaciej Purski } else { 3925c054c6c7SMaciej Purski /* 3926c054c6c7SMaciej Purski * Correct target voltage, so as it currently isn't 3927c054c6c7SMaciej Purski * violating max_spread 3928c054c6c7SMaciej Purski */ 3929c054c6c7SMaciej Purski possible_uV = max(target_uV, max_current_uV - max_spread); 3930c054c6c7SMaciej Purski possible_uV = min(possible_uV, min_current_uV + max_spread); 3931c054c6c7SMaciej Purski } 3932c054c6c7SMaciej Purski 3933c054c6c7SMaciej Purski if (possible_uV > desired_max_uV) 3934c054c6c7SMaciej Purski return -EINVAL; 3935c054c6c7SMaciej Purski 3936c054c6c7SMaciej Purski done = (possible_uV == target_uV); 3937c054c6c7SMaciej Purski desired_min_uV = possible_uV; 3938c054c6c7SMaciej Purski 3939c054c6c7SMaciej Purski finish: 394085254bcfSDmitry Osipenko /* Apply max_uV_step constraint if necessary */ 394185254bcfSDmitry Osipenko if (state == PM_SUSPEND_ON) { 394285254bcfSDmitry Osipenko ret = regulator_limit_voltage_step(rdev, current_uV, 394385254bcfSDmitry Osipenko &desired_min_uV); 394485254bcfSDmitry Osipenko if (ret < 0) 394585254bcfSDmitry Osipenko return ret; 394685254bcfSDmitry Osipenko 394785254bcfSDmitry Osipenko if (ret == 0) 394885254bcfSDmitry Osipenko done = false; 394985254bcfSDmitry Osipenko } 395085254bcfSDmitry Osipenko 3951c054c6c7SMaciej Purski /* Set current_uV if wasn't done earlier in the code and if necessary */ 3952c054c6c7SMaciej Purski if (n_coupled > 1 && *current_uV == -1) { 3953c054c6c7SMaciej Purski 3954c054c6c7SMaciej Purski if (_regulator_is_enabled(rdev)) { 3955d22b85a1SDmitry Osipenko ret = regulator_get_voltage_rdev(rdev); 3956c054c6c7SMaciej Purski if (ret < 0) 3957c054c6c7SMaciej Purski return ret; 3958c054c6c7SMaciej Purski 3959c054c6c7SMaciej Purski *current_uV = ret; 3960c054c6c7SMaciej Purski } else { 3961c054c6c7SMaciej Purski *current_uV = desired_min_uV; 3962c054c6c7SMaciej Purski } 3963c054c6c7SMaciej Purski } 3964c054c6c7SMaciej Purski 3965c054c6c7SMaciej Purski *min_uV = desired_min_uV; 3966c054c6c7SMaciej Purski *max_uV = desired_max_uV; 3967c054c6c7SMaciej Purski 3968c054c6c7SMaciej Purski return done; 3969c054c6c7SMaciej Purski } 3970c054c6c7SMaciej Purski 3971752db83aSMarek Szyprowski int regulator_do_balance_voltage(struct regulator_dev *rdev, 3972752db83aSMarek Szyprowski suspend_state_t state, bool skip_coupled) 3973c054c6c7SMaciej Purski { 3974c054c6c7SMaciej Purski struct regulator_dev **c_rdevs; 3975c054c6c7SMaciej Purski struct regulator_dev *best_rdev; 3976c054c6c7SMaciej Purski struct coupling_desc *c_desc = &rdev->coupling_desc; 3977c054c6c7SMaciej Purski int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev; 3978c054c6c7SMaciej Purski unsigned int delta, best_delta; 3979d8ca7d18SDmitry Osipenko unsigned long c_rdev_done = 0; 3980d8ca7d18SDmitry Osipenko bool best_c_rdev_done; 3981c054c6c7SMaciej Purski 3982c054c6c7SMaciej Purski c_rdevs = c_desc->coupled_rdevs; 3983752db83aSMarek Szyprowski n_coupled = skip_coupled ? 1 : c_desc->n_coupled; 3984c054c6c7SMaciej Purski 3985c054c6c7SMaciej Purski /* 3986c054c6c7SMaciej Purski * Find the best possible voltage change on each loop. Leave the loop 3987c054c6c7SMaciej Purski * if there isn't any possible change. 3988c054c6c7SMaciej Purski */ 3989c054c6c7SMaciej Purski do { 3990c054c6c7SMaciej Purski best_c_rdev_done = false; 3991c054c6c7SMaciej Purski best_delta = 0; 3992c054c6c7SMaciej Purski best_min_uV = 0; 3993c054c6c7SMaciej Purski best_max_uV = 0; 3994c054c6c7SMaciej Purski best_c_rdev = 0; 3995c054c6c7SMaciej Purski best_rdev = NULL; 3996c054c6c7SMaciej Purski 3997c054c6c7SMaciej Purski /* 3998c054c6c7SMaciej Purski * Find highest difference between optimal voltage 3999c054c6c7SMaciej Purski * and current voltage. 4000c054c6c7SMaciej Purski */ 4001c054c6c7SMaciej Purski for (i = 0; i < n_coupled; i++) { 4002c054c6c7SMaciej Purski /* 4003c054c6c7SMaciej Purski * optimal_uV is the best voltage that can be set for 4004c054c6c7SMaciej Purski * i-th regulator at the moment without violating 4005c054c6c7SMaciej Purski * max_spread constraint in order to balance 4006c054c6c7SMaciej Purski * the coupled voltages. 4007c054c6c7SMaciej Purski */ 4008c054c6c7SMaciej Purski int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; 4009c054c6c7SMaciej Purski 4010d8ca7d18SDmitry Osipenko if (test_bit(i, &c_rdev_done)) 4011c054c6c7SMaciej Purski continue; 4012c054c6c7SMaciej Purski 4013c054c6c7SMaciej Purski ret = regulator_get_optimal_voltage(c_rdevs[i], 4014c054c6c7SMaciej Purski ¤t_uV, 4015c054c6c7SMaciej Purski &optimal_uV, 4016c054c6c7SMaciej Purski &optimal_max_uV, 4017c054c6c7SMaciej Purski state, n_coupled); 4018c054c6c7SMaciej Purski if (ret < 0) 4019c054c6c7SMaciej Purski goto out; 4020c054c6c7SMaciej Purski 4021c054c6c7SMaciej Purski delta = abs(optimal_uV - current_uV); 4022c054c6c7SMaciej Purski 4023c054c6c7SMaciej Purski if (delta && best_delta <= delta) { 4024c054c6c7SMaciej Purski best_c_rdev_done = ret; 4025c054c6c7SMaciej Purski best_delta = delta; 4026c054c6c7SMaciej Purski best_rdev = c_rdevs[i]; 4027c054c6c7SMaciej Purski best_min_uV = optimal_uV; 4028c054c6c7SMaciej Purski best_max_uV = optimal_max_uV; 4029c054c6c7SMaciej Purski best_c_rdev = i; 4030c054c6c7SMaciej Purski } 4031c054c6c7SMaciej Purski } 4032c054c6c7SMaciej Purski 4033c054c6c7SMaciej Purski /* Nothing to change, return successfully */ 4034c054c6c7SMaciej Purski if (!best_rdev) { 4035c054c6c7SMaciej Purski ret = 0; 4036c054c6c7SMaciej Purski goto out; 4037c054c6c7SMaciej Purski } 40389243a195SMaciej Purski 4039c054c6c7SMaciej Purski ret = regulator_set_voltage_rdev(best_rdev, best_min_uV, 4040c054c6c7SMaciej Purski best_max_uV, state); 40419243a195SMaciej Purski 4042c054c6c7SMaciej Purski if (ret < 0) 4043c054c6c7SMaciej Purski goto out; 4044c054c6c7SMaciej Purski 4045d8ca7d18SDmitry Osipenko if (best_c_rdev_done) 4046d8ca7d18SDmitry Osipenko set_bit(best_c_rdev, &c_rdev_done); 4047c054c6c7SMaciej Purski 4048c054c6c7SMaciej Purski } while (n_coupled > 1); 4049c054c6c7SMaciej Purski 4050c054c6c7SMaciej Purski out: 405169686176SMaciej Purski return ret; 405269686176SMaciej Purski } 405369686176SMaciej Purski 4054752db83aSMarek Szyprowski static int regulator_balance_voltage(struct regulator_dev *rdev, 4055752db83aSMarek Szyprowski suspend_state_t state) 4056752db83aSMarek Szyprowski { 4057752db83aSMarek Szyprowski struct coupling_desc *c_desc = &rdev->coupling_desc; 4058752db83aSMarek Szyprowski struct regulator_coupler *coupler = c_desc->coupler; 4059752db83aSMarek Szyprowski bool skip_coupled = false; 4060752db83aSMarek Szyprowski 4061752db83aSMarek Szyprowski /* 4062752db83aSMarek Szyprowski * If system is in a state other than PM_SUSPEND_ON, don't check 4063752db83aSMarek Szyprowski * other coupled regulators. 4064752db83aSMarek Szyprowski */ 4065752db83aSMarek Szyprowski if (state != PM_SUSPEND_ON) 4066752db83aSMarek Szyprowski skip_coupled = true; 4067752db83aSMarek Szyprowski 4068752db83aSMarek Szyprowski if (c_desc->n_resolved < c_desc->n_coupled) { 4069752db83aSMarek Szyprowski rdev_err(rdev, "Not all coupled regulators registered\n"); 4070752db83aSMarek Szyprowski return -EPERM; 4071752db83aSMarek Szyprowski } 4072752db83aSMarek Szyprowski 4073752db83aSMarek Szyprowski /* Invoke custom balancer for customized couplers */ 4074752db83aSMarek Szyprowski if (coupler && coupler->balance_voltage) 4075752db83aSMarek Szyprowski return coupler->balance_voltage(coupler, rdev, state); 4076752db83aSMarek Szyprowski 4077752db83aSMarek Szyprowski return regulator_do_balance_voltage(rdev, state, skip_coupled); 4078752db83aSMarek Szyprowski } 4079752db83aSMarek Szyprowski 4080a9f226bcSSascha Hauer /** 4081a9f226bcSSascha Hauer * regulator_set_voltage - set regulator output voltage 4082a9f226bcSSascha Hauer * @regulator: regulator source 4083a9f226bcSSascha Hauer * @min_uV: Minimum required voltage in uV 4084a9f226bcSSascha Hauer * @max_uV: Maximum acceptable voltage in uV 4085a9f226bcSSascha Hauer * 4086a9f226bcSSascha Hauer * Sets a voltage regulator to the desired output voltage. This can be set 4087a9f226bcSSascha Hauer * during any regulator state. IOW, regulator can be disabled or enabled. 4088a9f226bcSSascha Hauer * 4089a9f226bcSSascha Hauer * If the regulator is enabled then the voltage will change to the new value 4090a9f226bcSSascha Hauer * immediately otherwise if the regulator is disabled the regulator will 4091a9f226bcSSascha Hauer * output at the new voltage when enabled. 4092a9f226bcSSascha Hauer * 4093a9f226bcSSascha Hauer * NOTE: If the regulator is shared between several devices then the lowest 4094a9f226bcSSascha Hauer * request voltage that meets the system constraints will be used. 4095a9f226bcSSascha Hauer * Regulator system constraints must be set for this regulator before 4096a9f226bcSSascha Hauer * calling this function otherwise this call will fail. 4097a9f226bcSSascha Hauer */ 4098a9f226bcSSascha Hauer int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) 4099a9f226bcSSascha Hauer { 4100f8702f9eSDmitry Osipenko struct ww_acquire_ctx ww_ctx; 4101f8702f9eSDmitry Osipenko int ret; 4102a9f226bcSSascha Hauer 4103f8702f9eSDmitry Osipenko regulator_lock_dependent(regulator->rdev, &ww_ctx); 4104a9f226bcSSascha Hauer 4105c360a6dfSChunyan Zhang ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV, 4106c360a6dfSChunyan Zhang PM_SUSPEND_ON); 4107a9f226bcSSascha Hauer 4108f8702f9eSDmitry Osipenko regulator_unlock_dependent(regulator->rdev, &ww_ctx); 4109a9f226bcSSascha Hauer 411092d7a558SPaolo Pisati return ret; 4111414c70cbSLiam Girdwood } 4112414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_voltage); 4113414c70cbSLiam Girdwood 4114f7efad10SChunyan Zhang static inline int regulator_suspend_toggle(struct regulator_dev *rdev, 4115f7efad10SChunyan Zhang suspend_state_t state, bool en) 4116f7efad10SChunyan Zhang { 4117f7efad10SChunyan Zhang struct regulator_state *rstate; 4118f7efad10SChunyan Zhang 4119f7efad10SChunyan Zhang rstate = regulator_get_suspend_state(rdev, state); 4120f7efad10SChunyan Zhang if (rstate == NULL) 4121f7efad10SChunyan Zhang return -EINVAL; 4122f7efad10SChunyan Zhang 4123f7efad10SChunyan Zhang if (!rstate->changeable) 4124f7efad10SChunyan Zhang return -EPERM; 4125f7efad10SChunyan Zhang 41263edd79cfSMarek Szyprowski rstate->enabled = (en) ? ENABLE_IN_SUSPEND : DISABLE_IN_SUSPEND; 4127f7efad10SChunyan Zhang 4128f7efad10SChunyan Zhang return 0; 4129f7efad10SChunyan Zhang } 4130f7efad10SChunyan Zhang 4131f7efad10SChunyan Zhang int regulator_suspend_enable(struct regulator_dev *rdev, 4132f7efad10SChunyan Zhang suspend_state_t state) 4133f7efad10SChunyan Zhang { 4134f7efad10SChunyan Zhang return regulator_suspend_toggle(rdev, state, true); 4135f7efad10SChunyan Zhang } 4136f7efad10SChunyan Zhang EXPORT_SYMBOL_GPL(regulator_suspend_enable); 4137f7efad10SChunyan Zhang 4138f7efad10SChunyan Zhang int regulator_suspend_disable(struct regulator_dev *rdev, 4139f7efad10SChunyan Zhang suspend_state_t state) 4140f7efad10SChunyan Zhang { 4141f7efad10SChunyan Zhang struct regulator *regulator; 4142f7efad10SChunyan Zhang struct regulator_voltage *voltage; 4143f7efad10SChunyan Zhang 4144f7efad10SChunyan Zhang /* 4145f7efad10SChunyan Zhang * if any consumer wants this regulator device keeping on in 4146f7efad10SChunyan Zhang * suspend states, don't set it as disabled. 4147f7efad10SChunyan Zhang */ 4148f7efad10SChunyan Zhang list_for_each_entry(regulator, &rdev->consumer_list, list) { 4149f7efad10SChunyan Zhang voltage = ®ulator->voltage[state]; 4150f7efad10SChunyan Zhang if (voltage->min_uV || voltage->max_uV) 4151f7efad10SChunyan Zhang return 0; 4152f7efad10SChunyan Zhang } 4153f7efad10SChunyan Zhang 4154f7efad10SChunyan Zhang return regulator_suspend_toggle(rdev, state, false); 4155f7efad10SChunyan Zhang } 4156f7efad10SChunyan Zhang EXPORT_SYMBOL_GPL(regulator_suspend_disable); 4157f7efad10SChunyan Zhang 4158f7efad10SChunyan Zhang static int _regulator_set_suspend_voltage(struct regulator *regulator, 4159f7efad10SChunyan Zhang int min_uV, int max_uV, 4160f7efad10SChunyan Zhang suspend_state_t state) 4161f7efad10SChunyan Zhang { 4162f7efad10SChunyan Zhang struct regulator_dev *rdev = regulator->rdev; 4163f7efad10SChunyan Zhang struct regulator_state *rstate; 4164f7efad10SChunyan Zhang 4165f7efad10SChunyan Zhang rstate = regulator_get_suspend_state(rdev, state); 4166f7efad10SChunyan Zhang if (rstate == NULL) 4167f7efad10SChunyan Zhang return -EINVAL; 4168f7efad10SChunyan Zhang 4169f7efad10SChunyan Zhang if (rstate->min_uV == rstate->max_uV) { 4170f7efad10SChunyan Zhang rdev_err(rdev, "The suspend voltage can't be changed!\n"); 4171f7efad10SChunyan Zhang return -EPERM; 4172f7efad10SChunyan Zhang } 4173f7efad10SChunyan Zhang 4174f7efad10SChunyan Zhang return regulator_set_voltage_unlocked(regulator, min_uV, max_uV, state); 4175f7efad10SChunyan Zhang } 4176f7efad10SChunyan Zhang 4177f7efad10SChunyan Zhang int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV, 4178f7efad10SChunyan Zhang int max_uV, suspend_state_t state) 4179f7efad10SChunyan Zhang { 4180f8702f9eSDmitry Osipenko struct ww_acquire_ctx ww_ctx; 4181f8702f9eSDmitry Osipenko int ret; 4182f7efad10SChunyan Zhang 4183f7efad10SChunyan Zhang /* PM_SUSPEND_ON is handled by regulator_set_voltage() */ 4184f7efad10SChunyan Zhang if (regulator_check_states(state) || state == PM_SUSPEND_ON) 4185f7efad10SChunyan Zhang return -EINVAL; 4186f7efad10SChunyan Zhang 4187f8702f9eSDmitry Osipenko regulator_lock_dependent(regulator->rdev, &ww_ctx); 4188f7efad10SChunyan Zhang 4189f7efad10SChunyan Zhang ret = _regulator_set_suspend_voltage(regulator, min_uV, 4190f7efad10SChunyan Zhang max_uV, state); 4191f7efad10SChunyan Zhang 4192f8702f9eSDmitry Osipenko regulator_unlock_dependent(regulator->rdev, &ww_ctx); 4193f7efad10SChunyan Zhang 4194f7efad10SChunyan Zhang return ret; 4195f7efad10SChunyan Zhang } 4196f7efad10SChunyan Zhang EXPORT_SYMBOL_GPL(regulator_set_suspend_voltage); 4197f7efad10SChunyan Zhang 4198606a2562SMark Brown /** 419988cd222bSLinus Walleij * regulator_set_voltage_time - get raise/fall time 420088cd222bSLinus Walleij * @regulator: regulator source 420188cd222bSLinus Walleij * @old_uV: starting voltage in microvolts 420288cd222bSLinus Walleij * @new_uV: target voltage in microvolts 420388cd222bSLinus Walleij * 420488cd222bSLinus Walleij * Provided with the starting and ending voltage, this function attempts to 420588cd222bSLinus Walleij * calculate the time in microseconds required to rise or fall to this new 420688cd222bSLinus Walleij * voltage. 420788cd222bSLinus Walleij */ 420888cd222bSLinus Walleij int regulator_set_voltage_time(struct regulator *regulator, 420988cd222bSLinus Walleij int old_uV, int new_uV) 421088cd222bSLinus Walleij { 421188cd222bSLinus Walleij struct regulator_dev *rdev = regulator->rdev; 4212272e2315SGuodong Xu const struct regulator_ops *ops = rdev->desc->ops; 421388cd222bSLinus Walleij int old_sel = -1; 421488cd222bSLinus Walleij int new_sel = -1; 421588cd222bSLinus Walleij int voltage; 421688cd222bSLinus Walleij int i; 421788cd222bSLinus Walleij 421873e705bfSMatthias Kaehlcke if (ops->set_voltage_time) 421973e705bfSMatthias Kaehlcke return ops->set_voltage_time(rdev, old_uV, new_uV); 422073e705bfSMatthias Kaehlcke else if (!ops->set_voltage_time_sel) 422173e705bfSMatthias Kaehlcke return _regulator_set_voltage_time(rdev, old_uV, new_uV); 422273e705bfSMatthias Kaehlcke 422388cd222bSLinus Walleij /* Currently requires operations to do this */ 422473e705bfSMatthias Kaehlcke if (!ops->list_voltage || !rdev->desc->n_voltages) 422588cd222bSLinus Walleij return -EINVAL; 422688cd222bSLinus Walleij 422788cd222bSLinus Walleij for (i = 0; i < rdev->desc->n_voltages; i++) { 422888cd222bSLinus Walleij /* We only look for exact voltage matches here */ 4229bdcd1177SClaudiu Beznea if (i < rdev->desc->linear_min_sel) 4230bdcd1177SClaudiu Beznea continue; 4231bdcd1177SClaudiu Beznea 4232ab97800eSClaudiu Beznea if (old_sel >= 0 && new_sel >= 0) 4233ab97800eSClaudiu Beznea break; 4234ab97800eSClaudiu Beznea 423588cd222bSLinus Walleij voltage = regulator_list_voltage(regulator, i); 423688cd222bSLinus Walleij if (voltage < 0) 423788cd222bSLinus Walleij return -EINVAL; 423888cd222bSLinus Walleij if (voltage == 0) 423988cd222bSLinus Walleij continue; 424088cd222bSLinus Walleij if (voltage == old_uV) 424188cd222bSLinus Walleij old_sel = i; 424288cd222bSLinus Walleij if (voltage == new_uV) 424388cd222bSLinus Walleij new_sel = i; 424488cd222bSLinus Walleij } 424588cd222bSLinus Walleij 424688cd222bSLinus Walleij if (old_sel < 0 || new_sel < 0) 424788cd222bSLinus Walleij return -EINVAL; 424888cd222bSLinus Walleij 424988cd222bSLinus Walleij return ops->set_voltage_time_sel(rdev, old_sel, new_sel); 425088cd222bSLinus Walleij } 425188cd222bSLinus Walleij EXPORT_SYMBOL_GPL(regulator_set_voltage_time); 425288cd222bSLinus Walleij 425388cd222bSLinus Walleij /** 425498a175b6SYadwinder Singh Brar * regulator_set_voltage_time_sel - get raise/fall time 4255296c6566SRandy Dunlap * @rdev: regulator source device 425698a175b6SYadwinder Singh Brar * @old_selector: selector for starting voltage 425798a175b6SYadwinder Singh Brar * @new_selector: selector for target voltage 425898a175b6SYadwinder Singh Brar * 425998a175b6SYadwinder Singh Brar * Provided with the starting and target voltage selectors, this function 426098a175b6SYadwinder Singh Brar * returns time in microseconds required to rise or fall to this new voltage 426198a175b6SYadwinder Singh Brar * 4262f11d08c3SAxel Lin * Drivers providing ramp_delay in regulation_constraints can use this as their 4263398715abSAxel Lin * set_voltage_time_sel() operation. 426498a175b6SYadwinder Singh Brar */ 426598a175b6SYadwinder Singh Brar int regulator_set_voltage_time_sel(struct regulator_dev *rdev, 426698a175b6SYadwinder Singh Brar unsigned int old_selector, 426798a175b6SYadwinder Singh Brar unsigned int new_selector) 426898a175b6SYadwinder Singh Brar { 4269f11d08c3SAxel Lin int old_volt, new_volt; 4270398715abSAxel Lin 4271f11d08c3SAxel Lin /* sanity check */ 4272f11d08c3SAxel Lin if (!rdev->desc->ops->list_voltage) 4273f11d08c3SAxel Lin return -EINVAL; 4274398715abSAxel Lin 4275f11d08c3SAxel Lin old_volt = rdev->desc->ops->list_voltage(rdev, old_selector); 4276f11d08c3SAxel Lin new_volt = rdev->desc->ops->list_voltage(rdev, new_selector); 4277f11d08c3SAxel Lin 427873e705bfSMatthias Kaehlcke if (rdev->desc->ops->set_voltage_time) 427973e705bfSMatthias Kaehlcke return rdev->desc->ops->set_voltage_time(rdev, old_volt, 428073e705bfSMatthias Kaehlcke new_volt); 428173e705bfSMatthias Kaehlcke else 428273e705bfSMatthias Kaehlcke return _regulator_set_voltage_time(rdev, old_volt, new_volt); 428398a175b6SYadwinder Singh Brar } 4284b19dbf71SMark Brown EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel); 428598a175b6SYadwinder Singh Brar 4286380d2b2dSDmitry Osipenko int regulator_sync_voltage_rdev(struct regulator_dev *rdev) 4287380d2b2dSDmitry Osipenko { 4288380d2b2dSDmitry Osipenko int ret; 4289380d2b2dSDmitry Osipenko 4290380d2b2dSDmitry Osipenko regulator_lock(rdev); 4291380d2b2dSDmitry Osipenko 4292380d2b2dSDmitry Osipenko if (!rdev->desc->ops->set_voltage && 4293380d2b2dSDmitry Osipenko !rdev->desc->ops->set_voltage_sel) { 4294380d2b2dSDmitry Osipenko ret = -EINVAL; 4295380d2b2dSDmitry Osipenko goto out; 4296380d2b2dSDmitry Osipenko } 4297380d2b2dSDmitry Osipenko 4298380d2b2dSDmitry Osipenko /* balance only, if regulator is coupled */ 4299380d2b2dSDmitry Osipenko if (rdev->coupling_desc.n_coupled > 1) 4300380d2b2dSDmitry Osipenko ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 4301380d2b2dSDmitry Osipenko else 4302380d2b2dSDmitry Osipenko ret = -EOPNOTSUPP; 4303380d2b2dSDmitry Osipenko 4304380d2b2dSDmitry Osipenko out: 4305380d2b2dSDmitry Osipenko regulator_unlock(rdev); 4306380d2b2dSDmitry Osipenko return ret; 4307380d2b2dSDmitry Osipenko } 4308380d2b2dSDmitry Osipenko 430998a175b6SYadwinder Singh Brar /** 4310606a2562SMark Brown * regulator_sync_voltage - re-apply last regulator output voltage 4311606a2562SMark Brown * @regulator: regulator source 4312606a2562SMark Brown * 4313606a2562SMark Brown * Re-apply the last configured voltage. This is intended to be used 4314606a2562SMark Brown * where some external control source the consumer is cooperating with 4315606a2562SMark Brown * has caused the configured voltage to change. 4316606a2562SMark Brown */ 4317606a2562SMark Brown int regulator_sync_voltage(struct regulator *regulator) 4318606a2562SMark Brown { 4319606a2562SMark Brown struct regulator_dev *rdev = regulator->rdev; 4320c360a6dfSChunyan Zhang struct regulator_voltage *voltage = ®ulator->voltage[PM_SUSPEND_ON]; 4321606a2562SMark Brown int ret, min_uV, max_uV; 4322606a2562SMark Brown 4323400d5a5dSDmitry Osipenko if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) 4324400d5a5dSDmitry Osipenko return 0; 4325400d5a5dSDmitry Osipenko 432666cf9a7eSMaciej Purski regulator_lock(rdev); 4327606a2562SMark Brown 4328606a2562SMark Brown if (!rdev->desc->ops->set_voltage && 4329606a2562SMark Brown !rdev->desc->ops->set_voltage_sel) { 4330606a2562SMark Brown ret = -EINVAL; 4331606a2562SMark Brown goto out; 4332606a2562SMark Brown } 4333606a2562SMark Brown 4334606a2562SMark Brown /* This is only going to work if we've had a voltage configured. */ 4335c360a6dfSChunyan Zhang if (!voltage->min_uV && !voltage->max_uV) { 4336606a2562SMark Brown ret = -EINVAL; 4337606a2562SMark Brown goto out; 4338606a2562SMark Brown } 4339606a2562SMark Brown 4340c360a6dfSChunyan Zhang min_uV = voltage->min_uV; 4341c360a6dfSChunyan Zhang max_uV = voltage->max_uV; 4342606a2562SMark Brown 4343606a2562SMark Brown /* This should be a paranoia check... */ 4344606a2562SMark Brown ret = regulator_check_voltage(rdev, &min_uV, &max_uV); 4345606a2562SMark Brown if (ret < 0) 4346606a2562SMark Brown goto out; 4347606a2562SMark Brown 4348c360a6dfSChunyan Zhang ret = regulator_check_consumers(rdev, &min_uV, &max_uV, 0); 4349606a2562SMark Brown if (ret < 0) 4350606a2562SMark Brown goto out; 4351606a2562SMark Brown 435224be0c71SDmitry Osipenko /* balance only, if regulator is coupled */ 435324be0c71SDmitry Osipenko if (rdev->coupling_desc.n_coupled > 1) 435424be0c71SDmitry Osipenko ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 435524be0c71SDmitry Osipenko else 4356606a2562SMark Brown ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 4357606a2562SMark Brown 4358606a2562SMark Brown out: 435966cf9a7eSMaciej Purski regulator_unlock(rdev); 4360606a2562SMark Brown return ret; 4361606a2562SMark Brown } 4362606a2562SMark Brown EXPORT_SYMBOL_GPL(regulator_sync_voltage); 4363606a2562SMark Brown 4364d22b85a1SDmitry Osipenko int regulator_get_voltage_rdev(struct regulator_dev *rdev) 4365414c70cbSLiam Girdwood { 4366bf5892a8SMark Brown int sel, ret; 4367fef95019SMark Brown bool bypassed; 4368fef95019SMark Brown 4369fef95019SMark Brown if (rdev->desc->ops->get_bypass) { 4370fef95019SMark Brown ret = rdev->desc->ops->get_bypass(rdev, &bypassed); 4371fef95019SMark Brown if (ret < 0) 4372fef95019SMark Brown return ret; 4373fef95019SMark Brown if (bypassed) { 4374fef95019SMark Brown /* if bypassed the regulator must have a supply */ 437545389c47SJon Hunter if (!rdev->supply) { 437645389c47SJon Hunter rdev_err(rdev, 437745389c47SJon Hunter "bypassed regulator has no supply!\n"); 437845389c47SJon Hunter return -EPROBE_DEFER; 437945389c47SJon Hunter } 4380fef95019SMark Brown 4381d22b85a1SDmitry Osipenko return regulator_get_voltage_rdev(rdev->supply->rdev); 4382fef95019SMark Brown } 4383fef95019SMark Brown } 4384476c2d83SMark Brown 4385476c2d83SMark Brown if (rdev->desc->ops->get_voltage_sel) { 4386476c2d83SMark Brown sel = rdev->desc->ops->get_voltage_sel(rdev); 4387476c2d83SMark Brown if (sel < 0) 4388476c2d83SMark Brown return sel; 4389bf5892a8SMark Brown ret = rdev->desc->ops->list_voltage(rdev, sel); 4390cb220d16SAxel Lin } else if (rdev->desc->ops->get_voltage) { 4391bf5892a8SMark Brown ret = rdev->desc->ops->get_voltage(rdev); 4392f7df20ecSMark Brown } else if (rdev->desc->ops->list_voltage) { 4393f7df20ecSMark Brown ret = rdev->desc->ops->list_voltage(rdev, 0); 43945a523605SLaxman Dewangan } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { 43955a523605SLaxman Dewangan ret = rdev->desc->fixed_uV; 4396e303996eSJavier Martinez Canillas } else if (rdev->supply) { 4397d22b85a1SDmitry Osipenko ret = regulator_get_voltage_rdev(rdev->supply->rdev); 4398cf1ad559SMichał Mirosław } else if (rdev->supply_name) { 4399cf1ad559SMichał Mirosław return -EPROBE_DEFER; 4400cb220d16SAxel Lin } else { 4401414c70cbSLiam Girdwood return -EINVAL; 4402cb220d16SAxel Lin } 4403bf5892a8SMark Brown 4404cb220d16SAxel Lin if (ret < 0) 4405cb220d16SAxel Lin return ret; 4406bf5892a8SMark Brown return ret - rdev->constraints->uV_offset; 4407414c70cbSLiam Girdwood } 44083d7610e8SEnric Balletbo i Serra EXPORT_SYMBOL_GPL(regulator_get_voltage_rdev); 4409414c70cbSLiam Girdwood 4410414c70cbSLiam Girdwood /** 4411414c70cbSLiam Girdwood * regulator_get_voltage - get regulator output voltage 4412414c70cbSLiam Girdwood * @regulator: regulator source 4413414c70cbSLiam Girdwood * 4414414c70cbSLiam Girdwood * This returns the current regulator voltage in uV. 4415414c70cbSLiam Girdwood * 4416414c70cbSLiam Girdwood * NOTE: If the regulator is disabled it will return the voltage value. This 4417414c70cbSLiam Girdwood * function should not be used to determine regulator state. 4418414c70cbSLiam Girdwood */ 4419414c70cbSLiam Girdwood int regulator_get_voltage(struct regulator *regulator) 4420414c70cbSLiam Girdwood { 4421f8702f9eSDmitry Osipenko struct ww_acquire_ctx ww_ctx; 4422414c70cbSLiam Girdwood int ret; 4423414c70cbSLiam Girdwood 4424f8702f9eSDmitry Osipenko regulator_lock_dependent(regulator->rdev, &ww_ctx); 4425d22b85a1SDmitry Osipenko ret = regulator_get_voltage_rdev(regulator->rdev); 4426f8702f9eSDmitry Osipenko regulator_unlock_dependent(regulator->rdev, &ww_ctx); 4427414c70cbSLiam Girdwood 4428414c70cbSLiam Girdwood return ret; 4429414c70cbSLiam Girdwood } 4430414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_voltage); 4431414c70cbSLiam Girdwood 4432414c70cbSLiam Girdwood /** 4433414c70cbSLiam Girdwood * regulator_set_current_limit - set regulator output current limit 4434414c70cbSLiam Girdwood * @regulator: regulator source 4435ce0d10f8SCharles Keepax * @min_uA: Minimum supported current in uA 4436414c70cbSLiam Girdwood * @max_uA: Maximum supported current in uA 4437414c70cbSLiam Girdwood * 4438414c70cbSLiam Girdwood * Sets current sink to the desired output current. This can be set during 4439414c70cbSLiam Girdwood * any regulator state. IOW, regulator can be disabled or enabled. 4440414c70cbSLiam Girdwood * 4441414c70cbSLiam Girdwood * If the regulator is enabled then the current will change to the new value 4442414c70cbSLiam Girdwood * immediately otherwise if the regulator is disabled the regulator will 4443414c70cbSLiam Girdwood * output at the new current when enabled. 4444414c70cbSLiam Girdwood * 4445414c70cbSLiam Girdwood * NOTE: Regulator system constraints must be set for this regulator before 4446414c70cbSLiam Girdwood * calling this function otherwise this call will fail. 4447414c70cbSLiam Girdwood */ 4448414c70cbSLiam Girdwood int regulator_set_current_limit(struct regulator *regulator, 4449414c70cbSLiam Girdwood int min_uA, int max_uA) 4450414c70cbSLiam Girdwood { 4451414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 4452414c70cbSLiam Girdwood int ret; 4453414c70cbSLiam Girdwood 445466cf9a7eSMaciej Purski regulator_lock(rdev); 4455414c70cbSLiam Girdwood 4456414c70cbSLiam Girdwood /* sanity check */ 4457414c70cbSLiam Girdwood if (!rdev->desc->ops->set_current_limit) { 4458414c70cbSLiam Girdwood ret = -EINVAL; 4459414c70cbSLiam Girdwood goto out; 4460414c70cbSLiam Girdwood } 4461414c70cbSLiam Girdwood 4462414c70cbSLiam Girdwood /* constraints check */ 4463414c70cbSLiam Girdwood ret = regulator_check_current_limit(rdev, &min_uA, &max_uA); 4464414c70cbSLiam Girdwood if (ret < 0) 4465414c70cbSLiam Girdwood goto out; 4466414c70cbSLiam Girdwood 4467414c70cbSLiam Girdwood ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA); 4468414c70cbSLiam Girdwood out: 446966cf9a7eSMaciej Purski regulator_unlock(rdev); 4470414c70cbSLiam Girdwood return ret; 4471414c70cbSLiam Girdwood } 4472414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_current_limit); 4473414c70cbSLiam Girdwood 44747e4d9683SDouglas Anderson static int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev) 44757e4d9683SDouglas Anderson { 44767e4d9683SDouglas Anderson /* sanity check */ 44777e4d9683SDouglas Anderson if (!rdev->desc->ops->get_current_limit) 44787e4d9683SDouglas Anderson return -EINVAL; 44797e4d9683SDouglas Anderson 44807e4d9683SDouglas Anderson return rdev->desc->ops->get_current_limit(rdev); 44817e4d9683SDouglas Anderson } 44827e4d9683SDouglas Anderson 4483414c70cbSLiam Girdwood static int _regulator_get_current_limit(struct regulator_dev *rdev) 4484414c70cbSLiam Girdwood { 4485414c70cbSLiam Girdwood int ret; 4486414c70cbSLiam Girdwood 448766cf9a7eSMaciej Purski regulator_lock(rdev); 44887e4d9683SDouglas Anderson ret = _regulator_get_current_limit_unlocked(rdev); 448966cf9a7eSMaciej Purski regulator_unlock(rdev); 44907e4d9683SDouglas Anderson 4491414c70cbSLiam Girdwood return ret; 4492414c70cbSLiam Girdwood } 4493414c70cbSLiam Girdwood 4494414c70cbSLiam Girdwood /** 4495414c70cbSLiam Girdwood * regulator_get_current_limit - get regulator output current 4496414c70cbSLiam Girdwood * @regulator: regulator source 4497414c70cbSLiam Girdwood * 4498414c70cbSLiam Girdwood * This returns the current supplied by the specified current sink in uA. 4499414c70cbSLiam Girdwood * 4500414c70cbSLiam Girdwood * NOTE: If the regulator is disabled it will return the current value. This 4501414c70cbSLiam Girdwood * function should not be used to determine regulator state. 4502414c70cbSLiam Girdwood */ 4503414c70cbSLiam Girdwood int regulator_get_current_limit(struct regulator *regulator) 4504414c70cbSLiam Girdwood { 4505414c70cbSLiam Girdwood return _regulator_get_current_limit(regulator->rdev); 4506414c70cbSLiam Girdwood } 4507414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_current_limit); 4508414c70cbSLiam Girdwood 4509414c70cbSLiam Girdwood /** 4510414c70cbSLiam Girdwood * regulator_set_mode - set regulator operating mode 4511414c70cbSLiam Girdwood * @regulator: regulator source 4512414c70cbSLiam Girdwood * @mode: operating mode - one of the REGULATOR_MODE constants 4513414c70cbSLiam Girdwood * 4514414c70cbSLiam Girdwood * Set regulator operating mode to increase regulator efficiency or improve 4515414c70cbSLiam Girdwood * regulation performance. 4516414c70cbSLiam Girdwood * 4517414c70cbSLiam Girdwood * NOTE: Regulator system constraints must be set for this regulator before 4518414c70cbSLiam Girdwood * calling this function otherwise this call will fail. 4519414c70cbSLiam Girdwood */ 4520414c70cbSLiam Girdwood int regulator_set_mode(struct regulator *regulator, unsigned int mode) 4521414c70cbSLiam Girdwood { 4522414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 4523414c70cbSLiam Girdwood int ret; 4524500b4ac9SSundar R Iyer int regulator_curr_mode; 4525414c70cbSLiam Girdwood 452666cf9a7eSMaciej Purski regulator_lock(rdev); 4527414c70cbSLiam Girdwood 4528414c70cbSLiam Girdwood /* sanity check */ 4529414c70cbSLiam Girdwood if (!rdev->desc->ops->set_mode) { 4530414c70cbSLiam Girdwood ret = -EINVAL; 4531414c70cbSLiam Girdwood goto out; 4532414c70cbSLiam Girdwood } 4533414c70cbSLiam Girdwood 4534500b4ac9SSundar R Iyer /* return if the same mode is requested */ 4535500b4ac9SSundar R Iyer if (rdev->desc->ops->get_mode) { 4536500b4ac9SSundar R Iyer regulator_curr_mode = rdev->desc->ops->get_mode(rdev); 4537500b4ac9SSundar R Iyer if (regulator_curr_mode == mode) { 4538500b4ac9SSundar R Iyer ret = 0; 4539500b4ac9SSundar R Iyer goto out; 4540500b4ac9SSundar R Iyer } 4541500b4ac9SSundar R Iyer } 4542500b4ac9SSundar R Iyer 4543414c70cbSLiam Girdwood /* constraints check */ 454422c51b47SAxel Lin ret = regulator_mode_constrain(rdev, &mode); 4545414c70cbSLiam Girdwood if (ret < 0) 4546414c70cbSLiam Girdwood goto out; 4547414c70cbSLiam Girdwood 4548414c70cbSLiam Girdwood ret = rdev->desc->ops->set_mode(rdev, mode); 4549414c70cbSLiam Girdwood out: 455066cf9a7eSMaciej Purski regulator_unlock(rdev); 4551414c70cbSLiam Girdwood return ret; 4552414c70cbSLiam Girdwood } 4553414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_mode); 4554414c70cbSLiam Girdwood 45557e4d9683SDouglas Anderson static unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev) 45567e4d9683SDouglas Anderson { 45577e4d9683SDouglas Anderson /* sanity check */ 45587e4d9683SDouglas Anderson if (!rdev->desc->ops->get_mode) 45597e4d9683SDouglas Anderson return -EINVAL; 45607e4d9683SDouglas Anderson 45617e4d9683SDouglas Anderson return rdev->desc->ops->get_mode(rdev); 45627e4d9683SDouglas Anderson } 45637e4d9683SDouglas Anderson 4564414c70cbSLiam Girdwood static unsigned int _regulator_get_mode(struct regulator_dev *rdev) 4565414c70cbSLiam Girdwood { 4566414c70cbSLiam Girdwood int ret; 4567414c70cbSLiam Girdwood 456866cf9a7eSMaciej Purski regulator_lock(rdev); 45697e4d9683SDouglas Anderson ret = _regulator_get_mode_unlocked(rdev); 457066cf9a7eSMaciej Purski regulator_unlock(rdev); 45717e4d9683SDouglas Anderson 4572414c70cbSLiam Girdwood return ret; 4573414c70cbSLiam Girdwood } 4574414c70cbSLiam Girdwood 4575414c70cbSLiam Girdwood /** 4576414c70cbSLiam Girdwood * regulator_get_mode - get regulator operating mode 4577414c70cbSLiam Girdwood * @regulator: regulator source 4578414c70cbSLiam Girdwood * 4579414c70cbSLiam Girdwood * Get the current regulator operating mode. 4580414c70cbSLiam Girdwood */ 4581414c70cbSLiam Girdwood unsigned int regulator_get_mode(struct regulator *regulator) 4582414c70cbSLiam Girdwood { 4583414c70cbSLiam Girdwood return _regulator_get_mode(regulator->rdev); 4584414c70cbSLiam Girdwood } 4585414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_mode); 4586414c70cbSLiam Girdwood 45877111c6d1SMatti Vaittinen static int rdev_get_cached_err_flags(struct regulator_dev *rdev) 45887111c6d1SMatti Vaittinen { 45897111c6d1SMatti Vaittinen int ret = 0; 45907111c6d1SMatti Vaittinen 45917111c6d1SMatti Vaittinen if (rdev->use_cached_err) { 45927111c6d1SMatti Vaittinen spin_lock(&rdev->err_lock); 45937111c6d1SMatti Vaittinen ret = rdev->cached_err; 45947111c6d1SMatti Vaittinen spin_unlock(&rdev->err_lock); 45957111c6d1SMatti Vaittinen } 45967111c6d1SMatti Vaittinen return ret; 45977111c6d1SMatti Vaittinen } 45987111c6d1SMatti Vaittinen 45991b5b4221SAxel Haslam static int _regulator_get_error_flags(struct regulator_dev *rdev, 46001b5b4221SAxel Haslam unsigned int *flags) 46011b5b4221SAxel Haslam { 46027111c6d1SMatti Vaittinen int cached_flags, ret = 0; 46031b5b4221SAxel Haslam 460466cf9a7eSMaciej Purski regulator_lock(rdev); 46051b5b4221SAxel Haslam 46067111c6d1SMatti Vaittinen cached_flags = rdev_get_cached_err_flags(rdev); 46071b5b4221SAxel Haslam 46087111c6d1SMatti Vaittinen if (rdev->desc->ops->get_error_flags) 46091b5b4221SAxel Haslam ret = rdev->desc->ops->get_error_flags(rdev, flags); 46107111c6d1SMatti Vaittinen else if (!rdev->use_cached_err) 46117111c6d1SMatti Vaittinen ret = -EINVAL; 46127111c6d1SMatti Vaittinen 46137111c6d1SMatti Vaittinen *flags |= cached_flags; 46147111c6d1SMatti Vaittinen 461566cf9a7eSMaciej Purski regulator_unlock(rdev); 46167111c6d1SMatti Vaittinen 46171b5b4221SAxel Haslam return ret; 46181b5b4221SAxel Haslam } 46191b5b4221SAxel Haslam 46201b5b4221SAxel Haslam /** 46211b5b4221SAxel Haslam * regulator_get_error_flags - get regulator error information 46221b5b4221SAxel Haslam * @regulator: regulator source 46231b5b4221SAxel Haslam * @flags: pointer to store error flags 46241b5b4221SAxel Haslam * 46251b5b4221SAxel Haslam * Get the current regulator error information. 46261b5b4221SAxel Haslam */ 46271b5b4221SAxel Haslam int regulator_get_error_flags(struct regulator *regulator, 46281b5b4221SAxel Haslam unsigned int *flags) 46291b5b4221SAxel Haslam { 46301b5b4221SAxel Haslam return _regulator_get_error_flags(regulator->rdev, flags); 46311b5b4221SAxel Haslam } 46321b5b4221SAxel Haslam EXPORT_SYMBOL_GPL(regulator_get_error_flags); 46331b5b4221SAxel Haslam 4634414c70cbSLiam Girdwood /** 4635e39ce48fSBjorn Andersson * regulator_set_load - set regulator load 4636414c70cbSLiam Girdwood * @regulator: regulator source 4637414c70cbSLiam Girdwood * @uA_load: load current 4638414c70cbSLiam Girdwood * 4639414c70cbSLiam Girdwood * Notifies the regulator core of a new device load. This is then used by 4640414c70cbSLiam Girdwood * DRMS (if enabled by constraints) to set the most efficient regulator 4641414c70cbSLiam Girdwood * operating mode for the new regulator loading. 4642414c70cbSLiam Girdwood * 4643414c70cbSLiam Girdwood * Consumer devices notify their supply regulator of the maximum power 4644414c70cbSLiam Girdwood * they will require (can be taken from device datasheet in the power 4645414c70cbSLiam Girdwood * consumption tables) when they change operational status and hence power 4646414c70cbSLiam Girdwood * state. Examples of operational state changes that can affect power 4647414c70cbSLiam Girdwood * consumption are :- 4648414c70cbSLiam Girdwood * 4649414c70cbSLiam Girdwood * o Device is opened / closed. 4650414c70cbSLiam Girdwood * o Device I/O is about to begin or has just finished. 4651414c70cbSLiam Girdwood * o Device is idling in between work. 4652414c70cbSLiam Girdwood * 4653414c70cbSLiam Girdwood * This information is also exported via sysfs to userspace. 4654414c70cbSLiam Girdwood * 4655414c70cbSLiam Girdwood * DRMS will sum the total requested load on the regulator and change 4656414c70cbSLiam Girdwood * to the most efficient operating mode if platform constraints allow. 4657414c70cbSLiam Girdwood * 46585451781dSDouglas Anderson * NOTE: when a regulator consumer requests to have a regulator 46595451781dSDouglas Anderson * disabled then any load that consumer requested no longer counts 46605451781dSDouglas Anderson * toward the total requested load. If the regulator is re-enabled 46615451781dSDouglas Anderson * then the previously requested load will start counting again. 46625451781dSDouglas Anderson * 46635451781dSDouglas Anderson * If a regulator is an always-on regulator then an individual consumer's 46645451781dSDouglas Anderson * load will still be removed if that consumer is fully disabled. 46655451781dSDouglas Anderson * 4666e39ce48fSBjorn Andersson * On error a negative errno is returned. 4667414c70cbSLiam Girdwood */ 4668e39ce48fSBjorn Andersson int regulator_set_load(struct regulator *regulator, int uA_load) 4669414c70cbSLiam Girdwood { 4670414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 46715451781dSDouglas Anderson int old_uA_load; 46725451781dSDouglas Anderson int ret = 0; 4673d92d95b6SStephen Boyd 467466cf9a7eSMaciej Purski regulator_lock(rdev); 46755451781dSDouglas Anderson old_uA_load = regulator->uA_load; 4676414c70cbSLiam Girdwood regulator->uA_load = uA_load; 46775451781dSDouglas Anderson if (regulator->enable_count && old_uA_load != uA_load) { 46788460ef38SBjorn Andersson ret = drms_uA_update(rdev); 46795451781dSDouglas Anderson if (ret < 0) 46805451781dSDouglas Anderson regulator->uA_load = old_uA_load; 46815451781dSDouglas Anderson } 468266cf9a7eSMaciej Purski regulator_unlock(rdev); 46838460ef38SBjorn Andersson 4684414c70cbSLiam Girdwood return ret; 4685414c70cbSLiam Girdwood } 4686e39ce48fSBjorn Andersson EXPORT_SYMBOL_GPL(regulator_set_load); 4687414c70cbSLiam Girdwood 4688414c70cbSLiam Girdwood /** 4689f59c8f9fSMark Brown * regulator_allow_bypass - allow the regulator to go into bypass mode 4690f59c8f9fSMark Brown * 4691f59c8f9fSMark Brown * @regulator: Regulator to configure 46929345dfb8SNishanth Menon * @enable: enable or disable bypass mode 4693f59c8f9fSMark Brown * 4694f59c8f9fSMark Brown * Allow the regulator to go into bypass mode if all other consumers 4695f59c8f9fSMark Brown * for the regulator also enable bypass mode and the machine 4696f59c8f9fSMark Brown * constraints allow this. Bypass mode means that the regulator is 4697f59c8f9fSMark Brown * simply passing the input directly to the output with no regulation. 4698f59c8f9fSMark Brown */ 4699f59c8f9fSMark Brown int regulator_allow_bypass(struct regulator *regulator, bool enable) 4700f59c8f9fSMark Brown { 4701f59c8f9fSMark Brown struct regulator_dev *rdev = regulator->rdev; 470248325655SCharles Keepax const char *name = rdev_get_name(rdev); 4703f59c8f9fSMark Brown int ret = 0; 4704f59c8f9fSMark Brown 4705f59c8f9fSMark Brown if (!rdev->desc->ops->set_bypass) 4706f59c8f9fSMark Brown return 0; 4707f59c8f9fSMark Brown 47088a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_BYPASS)) 4709f59c8f9fSMark Brown return 0; 4710f59c8f9fSMark Brown 471166cf9a7eSMaciej Purski regulator_lock(rdev); 4712f59c8f9fSMark Brown 4713f59c8f9fSMark Brown if (enable && !regulator->bypass) { 4714f59c8f9fSMark Brown rdev->bypass_count++; 4715f59c8f9fSMark Brown 4716f59c8f9fSMark Brown if (rdev->bypass_count == rdev->open_count) { 471748325655SCharles Keepax trace_regulator_bypass_enable(name); 471848325655SCharles Keepax 4719f59c8f9fSMark Brown ret = rdev->desc->ops->set_bypass(rdev, enable); 4720f59c8f9fSMark Brown if (ret != 0) 4721f59c8f9fSMark Brown rdev->bypass_count--; 472248325655SCharles Keepax else 472348325655SCharles Keepax trace_regulator_bypass_enable_complete(name); 4724f59c8f9fSMark Brown } 4725f59c8f9fSMark Brown 4726f59c8f9fSMark Brown } else if (!enable && regulator->bypass) { 4727f59c8f9fSMark Brown rdev->bypass_count--; 4728f59c8f9fSMark Brown 4729f59c8f9fSMark Brown if (rdev->bypass_count != rdev->open_count) { 473048325655SCharles Keepax trace_regulator_bypass_disable(name); 473148325655SCharles Keepax 4732f59c8f9fSMark Brown ret = rdev->desc->ops->set_bypass(rdev, enable); 4733f59c8f9fSMark Brown if (ret != 0) 4734f59c8f9fSMark Brown rdev->bypass_count++; 473548325655SCharles Keepax else 473648325655SCharles Keepax trace_regulator_bypass_disable_complete(name); 4737f59c8f9fSMark Brown } 4738f59c8f9fSMark Brown } 4739f59c8f9fSMark Brown 4740f59c8f9fSMark Brown if (ret == 0) 4741f59c8f9fSMark Brown regulator->bypass = enable; 4742f59c8f9fSMark Brown 474366cf9a7eSMaciej Purski regulator_unlock(rdev); 4744f59c8f9fSMark Brown 4745f59c8f9fSMark Brown return ret; 4746f59c8f9fSMark Brown } 4747f59c8f9fSMark Brown EXPORT_SYMBOL_GPL(regulator_allow_bypass); 4748f59c8f9fSMark Brown 4749f59c8f9fSMark Brown /** 4750414c70cbSLiam Girdwood * regulator_register_notifier - register regulator event notifier 4751414c70cbSLiam Girdwood * @regulator: regulator source 475269279fb9SMark Brown * @nb: notifier block 4753414c70cbSLiam Girdwood * 4754414c70cbSLiam Girdwood * Register notifier block to receive regulator events. 4755414c70cbSLiam Girdwood */ 4756414c70cbSLiam Girdwood int regulator_register_notifier(struct regulator *regulator, 4757414c70cbSLiam Girdwood struct notifier_block *nb) 4758414c70cbSLiam Girdwood { 4759414c70cbSLiam Girdwood return blocking_notifier_chain_register(®ulator->rdev->notifier, 4760414c70cbSLiam Girdwood nb); 4761414c70cbSLiam Girdwood } 4762414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_register_notifier); 4763414c70cbSLiam Girdwood 4764414c70cbSLiam Girdwood /** 4765414c70cbSLiam Girdwood * regulator_unregister_notifier - unregister regulator event notifier 4766414c70cbSLiam Girdwood * @regulator: regulator source 476769279fb9SMark Brown * @nb: notifier block 4768414c70cbSLiam Girdwood * 4769414c70cbSLiam Girdwood * Unregister regulator event notifier block. 4770414c70cbSLiam Girdwood */ 4771414c70cbSLiam Girdwood int regulator_unregister_notifier(struct regulator *regulator, 4772414c70cbSLiam Girdwood struct notifier_block *nb) 4773414c70cbSLiam Girdwood { 4774414c70cbSLiam Girdwood return blocking_notifier_chain_unregister(®ulator->rdev->notifier, 4775414c70cbSLiam Girdwood nb); 4776414c70cbSLiam Girdwood } 4777414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_unregister_notifier); 4778414c70cbSLiam Girdwood 4779b136fb44SJonathan Cameron /* notify regulator consumers and downstream regulator consumers. 4780b136fb44SJonathan Cameron * Note mutex must be held by caller. 4781b136fb44SJonathan Cameron */ 47827179569aSHeiko Stübner static int _notifier_call_chain(struct regulator_dev *rdev, 4783414c70cbSLiam Girdwood unsigned long event, void *data) 4784414c70cbSLiam Girdwood { 4785414c70cbSLiam Girdwood /* call rdev chain first */ 47867179569aSHeiko Stübner return blocking_notifier_call_chain(&rdev->notifier, event, data); 4787414c70cbSLiam Girdwood } 4788414c70cbSLiam Girdwood 4789fd184506SZev Weiss int _regulator_bulk_get(struct device *dev, int num_consumers, 4790fd184506SZev Weiss struct regulator_bulk_data *consumers, enum regulator_get_type get_type) 4791414c70cbSLiam Girdwood { 4792414c70cbSLiam Girdwood int i; 4793414c70cbSLiam Girdwood int ret; 4794414c70cbSLiam Girdwood 4795414c70cbSLiam Girdwood for (i = 0; i < num_consumers; i++) 4796414c70cbSLiam Girdwood consumers[i].consumer = NULL; 4797414c70cbSLiam Girdwood 4798414c70cbSLiam Girdwood for (i = 0; i < num_consumers; i++) { 4799fd184506SZev Weiss consumers[i].consumer = _regulator_get(dev, 4800fd184506SZev Weiss consumers[i].supply, get_type); 4801414c70cbSLiam Girdwood if (IS_ERR(consumers[i].consumer)) { 48026eabfc01SDouglas Anderson ret = dev_err_probe(dev, PTR_ERR(consumers[i].consumer), 48036eabfc01SDouglas Anderson "Failed to get supply '%s'", 48046eabfc01SDouglas Anderson consumers[i].supply); 4805d511e8a7SDouglas Anderson consumers[i].consumer = NULL; 4806414c70cbSLiam Girdwood goto err; 4807414c70cbSLiam Girdwood } 48086eabfc01SDouglas Anderson 48096eabfc01SDouglas Anderson if (consumers[i].init_load_uA > 0) { 48106eabfc01SDouglas Anderson ret = regulator_set_load(consumers[i].consumer, 48116eabfc01SDouglas Anderson consumers[i].init_load_uA); 48126eabfc01SDouglas Anderson if (ret) { 48136eabfc01SDouglas Anderson i++; 48146eabfc01SDouglas Anderson goto err; 48156eabfc01SDouglas Anderson } 48166eabfc01SDouglas Anderson } 4817414c70cbSLiam Girdwood } 4818414c70cbSLiam Girdwood 4819414c70cbSLiam Girdwood return 0; 4820414c70cbSLiam Girdwood 4821414c70cbSLiam Girdwood err: 4822b29c7690SAxel Lin while (--i >= 0) 4823414c70cbSLiam Girdwood regulator_put(consumers[i].consumer); 4824414c70cbSLiam Girdwood 4825414c70cbSLiam Girdwood return ret; 4826414c70cbSLiam Girdwood } 4827fd184506SZev Weiss 4828fd184506SZev Weiss /** 4829fd184506SZev Weiss * regulator_bulk_get - get multiple regulator consumers 4830fd184506SZev Weiss * 4831fd184506SZev Weiss * @dev: Device to supply 4832fd184506SZev Weiss * @num_consumers: Number of consumers to register 4833fd184506SZev Weiss * @consumers: Configuration of consumers; clients are stored here. 4834fd184506SZev Weiss * 4835fd184506SZev Weiss * @return 0 on success, an errno on failure. 4836fd184506SZev Weiss * 4837fd184506SZev Weiss * This helper function allows drivers to get several regulator 4838fd184506SZev Weiss * consumers in one operation. If any of the regulators cannot be 4839fd184506SZev Weiss * acquired then any regulators that were allocated will be freed 4840fd184506SZev Weiss * before returning to the caller. 4841fd184506SZev Weiss */ 4842fd184506SZev Weiss int regulator_bulk_get(struct device *dev, int num_consumers, 4843fd184506SZev Weiss struct regulator_bulk_data *consumers) 4844fd184506SZev Weiss { 4845fd184506SZev Weiss return _regulator_bulk_get(dev, num_consumers, consumers, NORMAL_GET); 4846fd184506SZev Weiss } 4847414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_bulk_get); 4848414c70cbSLiam Girdwood 4849f21e0e81SMark Brown static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) 4850f21e0e81SMark Brown { 4851f21e0e81SMark Brown struct regulator_bulk_data *bulk = data; 4852f21e0e81SMark Brown 4853f21e0e81SMark Brown bulk->ret = regulator_enable(bulk->consumer); 4854f21e0e81SMark Brown } 4855f21e0e81SMark Brown 4856414c70cbSLiam Girdwood /** 4857414c70cbSLiam Girdwood * regulator_bulk_enable - enable multiple regulator consumers 4858414c70cbSLiam Girdwood * 4859414c70cbSLiam Girdwood * @num_consumers: Number of consumers 4860414c70cbSLiam Girdwood * @consumers: Consumer data; clients are stored here. 4861414c70cbSLiam Girdwood * @return 0 on success, an errno on failure 4862414c70cbSLiam Girdwood * 4863414c70cbSLiam Girdwood * This convenience API allows consumers to enable multiple regulator 4864414c70cbSLiam Girdwood * clients in a single API call. If any consumers cannot be enabled 4865414c70cbSLiam Girdwood * then any others that were enabled will be disabled again prior to 4866414c70cbSLiam Girdwood * return. 4867414c70cbSLiam Girdwood */ 4868414c70cbSLiam Girdwood int regulator_bulk_enable(int num_consumers, 4869414c70cbSLiam Girdwood struct regulator_bulk_data *consumers) 4870414c70cbSLiam Girdwood { 48712955b47dSDan Williams ASYNC_DOMAIN_EXCLUSIVE(async_domain); 4872414c70cbSLiam Girdwood int i; 4873f21e0e81SMark Brown int ret = 0; 4874414c70cbSLiam Girdwood 48756492bc1bSMark Brown for (i = 0; i < num_consumers; i++) { 4876f21e0e81SMark Brown async_schedule_domain(regulator_bulk_enable_async, 4877f21e0e81SMark Brown &consumers[i], &async_domain); 48786492bc1bSMark Brown } 4879f21e0e81SMark Brown 4880f21e0e81SMark Brown async_synchronize_full_domain(&async_domain); 4881f21e0e81SMark Brown 4882f21e0e81SMark Brown /* If any consumer failed we need to unwind any that succeeded */ 4883414c70cbSLiam Girdwood for (i = 0; i < num_consumers; i++) { 4884f21e0e81SMark Brown if (consumers[i].ret != 0) { 4885f21e0e81SMark Brown ret = consumers[i].ret; 4886414c70cbSLiam Girdwood goto err; 4887414c70cbSLiam Girdwood } 4888f21e0e81SMark Brown } 4889414c70cbSLiam Girdwood 4890414c70cbSLiam Girdwood return 0; 4891414c70cbSLiam Girdwood 4892414c70cbSLiam Girdwood err: 4893fbe31057SAndrzej Hajda for (i = 0; i < num_consumers; i++) { 4894fbe31057SAndrzej Hajda if (consumers[i].ret < 0) 489561aab5adSMichał Mirosław pr_err("Failed to enable %s: %pe\n", consumers[i].supply, 489661aab5adSMichał Mirosław ERR_PTR(consumers[i].ret)); 4897fbe31057SAndrzej Hajda else 4898414c70cbSLiam Girdwood regulator_disable(consumers[i].consumer); 4899fbe31057SAndrzej Hajda } 4900414c70cbSLiam Girdwood 4901414c70cbSLiam Girdwood return ret; 4902414c70cbSLiam Girdwood } 4903414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_bulk_enable); 4904414c70cbSLiam Girdwood 4905414c70cbSLiam Girdwood /** 4906414c70cbSLiam Girdwood * regulator_bulk_disable - disable multiple regulator consumers 4907414c70cbSLiam Girdwood * 4908414c70cbSLiam Girdwood * @num_consumers: Number of consumers 4909414c70cbSLiam Girdwood * @consumers: Consumer data; clients are stored here. 4910414c70cbSLiam Girdwood * @return 0 on success, an errno on failure 4911414c70cbSLiam Girdwood * 4912414c70cbSLiam Girdwood * This convenience API allows consumers to disable multiple regulator 491349e22632SSylwester Nawrocki * clients in a single API call. If any consumers cannot be disabled 491449e22632SSylwester Nawrocki * then any others that were disabled will be enabled again prior to 4915414c70cbSLiam Girdwood * return. 4916414c70cbSLiam Girdwood */ 4917414c70cbSLiam Girdwood int regulator_bulk_disable(int num_consumers, 4918414c70cbSLiam Girdwood struct regulator_bulk_data *consumers) 4919414c70cbSLiam Girdwood { 4920414c70cbSLiam Girdwood int i; 492101e86f49SMark Brown int ret, r; 4922414c70cbSLiam Girdwood 492349e22632SSylwester Nawrocki for (i = num_consumers - 1; i >= 0; --i) { 4924414c70cbSLiam Girdwood ret = regulator_disable(consumers[i].consumer); 4925414c70cbSLiam Girdwood if (ret != 0) 4926414c70cbSLiam Girdwood goto err; 4927414c70cbSLiam Girdwood } 4928414c70cbSLiam Girdwood 4929414c70cbSLiam Girdwood return 0; 4930414c70cbSLiam Girdwood 4931414c70cbSLiam Girdwood err: 493261aab5adSMichał Mirosław pr_err("Failed to disable %s: %pe\n", consumers[i].supply, ERR_PTR(ret)); 493301e86f49SMark Brown for (++i; i < num_consumers; ++i) { 493401e86f49SMark Brown r = regulator_enable(consumers[i].consumer); 493501e86f49SMark Brown if (r != 0) 493661aab5adSMichał Mirosław pr_err("Failed to re-enable %s: %pe\n", 493761aab5adSMichał Mirosław consumers[i].supply, ERR_PTR(r)); 493801e86f49SMark Brown } 4939414c70cbSLiam Girdwood 4940414c70cbSLiam Girdwood return ret; 4941414c70cbSLiam Girdwood } 4942414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_bulk_disable); 4943414c70cbSLiam Girdwood 4944414c70cbSLiam Girdwood /** 4945e1de2f42SDonggeun Kim * regulator_bulk_force_disable - force disable multiple regulator consumers 4946e1de2f42SDonggeun Kim * 4947e1de2f42SDonggeun Kim * @num_consumers: Number of consumers 4948e1de2f42SDonggeun Kim * @consumers: Consumer data; clients are stored here. 4949e1de2f42SDonggeun Kim * @return 0 on success, an errno on failure 4950e1de2f42SDonggeun Kim * 4951e1de2f42SDonggeun Kim * This convenience API allows consumers to forcibly disable multiple regulator 4952e1de2f42SDonggeun Kim * clients in a single API call. 4953e1de2f42SDonggeun Kim * NOTE: This should be used for situations when device damage will 4954e1de2f42SDonggeun Kim * likely occur if the regulators are not disabled (e.g. over temp). 4955e1de2f42SDonggeun Kim * Although regulator_force_disable function call for some consumers can 4956e1de2f42SDonggeun Kim * return error numbers, the function is called for all consumers. 4957e1de2f42SDonggeun Kim */ 4958e1de2f42SDonggeun Kim int regulator_bulk_force_disable(int num_consumers, 4959e1de2f42SDonggeun Kim struct regulator_bulk_data *consumers) 4960e1de2f42SDonggeun Kim { 4961e1de2f42SDonggeun Kim int i; 4962b8c77ff6SDmitry Torokhov int ret = 0; 4963e1de2f42SDonggeun Kim 4964b8c77ff6SDmitry Torokhov for (i = 0; i < num_consumers; i++) { 4965e1de2f42SDonggeun Kim consumers[i].ret = 4966e1de2f42SDonggeun Kim regulator_force_disable(consumers[i].consumer); 4967e1de2f42SDonggeun Kim 4968b8c77ff6SDmitry Torokhov /* Store first error for reporting */ 4969b8c77ff6SDmitry Torokhov if (consumers[i].ret && !ret) 4970e1de2f42SDonggeun Kim ret = consumers[i].ret; 4971e1de2f42SDonggeun Kim } 4972e1de2f42SDonggeun Kim 4973e1de2f42SDonggeun Kim return ret; 4974e1de2f42SDonggeun Kim } 4975e1de2f42SDonggeun Kim EXPORT_SYMBOL_GPL(regulator_bulk_force_disable); 4976e1de2f42SDonggeun Kim 4977e1de2f42SDonggeun Kim /** 4978414c70cbSLiam Girdwood * regulator_bulk_free - free multiple regulator consumers 4979414c70cbSLiam Girdwood * 4980414c70cbSLiam Girdwood * @num_consumers: Number of consumers 4981414c70cbSLiam Girdwood * @consumers: Consumer data; clients are stored here. 4982414c70cbSLiam Girdwood * 4983414c70cbSLiam Girdwood * This convenience API allows consumers to free multiple regulator 4984414c70cbSLiam Girdwood * clients in a single API call. 4985414c70cbSLiam Girdwood */ 4986414c70cbSLiam Girdwood void regulator_bulk_free(int num_consumers, 4987414c70cbSLiam Girdwood struct regulator_bulk_data *consumers) 4988414c70cbSLiam Girdwood { 4989414c70cbSLiam Girdwood int i; 4990414c70cbSLiam Girdwood 4991414c70cbSLiam Girdwood for (i = 0; i < num_consumers; i++) { 4992414c70cbSLiam Girdwood regulator_put(consumers[i].consumer); 4993414c70cbSLiam Girdwood consumers[i].consumer = NULL; 4994414c70cbSLiam Girdwood } 4995414c70cbSLiam Girdwood } 4996414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_bulk_free); 4997414c70cbSLiam Girdwood 4998414c70cbSLiam Girdwood /** 4999414c70cbSLiam Girdwood * regulator_notifier_call_chain - call regulator event notifier 500069279fb9SMark Brown * @rdev: regulator source 5001414c70cbSLiam Girdwood * @event: notifier block 500269279fb9SMark Brown * @data: callback-specific data. 5003414c70cbSLiam Girdwood * 5004414c70cbSLiam Girdwood * Called by regulator drivers to notify clients a regulator event has 50053bca239dSMichał Mirosław * occurred. 5006414c70cbSLiam Girdwood */ 5007414c70cbSLiam Girdwood int regulator_notifier_call_chain(struct regulator_dev *rdev, 5008414c70cbSLiam Girdwood unsigned long event, void *data) 5009414c70cbSLiam Girdwood { 5010414c70cbSLiam Girdwood _notifier_call_chain(rdev, event, data); 5011414c70cbSLiam Girdwood return NOTIFY_DONE; 5012414c70cbSLiam Girdwood 5013414c70cbSLiam Girdwood } 5014414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_notifier_call_chain); 5015414c70cbSLiam Girdwood 5016be721979SMark Brown /** 5017be721979SMark Brown * regulator_mode_to_status - convert a regulator mode into a status 5018be721979SMark Brown * 5019be721979SMark Brown * @mode: Mode to convert 5020be721979SMark Brown * 5021be721979SMark Brown * Convert a regulator mode into a status. 5022be721979SMark Brown */ 5023be721979SMark Brown int regulator_mode_to_status(unsigned int mode) 5024be721979SMark Brown { 5025be721979SMark Brown switch (mode) { 5026be721979SMark Brown case REGULATOR_MODE_FAST: 5027be721979SMark Brown return REGULATOR_STATUS_FAST; 5028be721979SMark Brown case REGULATOR_MODE_NORMAL: 5029be721979SMark Brown return REGULATOR_STATUS_NORMAL; 5030be721979SMark Brown case REGULATOR_MODE_IDLE: 5031be721979SMark Brown return REGULATOR_STATUS_IDLE; 503203ffcf3dSKrystian Garbaciak case REGULATOR_MODE_STANDBY: 5033be721979SMark Brown return REGULATOR_STATUS_STANDBY; 5034be721979SMark Brown default: 50351beaf762SKrystian Garbaciak return REGULATOR_STATUS_UNDEFINED; 5036be721979SMark Brown } 5037be721979SMark Brown } 5038be721979SMark Brown EXPORT_SYMBOL_GPL(regulator_mode_to_status); 5039be721979SMark Brown 504039f802d6STakashi Iwai static struct attribute *regulator_dev_attrs[] = { 504139f802d6STakashi Iwai &dev_attr_name.attr, 504239f802d6STakashi Iwai &dev_attr_num_users.attr, 504339f802d6STakashi Iwai &dev_attr_type.attr, 504439f802d6STakashi Iwai &dev_attr_microvolts.attr, 504539f802d6STakashi Iwai &dev_attr_microamps.attr, 504639f802d6STakashi Iwai &dev_attr_opmode.attr, 504739f802d6STakashi Iwai &dev_attr_state.attr, 504839f802d6STakashi Iwai &dev_attr_status.attr, 504939f802d6STakashi Iwai &dev_attr_bypass.attr, 505039f802d6STakashi Iwai &dev_attr_requested_microamps.attr, 505139f802d6STakashi Iwai &dev_attr_min_microvolts.attr, 505239f802d6STakashi Iwai &dev_attr_max_microvolts.attr, 505339f802d6STakashi Iwai &dev_attr_min_microamps.attr, 505439f802d6STakashi Iwai &dev_attr_max_microamps.attr, 50550f2d636eSZev Weiss &dev_attr_under_voltage.attr, 50560f2d636eSZev Weiss &dev_attr_over_current.attr, 50570f2d636eSZev Weiss &dev_attr_regulation_out.attr, 50580f2d636eSZev Weiss &dev_attr_fail.attr, 50590f2d636eSZev Weiss &dev_attr_over_temp.attr, 50600f2d636eSZev Weiss &dev_attr_under_voltage_warn.attr, 50610f2d636eSZev Weiss &dev_attr_over_current_warn.attr, 50620f2d636eSZev Weiss &dev_attr_over_voltage_warn.attr, 50630f2d636eSZev Weiss &dev_attr_over_temp_warn.attr, 506439f802d6STakashi Iwai &dev_attr_suspend_standby_state.attr, 506539f802d6STakashi Iwai &dev_attr_suspend_mem_state.attr, 506639f802d6STakashi Iwai &dev_attr_suspend_disk_state.attr, 506739f802d6STakashi Iwai &dev_attr_suspend_standby_microvolts.attr, 506839f802d6STakashi Iwai &dev_attr_suspend_mem_microvolts.attr, 506939f802d6STakashi Iwai &dev_attr_suspend_disk_microvolts.attr, 507039f802d6STakashi Iwai &dev_attr_suspend_standby_mode.attr, 507139f802d6STakashi Iwai &dev_attr_suspend_mem_mode.attr, 507239f802d6STakashi Iwai &dev_attr_suspend_disk_mode.attr, 507339f802d6STakashi Iwai NULL 507439f802d6STakashi Iwai }; 507539f802d6STakashi Iwai 50767ad68e2fSDavid Brownell /* 50777ad68e2fSDavid Brownell * To avoid cluttering sysfs (and memory) with useless state, only 50787ad68e2fSDavid Brownell * create attributes that can be meaningfully displayed. 50797ad68e2fSDavid Brownell */ 508039f802d6STakashi Iwai static umode_t regulator_attr_is_visible(struct kobject *kobj, 508139f802d6STakashi Iwai struct attribute *attr, int idx) 50827ad68e2fSDavid Brownell { 508339f802d6STakashi Iwai struct device *dev = kobj_to_dev(kobj); 508483080a14SGeliang Tang struct regulator_dev *rdev = dev_to_rdev(dev); 5085272e2315SGuodong Xu const struct regulator_ops *ops = rdev->desc->ops; 508639f802d6STakashi Iwai umode_t mode = attr->mode; 508739f802d6STakashi Iwai 508839f802d6STakashi Iwai /* these three are always present */ 508939f802d6STakashi Iwai if (attr == &dev_attr_name.attr || 509039f802d6STakashi Iwai attr == &dev_attr_num_users.attr || 509139f802d6STakashi Iwai attr == &dev_attr_type.attr) 509239f802d6STakashi Iwai return mode; 50937ad68e2fSDavid Brownell 50947ad68e2fSDavid Brownell /* some attributes need specific methods to be displayed */ 509539f802d6STakashi Iwai if (attr == &dev_attr_microvolts.attr) { 50964c78899bSMark Brown if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || 5097f2889e65SMark Brown (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || 50985a523605SLaxman Dewangan (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || 509939f802d6STakashi Iwai (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1)) 510039f802d6STakashi Iwai return mode; 510139f802d6STakashi Iwai return 0; 5102f59c8f9fSMark Brown } 51037ad68e2fSDavid Brownell 510439f802d6STakashi Iwai if (attr == &dev_attr_microamps.attr) 510539f802d6STakashi Iwai return ops->get_current_limit ? mode : 0; 510639f802d6STakashi Iwai 510739f802d6STakashi Iwai if (attr == &dev_attr_opmode.attr) 510839f802d6STakashi Iwai return ops->get_mode ? mode : 0; 510939f802d6STakashi Iwai 511039f802d6STakashi Iwai if (attr == &dev_attr_state.attr) 511139f802d6STakashi Iwai return (rdev->ena_pin || ops->is_enabled) ? mode : 0; 511239f802d6STakashi Iwai 511339f802d6STakashi Iwai if (attr == &dev_attr_status.attr) 511439f802d6STakashi Iwai return ops->get_status ? mode : 0; 511539f802d6STakashi Iwai 511639f802d6STakashi Iwai if (attr == &dev_attr_bypass.attr) 511739f802d6STakashi Iwai return ops->get_bypass ? mode : 0; 511839f802d6STakashi Iwai 51190f2d636eSZev Weiss if (attr == &dev_attr_under_voltage.attr || 51200f2d636eSZev Weiss attr == &dev_attr_over_current.attr || 51210f2d636eSZev Weiss attr == &dev_attr_regulation_out.attr || 51220f2d636eSZev Weiss attr == &dev_attr_fail.attr || 51230f2d636eSZev Weiss attr == &dev_attr_over_temp.attr || 51240f2d636eSZev Weiss attr == &dev_attr_under_voltage_warn.attr || 51250f2d636eSZev Weiss attr == &dev_attr_over_current_warn.attr || 51260f2d636eSZev Weiss attr == &dev_attr_over_voltage_warn.attr || 51270f2d636eSZev Weiss attr == &dev_attr_over_temp_warn.attr) 51280f2d636eSZev Weiss return ops->get_error_flags ? mode : 0; 51290f2d636eSZev Weiss 51307ad68e2fSDavid Brownell /* constraints need specific supporting methods */ 513139f802d6STakashi Iwai if (attr == &dev_attr_min_microvolts.attr || 513239f802d6STakashi Iwai attr == &dev_attr_max_microvolts.attr) 513339f802d6STakashi Iwai return (ops->set_voltage || ops->set_voltage_sel) ? mode : 0; 513439f802d6STakashi Iwai 513539f802d6STakashi Iwai if (attr == &dev_attr_min_microamps.attr || 513639f802d6STakashi Iwai attr == &dev_attr_max_microamps.attr) 513739f802d6STakashi Iwai return ops->set_current_limit ? mode : 0; 513839f802d6STakashi Iwai 513939f802d6STakashi Iwai if (attr == &dev_attr_suspend_standby_state.attr || 514039f802d6STakashi Iwai attr == &dev_attr_suspend_mem_state.attr || 514139f802d6STakashi Iwai attr == &dev_attr_suspend_disk_state.attr) 514239f802d6STakashi Iwai return mode; 514339f802d6STakashi Iwai 514439f802d6STakashi Iwai if (attr == &dev_attr_suspend_standby_microvolts.attr || 514539f802d6STakashi Iwai attr == &dev_attr_suspend_mem_microvolts.attr || 514639f802d6STakashi Iwai attr == &dev_attr_suspend_disk_microvolts.attr) 514739f802d6STakashi Iwai return ops->set_suspend_voltage ? mode : 0; 514839f802d6STakashi Iwai 514939f802d6STakashi Iwai if (attr == &dev_attr_suspend_standby_mode.attr || 515039f802d6STakashi Iwai attr == &dev_attr_suspend_mem_mode.attr || 515139f802d6STakashi Iwai attr == &dev_attr_suspend_disk_mode.attr) 515239f802d6STakashi Iwai return ops->set_suspend_mode ? mode : 0; 515339f802d6STakashi Iwai 515439f802d6STakashi Iwai return mode; 51557ad68e2fSDavid Brownell } 51567ad68e2fSDavid Brownell 515739f802d6STakashi Iwai static const struct attribute_group regulator_dev_group = { 515839f802d6STakashi Iwai .attrs = regulator_dev_attrs, 515939f802d6STakashi Iwai .is_visible = regulator_attr_is_visible, 516039f802d6STakashi Iwai }; 51617ad68e2fSDavid Brownell 516239f802d6STakashi Iwai static const struct attribute_group *regulator_dev_groups[] = { 516339f802d6STakashi Iwai ®ulator_dev_group, 516439f802d6STakashi Iwai NULL 516539f802d6STakashi Iwai }; 516639f802d6STakashi Iwai 516739f802d6STakashi Iwai static void regulator_dev_release(struct device *dev) 516839f802d6STakashi Iwai { 516939f802d6STakashi Iwai struct regulator_dev *rdev = dev_get_drvdata(dev); 517029f5f486SMark Brown 517129f5f486SMark Brown kfree(rdev->constraints); 517229f5f486SMark Brown of_node_put(rdev->dev.of_node); 517339f802d6STakashi Iwai kfree(rdev); 51747ad68e2fSDavid Brownell } 51757ad68e2fSDavid Brownell 51761130e5b3SMark Brown static void rdev_init_debugfs(struct regulator_dev *rdev) 51771130e5b3SMark Brown { 5178a9eaa813SGuenter Roeck struct device *parent = rdev->dev.parent; 5179a9eaa813SGuenter Roeck const char *rname = rdev_get_name(rdev); 5180a9eaa813SGuenter Roeck char name[NAME_MAX]; 5181a9eaa813SGuenter Roeck 5182a9eaa813SGuenter Roeck /* Avoid duplicate debugfs directory names */ 5183a9eaa813SGuenter Roeck if (parent && rname == rdev->desc->name) { 5184a9eaa813SGuenter Roeck snprintf(name, sizeof(name), "%s-%s", dev_name(parent), 5185a9eaa813SGuenter Roeck rname); 5186a9eaa813SGuenter Roeck rname = name; 5187a9eaa813SGuenter Roeck } 5188a9eaa813SGuenter Roeck 5189a9eaa813SGuenter Roeck rdev->debugfs = debugfs_create_dir(rname, debugfs_root); 519024751434SStephen Boyd if (!rdev->debugfs) { 51911130e5b3SMark Brown rdev_warn(rdev, "Failed to create debugfs directory\n"); 51921130e5b3SMark Brown return; 51931130e5b3SMark Brown } 51941130e5b3SMark Brown 51951130e5b3SMark Brown debugfs_create_u32("use_count", 0444, rdev->debugfs, 51961130e5b3SMark Brown &rdev->use_count); 51971130e5b3SMark Brown debugfs_create_u32("open_count", 0444, rdev->debugfs, 51981130e5b3SMark Brown &rdev->open_count); 5199f59c8f9fSMark Brown debugfs_create_u32("bypass_count", 0444, rdev->debugfs, 5200f59c8f9fSMark Brown &rdev->bypass_count); 52011130e5b3SMark Brown } 52021130e5b3SMark Brown 52035e3ca2b3SJavier Martinez Canillas static int regulator_register_resolve_supply(struct device *dev, void *data) 52045e3ca2b3SJavier Martinez Canillas { 52057ddede6aSJon Hunter struct regulator_dev *rdev = dev_to_rdev(dev); 52067ddede6aSJon Hunter 52077ddede6aSJon Hunter if (regulator_resolve_supply(rdev)) 52087ddede6aSJon Hunter rdev_dbg(rdev, "unable to resolve supply\n"); 52097ddede6aSJon Hunter 52107ddede6aSJon Hunter return 0; 52115e3ca2b3SJavier Martinez Canillas } 52125e3ca2b3SJavier Martinez Canillas 5213d8ca7d18SDmitry Osipenko int regulator_coupler_register(struct regulator_coupler *coupler) 5214d8ca7d18SDmitry Osipenko { 5215d8ca7d18SDmitry Osipenko mutex_lock(®ulator_list_mutex); 5216d8ca7d18SDmitry Osipenko list_add_tail(&coupler->list, ®ulator_coupler_list); 5217d8ca7d18SDmitry Osipenko mutex_unlock(®ulator_list_mutex); 5218d8ca7d18SDmitry Osipenko 5219d8ca7d18SDmitry Osipenko return 0; 5220d8ca7d18SDmitry Osipenko } 5221d8ca7d18SDmitry Osipenko 5222d8ca7d18SDmitry Osipenko static struct regulator_coupler * 5223d8ca7d18SDmitry Osipenko regulator_find_coupler(struct regulator_dev *rdev) 5224d8ca7d18SDmitry Osipenko { 5225d8ca7d18SDmitry Osipenko struct regulator_coupler *coupler; 5226d8ca7d18SDmitry Osipenko int err; 5227d8ca7d18SDmitry Osipenko 5228d8ca7d18SDmitry Osipenko /* 5229d8ca7d18SDmitry Osipenko * Note that regulators are appended to the list and the generic 5230d8ca7d18SDmitry Osipenko * coupler is registered first, hence it will be attached at last 5231d8ca7d18SDmitry Osipenko * if nobody cared. 5232d8ca7d18SDmitry Osipenko */ 5233d8ca7d18SDmitry Osipenko list_for_each_entry_reverse(coupler, ®ulator_coupler_list, list) { 5234d8ca7d18SDmitry Osipenko err = coupler->attach_regulator(coupler, rdev); 5235d8ca7d18SDmitry Osipenko if (!err) { 5236d8ca7d18SDmitry Osipenko if (!coupler->balance_voltage && 5237d8ca7d18SDmitry Osipenko rdev->coupling_desc.n_coupled > 2) 5238d8ca7d18SDmitry Osipenko goto err_unsupported; 5239d8ca7d18SDmitry Osipenko 5240d8ca7d18SDmitry Osipenko return coupler; 5241d8ca7d18SDmitry Osipenko } 5242d8ca7d18SDmitry Osipenko 5243d8ca7d18SDmitry Osipenko if (err < 0) 5244d8ca7d18SDmitry Osipenko return ERR_PTR(err); 5245d8ca7d18SDmitry Osipenko 5246d8ca7d18SDmitry Osipenko if (err == 1) 5247d8ca7d18SDmitry Osipenko continue; 5248d8ca7d18SDmitry Osipenko 5249d8ca7d18SDmitry Osipenko break; 5250d8ca7d18SDmitry Osipenko } 5251d8ca7d18SDmitry Osipenko 5252d8ca7d18SDmitry Osipenko return ERR_PTR(-EINVAL); 5253d8ca7d18SDmitry Osipenko 5254d8ca7d18SDmitry Osipenko err_unsupported: 5255d8ca7d18SDmitry Osipenko if (coupler->detach_regulator) 5256d8ca7d18SDmitry Osipenko coupler->detach_regulator(coupler, rdev); 5257d8ca7d18SDmitry Osipenko 5258d8ca7d18SDmitry Osipenko rdev_err(rdev, 5259d8ca7d18SDmitry Osipenko "Voltage balancing for multiple regulator couples is unimplemented\n"); 5260d8ca7d18SDmitry Osipenko 5261d8ca7d18SDmitry Osipenko return ERR_PTR(-EPERM); 5262d8ca7d18SDmitry Osipenko } 5263d8ca7d18SDmitry Osipenko 5264f9503385SDmitry Osipenko static void regulator_resolve_coupling(struct regulator_dev *rdev) 5265d3d64537SMaciej Purski { 5266d8ca7d18SDmitry Osipenko struct regulator_coupler *coupler = rdev->coupling_desc.coupler; 5267d3d64537SMaciej Purski struct coupling_desc *c_desc = &rdev->coupling_desc; 5268d3d64537SMaciej Purski int n_coupled = c_desc->n_coupled; 5269d3d64537SMaciej Purski struct regulator_dev *c_rdev; 5270d3d64537SMaciej Purski int i; 5271d3d64537SMaciej Purski 5272d3d64537SMaciej Purski for (i = 1; i < n_coupled; i++) { 5273d3d64537SMaciej Purski /* already resolved */ 5274d3d64537SMaciej Purski if (c_desc->coupled_rdevs[i]) 5275d3d64537SMaciej Purski continue; 5276d3d64537SMaciej Purski 5277d3d64537SMaciej Purski c_rdev = of_parse_coupled_regulator(rdev, i - 1); 5278d3d64537SMaciej Purski 5279f9503385SDmitry Osipenko if (!c_rdev) 5280f9503385SDmitry Osipenko continue; 5281f9503385SDmitry Osipenko 5282d8ca7d18SDmitry Osipenko if (c_rdev->coupling_desc.coupler != coupler) { 5283d8ca7d18SDmitry Osipenko rdev_err(rdev, "coupler mismatch with %s\n", 5284d8ca7d18SDmitry Osipenko rdev_get_name(c_rdev)); 5285d8ca7d18SDmitry Osipenko return; 5286d8ca7d18SDmitry Osipenko } 5287d8ca7d18SDmitry Osipenko 5288d3d64537SMaciej Purski c_desc->coupled_rdevs[i] = c_rdev; 5289d3d64537SMaciej Purski c_desc->n_resolved++; 5290f9503385SDmitry Osipenko 5291f9503385SDmitry Osipenko regulator_resolve_coupling(c_rdev); 5292d3d64537SMaciej Purski } 5293d3d64537SMaciej Purski } 5294d3d64537SMaciej Purski 52956303f3e7SDmitry Osipenko static void regulator_remove_coupling(struct regulator_dev *rdev) 5296d3d64537SMaciej Purski { 5297d8ca7d18SDmitry Osipenko struct regulator_coupler *coupler = rdev->coupling_desc.coupler; 52986303f3e7SDmitry Osipenko struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc; 52996303f3e7SDmitry Osipenko struct regulator_dev *__c_rdev, *c_rdev; 53006303f3e7SDmitry Osipenko unsigned int __n_coupled, n_coupled; 53016303f3e7SDmitry Osipenko int i, k; 5302d8ca7d18SDmitry Osipenko int err; 5303d3d64537SMaciej Purski 53046303f3e7SDmitry Osipenko n_coupled = c_desc->n_coupled; 5305d3d64537SMaciej Purski 53066303f3e7SDmitry Osipenko for (i = 1; i < n_coupled; i++) { 53076303f3e7SDmitry Osipenko c_rdev = c_desc->coupled_rdevs[i]; 5308d3d64537SMaciej Purski 53096303f3e7SDmitry Osipenko if (!c_rdev) 53106303f3e7SDmitry Osipenko continue; 53116303f3e7SDmitry Osipenko 53126303f3e7SDmitry Osipenko regulator_lock(c_rdev); 53136303f3e7SDmitry Osipenko 53146303f3e7SDmitry Osipenko __c_desc = &c_rdev->coupling_desc; 53156303f3e7SDmitry Osipenko __n_coupled = __c_desc->n_coupled; 53166303f3e7SDmitry Osipenko 53176303f3e7SDmitry Osipenko for (k = 1; k < __n_coupled; k++) { 53186303f3e7SDmitry Osipenko __c_rdev = __c_desc->coupled_rdevs[k]; 53196303f3e7SDmitry Osipenko 53206303f3e7SDmitry Osipenko if (__c_rdev == rdev) { 53216303f3e7SDmitry Osipenko __c_desc->coupled_rdevs[k] = NULL; 53226303f3e7SDmitry Osipenko __c_desc->n_resolved--; 53236303f3e7SDmitry Osipenko break; 53246303f3e7SDmitry Osipenko } 5325d3d64537SMaciej Purski } 5326d3d64537SMaciej Purski 53276303f3e7SDmitry Osipenko regulator_unlock(c_rdev); 53286303f3e7SDmitry Osipenko 53296303f3e7SDmitry Osipenko c_desc->coupled_rdevs[i] = NULL; 53306303f3e7SDmitry Osipenko c_desc->n_resolved--; 53316303f3e7SDmitry Osipenko } 5332d8ca7d18SDmitry Osipenko 5333d8ca7d18SDmitry Osipenko if (coupler && coupler->detach_regulator) { 5334d8ca7d18SDmitry Osipenko err = coupler->detach_regulator(coupler, rdev); 5335d8ca7d18SDmitry Osipenko if (err) 533661aab5adSMichał Mirosław rdev_err(rdev, "failed to detach from coupler: %pe\n", 533761aab5adSMichał Mirosław ERR_PTR(err)); 5338d8ca7d18SDmitry Osipenko } 5339d8ca7d18SDmitry Osipenko 5340d8ca7d18SDmitry Osipenko kfree(rdev->coupling_desc.coupled_rdevs); 5341d8ca7d18SDmitry Osipenko rdev->coupling_desc.coupled_rdevs = NULL; 53426303f3e7SDmitry Osipenko } 53436303f3e7SDmitry Osipenko 5344f9503385SDmitry Osipenko static int regulator_init_coupling(struct regulator_dev *rdev) 5345d3d64537SMaciej Purski { 53467d819664SMichał Mirosław struct regulator_dev **coupled; 5347d8ca7d18SDmitry Osipenko int err, n_phandles; 5348d3d64537SMaciej Purski 5349d3d64537SMaciej Purski if (!IS_ENABLED(CONFIG_OF)) 5350d3d64537SMaciej Purski n_phandles = 0; 5351d3d64537SMaciej Purski else 5352d3d64537SMaciej Purski n_phandles = of_get_n_coupled(rdev); 5353d3d64537SMaciej Purski 53547d819664SMichał Mirosław coupled = kcalloc(n_phandles + 1, sizeof(*coupled), GFP_KERNEL); 53557d819664SMichał Mirosław if (!coupled) 5356d8ca7d18SDmitry Osipenko return -ENOMEM; 5357d3d64537SMaciej Purski 53587d819664SMichał Mirosław rdev->coupling_desc.coupled_rdevs = coupled; 53597d819664SMichał Mirosław 5360d3d64537SMaciej Purski /* 5361d3d64537SMaciej Purski * Every regulator should always have coupling descriptor filled with 5362d3d64537SMaciej Purski * at least pointer to itself. 5363d3d64537SMaciej Purski */ 5364d3d64537SMaciej Purski rdev->coupling_desc.coupled_rdevs[0] = rdev; 5365d3d64537SMaciej Purski rdev->coupling_desc.n_coupled = n_phandles + 1; 5366d3d64537SMaciej Purski rdev->coupling_desc.n_resolved++; 5367d3d64537SMaciej Purski 5368d3d64537SMaciej Purski /* regulator isn't coupled */ 5369d3d64537SMaciej Purski if (n_phandles == 0) 5370d3d64537SMaciej Purski return 0; 5371d3d64537SMaciej Purski 5372d3d64537SMaciej Purski if (!of_check_coupling_data(rdev)) 5373d3d64537SMaciej Purski return -EPERM; 5374d3d64537SMaciej Purski 537573a32129SMichał Mirosław mutex_lock(®ulator_list_mutex); 5376d8ca7d18SDmitry Osipenko rdev->coupling_desc.coupler = regulator_find_coupler(rdev); 537773a32129SMichał Mirosław mutex_unlock(®ulator_list_mutex); 537873a32129SMichał Mirosław 5379d8ca7d18SDmitry Osipenko if (IS_ERR(rdev->coupling_desc.coupler)) { 5380d8ca7d18SDmitry Osipenko err = PTR_ERR(rdev->coupling_desc.coupler); 538161aab5adSMichał Mirosław rdev_err(rdev, "failed to get coupler: %pe\n", ERR_PTR(err)); 5382d8ca7d18SDmitry Osipenko return err; 5383d8ca7d18SDmitry Osipenko } 5384d8ca7d18SDmitry Osipenko 5385d3d64537SMaciej Purski return 0; 5386d3d64537SMaciej Purski } 5387d3d64537SMaciej Purski 5388d8ca7d18SDmitry Osipenko static int generic_coupler_attach(struct regulator_coupler *coupler, 5389d8ca7d18SDmitry Osipenko struct regulator_dev *rdev) 5390d8ca7d18SDmitry Osipenko { 5391d8ca7d18SDmitry Osipenko if (rdev->coupling_desc.n_coupled > 2) { 5392d8ca7d18SDmitry Osipenko rdev_err(rdev, 5393d8ca7d18SDmitry Osipenko "Voltage balancing for multiple regulator couples is unimplemented\n"); 5394d8ca7d18SDmitry Osipenko return -EPERM; 5395d8ca7d18SDmitry Osipenko } 5396d8ca7d18SDmitry Osipenko 5397e381bfe4SDmitry Osipenko if (!rdev->constraints->always_on) { 5398e381bfe4SDmitry Osipenko rdev_err(rdev, 5399e381bfe4SDmitry Osipenko "Coupling of a non always-on regulator is unimplemented\n"); 5400e381bfe4SDmitry Osipenko return -ENOTSUPP; 5401e381bfe4SDmitry Osipenko } 5402e381bfe4SDmitry Osipenko 5403d8ca7d18SDmitry Osipenko return 0; 5404d8ca7d18SDmitry Osipenko } 5405d8ca7d18SDmitry Osipenko 5406d8ca7d18SDmitry Osipenko static struct regulator_coupler generic_regulator_coupler = { 5407d8ca7d18SDmitry Osipenko .attach_regulator = generic_coupler_attach, 5408d8ca7d18SDmitry Osipenko }; 5409d8ca7d18SDmitry Osipenko 5410414c70cbSLiam Girdwood /** 5411414c70cbSLiam Girdwood * regulator_register - register regulator 541269279fb9SMark Brown * @regulator_desc: regulator to register 5413f47531b1SKrzysztof Kozlowski * @cfg: runtime configuration for regulator 5414414c70cbSLiam Girdwood * 5415414c70cbSLiam Girdwood * Called by regulator drivers to register a regulator. 54160384618aSAxel Lin * Returns a valid pointer to struct regulator_dev on success 54170384618aSAxel Lin * or an ERR_PTR() on error. 5418414c70cbSLiam Girdwood */ 541965f26846SMark Brown struct regulator_dev * 542065f26846SMark Brown regulator_register(const struct regulator_desc *regulator_desc, 54211b3de223SKrzysztof Kozlowski const struct regulator_config *cfg) 5422414c70cbSLiam Girdwood { 5423c172708dSMark Brown const struct regulator_init_data *init_data; 54241b3de223SKrzysztof Kozlowski struct regulator_config *config = NULL; 542572dca06fSAniroop Mathur static atomic_t regulator_no = ATOMIC_INIT(-1); 5426414c70cbSLiam Girdwood struct regulator_dev *rdev; 54270edb040dSLinus Walleij bool dangling_cfg_gpiod = false; 54280edb040dSLinus Walleij bool dangling_of_gpiod = false; 542932c8fad4SMark Brown struct device *dev; 5430a5766f11SLiam Girdwood int ret, i; 5431520fb178SChristian Kohlschütter bool resolved_early = false; 5432414c70cbSLiam Girdwood 54330edb040dSLinus Walleij if (cfg == NULL) 5434414c70cbSLiam Girdwood return ERR_PTR(-EINVAL); 54350edb040dSLinus Walleij if (cfg->ena_gpiod) 54360edb040dSLinus Walleij dangling_cfg_gpiod = true; 54370edb040dSLinus Walleij if (regulator_desc == NULL) { 54380edb040dSLinus Walleij ret = -EINVAL; 54390edb040dSLinus Walleij goto rinse; 54400edb040dSLinus Walleij } 5441414c70cbSLiam Girdwood 54421b3de223SKrzysztof Kozlowski dev = cfg->dev; 5443dcf70112SMark Brown WARN_ON(!dev); 544432c8fad4SMark Brown 54450edb040dSLinus Walleij if (regulator_desc->name == NULL || regulator_desc->ops == NULL) { 54460edb040dSLinus Walleij ret = -EINVAL; 54470edb040dSLinus Walleij goto rinse; 54480edb040dSLinus Walleij } 5449414c70cbSLiam Girdwood 5450cd78dfc6SDiego Liziero if (regulator_desc->type != REGULATOR_VOLTAGE && 54510edb040dSLinus Walleij regulator_desc->type != REGULATOR_CURRENT) { 54520edb040dSLinus Walleij ret = -EINVAL; 54530edb040dSLinus Walleij goto rinse; 54540edb040dSLinus Walleij } 5455414c70cbSLiam Girdwood 5456476c2d83SMark Brown /* Only one of each should be implemented */ 5457476c2d83SMark Brown WARN_ON(regulator_desc->ops->get_voltage && 5458476c2d83SMark Brown regulator_desc->ops->get_voltage_sel); 5459e8eef82bSMark Brown WARN_ON(regulator_desc->ops->set_voltage && 5460e8eef82bSMark Brown regulator_desc->ops->set_voltage_sel); 5461476c2d83SMark Brown 5462476c2d83SMark Brown /* If we're using selectors we must implement list_voltage. */ 5463476c2d83SMark Brown if (regulator_desc->ops->get_voltage_sel && 5464476c2d83SMark Brown !regulator_desc->ops->list_voltage) { 54650edb040dSLinus Walleij ret = -EINVAL; 54660edb040dSLinus Walleij goto rinse; 5467476c2d83SMark Brown } 5468e8eef82bSMark Brown if (regulator_desc->ops->set_voltage_sel && 5469e8eef82bSMark Brown !regulator_desc->ops->list_voltage) { 54700edb040dSLinus Walleij ret = -EINVAL; 54710edb040dSLinus Walleij goto rinse; 5472e8eef82bSMark Brown } 5473476c2d83SMark Brown 5474414c70cbSLiam Girdwood rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); 54750edb040dSLinus Walleij if (rdev == NULL) { 54760edb040dSLinus Walleij ret = -ENOMEM; 54770edb040dSLinus Walleij goto rinse; 54780edb040dSLinus Walleij } 5479d3c73156SMichał Mirosław device_initialize(&rdev->dev); 54807111c6d1SMatti Vaittinen spin_lock_init(&rdev->err_lock); 5481414c70cbSLiam Girdwood 54821b3de223SKrzysztof Kozlowski /* 54831b3de223SKrzysztof Kozlowski * Duplicate the config so the driver could override it after 54841b3de223SKrzysztof Kozlowski * parsing init data. 54851b3de223SKrzysztof Kozlowski */ 54861b3de223SKrzysztof Kozlowski config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL); 54871b3de223SKrzysztof Kozlowski if (config == NULL) { 54880edb040dSLinus Walleij ret = -ENOMEM; 5489d3c73156SMichał Mirosław goto clean; 54901b3de223SKrzysztof Kozlowski } 54911b3de223SKrzysztof Kozlowski 5492bfa21a0dSKrzysztof Kozlowski init_data = regulator_of_get_init_data(dev, regulator_desc, config, 5493a0c7b164SMark Brown &rdev->dev.of_node); 5494f8970d34SMarco Felsch 5495f8970d34SMarco Felsch /* 5496f8970d34SMarco Felsch * Sometimes not all resources are probed already so we need to take 5497f8970d34SMarco Felsch * that into account. This happens most the time if the ena_gpiod comes 5498f8970d34SMarco Felsch * from a gpio extender or something else. 5499f8970d34SMarco Felsch */ 5500f8970d34SMarco Felsch if (PTR_ERR(init_data) == -EPROBE_DEFER) { 5501f8970d34SMarco Felsch ret = -EPROBE_DEFER; 5502d3c73156SMichał Mirosław goto clean; 5503f8970d34SMarco Felsch } 5504f8970d34SMarco Felsch 55050edb040dSLinus Walleij /* 55060edb040dSLinus Walleij * We need to keep track of any GPIO descriptor coming from the 55070edb040dSLinus Walleij * device tree until we have handled it over to the core. If the 55080edb040dSLinus Walleij * config that was passed in to this function DOES NOT contain 55090edb040dSLinus Walleij * a descriptor, and the config after this call DOES contain 551048f1b4efSKrzysztof Kozlowski * a descriptor, we definitely got one from parsing the device 55110edb040dSLinus Walleij * tree. 55120edb040dSLinus Walleij */ 55130edb040dSLinus Walleij if (!cfg->ena_gpiod && config->ena_gpiod) 55140edb040dSLinus Walleij dangling_of_gpiod = true; 5515a0c7b164SMark Brown if (!init_data) { 5516a0c7b164SMark Brown init_data = config->init_data; 5517a0c7b164SMark Brown rdev->dev.of_node = of_node_get(config->of_node); 5518a0c7b164SMark Brown } 5519a0c7b164SMark Brown 5520f8702f9eSDmitry Osipenko ww_mutex_init(&rdev->mutex, ®ulator_ww_class); 5521c172708dSMark Brown rdev->reg_data = config->driver_data; 5522414c70cbSLiam Girdwood rdev->owner = regulator_desc->owner; 5523414c70cbSLiam Girdwood rdev->desc = regulator_desc; 55243a4b0a07SMark Brown if (config->regmap) 552565b19ce6SMark Brown rdev->regmap = config->regmap; 552652b84dacSAnilKumar Ch else if (dev_get_regmap(dev, NULL)) 55273a4b0a07SMark Brown rdev->regmap = dev_get_regmap(dev, NULL); 552852b84dacSAnilKumar Ch else if (dev->parent) 552952b84dacSAnilKumar Ch rdev->regmap = dev_get_regmap(dev->parent, NULL); 5530414c70cbSLiam Girdwood INIT_LIST_HEAD(&rdev->consumer_list); 5531414c70cbSLiam Girdwood INIT_LIST_HEAD(&rdev->list); 5532414c70cbSLiam Girdwood BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); 5533da07ecd9SMark Brown INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); 5534414c70cbSLiam Girdwood 5535520fb178SChristian Kohlschütter if (init_data && init_data->supply_regulator) 5536520fb178SChristian Kohlschütter rdev->supply_name = init_data->supply_regulator; 5537520fb178SChristian Kohlschütter else if (regulator_desc->supply_name) 5538520fb178SChristian Kohlschütter rdev->supply_name = regulator_desc->supply_name; 5539daad134dSKrzysztof Adamski 5540a5766f11SLiam Girdwood /* register with sysfs */ 5541a5766f11SLiam Girdwood rdev->dev.class = ®ulator_class; 5542a5766f11SLiam Girdwood rdev->dev.parent = dev; 554372dca06fSAniroop Mathur dev_set_name(&rdev->dev, "regulator.%lu", 554439138818SAniroop Mathur (unsigned long) atomic_inc_return(®ulator_no)); 55459177514cSVladimir Zapolskiy dev_set_drvdata(&rdev->dev, rdev); 5546a5766f11SLiam Girdwood 554774f544c1SMike Rapoport /* set regulator constraints */ 55489a8f5e07SMark Brown if (init_data) 554957a6ad48SMichał Mirosław rdev->constraints = kmemdup(&init_data->constraints, 555057a6ad48SMichał Mirosław sizeof(*rdev->constraints), 555157a6ad48SMichał Mirosław GFP_KERNEL); 555257a6ad48SMichał Mirosław else 555357a6ad48SMichał Mirosław rdev->constraints = kzalloc(sizeof(*rdev->constraints), 555457a6ad48SMichał Mirosław GFP_KERNEL); 555557a6ad48SMichał Mirosław if (!rdev->constraints) { 555657a6ad48SMichał Mirosław ret = -ENOMEM; 555757a6ad48SMichał Mirosław goto wash; 555857a6ad48SMichał Mirosław } 55599a8f5e07SMark Brown 55608a866d52SChristian Kohlschütter if ((rdev->supply_name && !rdev->supply) && 55618a866d52SChristian Kohlschütter (rdev->constraints->always_on || 55628a866d52SChristian Kohlschütter rdev->constraints->boot_on)) { 55638a866d52SChristian Kohlschütter ret = regulator_resolve_supply(rdev); 55648a866d52SChristian Kohlschütter if (ret) 55658a866d52SChristian Kohlschütter rdev_dbg(rdev, "unable to resolve supply early: %pe\n", 55668a866d52SChristian Kohlschütter ERR_PTR(ret)); 5567520fb178SChristian Kohlschütter 5568520fb178SChristian Kohlschütter resolved_early = true; 55698a866d52SChristian Kohlschütter } 55708a866d52SChristian Kohlschütter 55718a866d52SChristian Kohlschütter /* perform any regulator specific init */ 5572414c70cbSLiam Girdwood if (init_data && init_data->regulator_init) { 5573414c70cbSLiam Girdwood ret = init_data->regulator_init(rdev->reg_data); 5574414c70cbSLiam Girdwood if (ret < 0) 5575520fb178SChristian Kohlschütter goto wash; 5576414c70cbSLiam Girdwood } 5577414c70cbSLiam Girdwood 5578414c70cbSLiam Girdwood if (config->ena_gpiod) { 5579414c70cbSLiam Girdwood ret = regulator_ena_gpio_request(rdev, config); 5580a5766f11SLiam Girdwood if (ret != 0) { 5581a5766f11SLiam Girdwood rdev_err(rdev, "Failed to request enable GPIO: %pe\n", 5582a5766f11SLiam Girdwood ERR_PTR(ret)); 5583520fb178SChristian Kohlschütter goto wash; 5584a5766f11SLiam Girdwood } 5585a5766f11SLiam Girdwood /* The regulator core took over the GPIO descriptor */ 5586a5766f11SLiam Girdwood dangling_cfg_gpiod = false; 5587a5766f11SLiam Girdwood dangling_of_gpiod = false; 5588a5766f11SLiam Girdwood } 558969511a45SRajendra Nayak 559057a6ad48SMichał Mirosław ret = set_machine_constraints(rdev); 5591520fb178SChristian Kohlschütter if (ret == -EPROBE_DEFER && !resolved_early) { 5592aea6cb99SMichał Mirosław /* Regulator might be in bypass mode and so needs its supply 559369b8821eSShubhankar Kuranagatti * to set the constraints 559469b8821eSShubhankar Kuranagatti */ 5595aea6cb99SMichał Mirosław /* FIXME: this currently triggers a chicken-and-egg problem 5596aea6cb99SMichał Mirosław * when creating -SUPPLY symlink in sysfs to a regulator 559769b8821eSShubhankar Kuranagatti * that is just being created 559869b8821eSShubhankar Kuranagatti */ 55990917c9dbSMichał Mirosław rdev_dbg(rdev, "will resolve supply early: %s\n", 56000917c9dbSMichał Mirosław rdev->supply_name); 5601aea6cb99SMichał Mirosław ret = regulator_resolve_supply(rdev); 5602aea6cb99SMichał Mirosław if (!ret) 560357a6ad48SMichał Mirosław ret = set_machine_constraints(rdev); 5604aea6cb99SMichał Mirosław else 5605aea6cb99SMichał Mirosław rdev_dbg(rdev, "unable to resolve supply early: %pe\n", 5606aea6cb99SMichał Mirosław ERR_PTR(ret)); 5607aea6cb99SMichał Mirosław } 560845389c47SJon Hunter if (ret < 0) 560945389c47SJon Hunter goto wash; 561045389c47SJon Hunter 5611f9503385SDmitry Osipenko ret = regulator_init_coupling(rdev); 5612f9503385SDmitry Osipenko if (ret < 0) 5613d3d64537SMaciej Purski goto wash; 5614d3d64537SMaciej Purski 5615a5766f11SLiam Girdwood /* add consumers devices */ 56169a8f5e07SMark Brown if (init_data) { 5617a5766f11SLiam Girdwood for (i = 0; i < init_data->num_consumer_supplies; i++) { 5618a5766f11SLiam Girdwood ret = set_consumer_device_supply(rdev, 561940f9244fSMark Brown init_data->consumer_supplies[i].dev_name, 5620a5766f11SLiam Girdwood init_data->consumer_supplies[i].supply); 562123c2f041SMark Brown if (ret < 0) { 562223c2f041SMark Brown dev_err(dev, "Failed to set supply %s\n", 562323c2f041SMark Brown init_data->consumer_supplies[i].supply); 5624d4033b54SJani Nikula goto unset_supplies; 5625a5766f11SLiam Girdwood } 562623c2f041SMark Brown } 56279a8f5e07SMark Brown } 5628a5766f11SLiam Girdwood 5629fd086045SMatthias Kaehlcke if (!rdev->desc->ops->get_voltage && 5630fd086045SMatthias Kaehlcke !rdev->desc->ops->list_voltage && 5631fd086045SMatthias Kaehlcke !rdev->desc->fixed_uV) 5632fd086045SMatthias Kaehlcke rdev->is_switch = true; 5633fd086045SMatthias Kaehlcke 56349177514cSVladimir Zapolskiy ret = device_add(&rdev->dev); 56359177514cSVladimir Zapolskiy if (ret != 0) 5636c438b9d0SJon Hunter goto unset_supplies; 5637c438b9d0SJon Hunter 56381130e5b3SMark Brown rdev_init_debugfs(rdev); 56395e3ca2b3SJavier Martinez Canillas 5640f9503385SDmitry Osipenko /* try to resolve regulators coupling since a new one was registered */ 5641f9503385SDmitry Osipenko mutex_lock(®ulator_list_mutex); 5642f9503385SDmitry Osipenko regulator_resolve_coupling(rdev); 5643f9503385SDmitry Osipenko mutex_unlock(®ulator_list_mutex); 5644f9503385SDmitry Osipenko 56455e3ca2b3SJavier Martinez Canillas /* try to resolve regulators supply since a new one was registered */ 56465e3ca2b3SJavier Martinez Canillas class_for_each_device(®ulator_class, NULL, NULL, 56475e3ca2b3SJavier Martinez Canillas regulator_register_resolve_supply); 56481b3de223SKrzysztof Kozlowski kfree(config); 5649414c70cbSLiam Girdwood return rdev; 56504fca9545SDavid Brownell 5651d4033b54SJani Nikula unset_supplies: 565245389c47SJon Hunter mutex_lock(®ulator_list_mutex); 5653d4033b54SJani Nikula unset_regulator_supplies(rdev); 5654d8ca7d18SDmitry Osipenko regulator_remove_coupling(rdev); 565545389c47SJon Hunter mutex_unlock(®ulator_list_mutex); 565632165230SKrzysztof Adamski wash: 565726c2c997SDmitry Osipenko kfree(rdev->coupling_desc.coupled_rdevs); 565845389c47SJon Hunter mutex_lock(®ulator_list_mutex); 565932165230SKrzysztof Adamski regulator_ena_gpio_free(rdev); 566045389c47SJon Hunter mutex_unlock(®ulator_list_mutex); 56614fca9545SDavid Brownell clean: 56620edb040dSLinus Walleij if (dangling_of_gpiod) 56630edb040dSLinus Walleij gpiod_put(config->ena_gpiod); 5664a2151374SJon Hunter kfree(config); 5665d3c73156SMichał Mirosław put_device(&rdev->dev); 56660edb040dSLinus Walleij rinse: 56670edb040dSLinus Walleij if (dangling_cfg_gpiod) 56680edb040dSLinus Walleij gpiod_put(cfg->ena_gpiod); 5669a2151374SJon Hunter return ERR_PTR(ret); 5670414c70cbSLiam Girdwood } 5671414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_register); 5672414c70cbSLiam Girdwood 5673414c70cbSLiam Girdwood /** 5674414c70cbSLiam Girdwood * regulator_unregister - unregister regulator 567569279fb9SMark Brown * @rdev: regulator to unregister 5676414c70cbSLiam Girdwood * 5677414c70cbSLiam Girdwood * Called by regulator drivers to unregister a regulator. 5678414c70cbSLiam Girdwood */ 5679414c70cbSLiam Girdwood void regulator_unregister(struct regulator_dev *rdev) 5680414c70cbSLiam Girdwood { 5681414c70cbSLiam Girdwood if (rdev == NULL) 5682414c70cbSLiam Girdwood return; 5683414c70cbSLiam Girdwood 5684891636eaSMark Brown if (rdev->supply) { 5685891636eaSMark Brown while (rdev->use_count--) 5686891636eaSMark Brown regulator_disable(rdev->supply); 5687e032b376SMark Brown regulator_put(rdev->supply); 5688891636eaSMark Brown } 5689ff9b34b6SDmitry Osipenko 569006377301SCharles Keepax flush_work(&rdev->disable_work.work); 569106377301SCharles Keepax 5692414c70cbSLiam Girdwood mutex_lock(®ulator_list_mutex); 5693ff9b34b6SDmitry Osipenko 56941130e5b3SMark Brown debugfs_remove_recursive(rdev->debugfs); 56956bf87d17SMark Brown WARN_ON(rdev->open_count); 56966303f3e7SDmitry Osipenko regulator_remove_coupling(rdev); 56970f1d747bSMike Rapoport unset_regulator_supplies(rdev); 5698414c70cbSLiam Girdwood list_del(&rdev->list); 5699f19b00daSKim, Milo regulator_ena_gpio_free(rdev); 570058fb5cf5SLothar Waßmann device_unregister(&rdev->dev); 5701ff9b34b6SDmitry Osipenko 5702ff9b34b6SDmitry Osipenko mutex_unlock(®ulator_list_mutex); 5703414c70cbSLiam Girdwood } 5704414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_unregister); 5705414c70cbSLiam Girdwood 5706f7efad10SChunyan Zhang #ifdef CONFIG_SUSPEND 5707414c70cbSLiam Girdwood /** 57080380cf7dSpascal paillet * regulator_suspend - prepare regulators for system wide suspend 57091efef7ccSRandy Dunlap * @dev: ``&struct device`` pointer that is passed to _regulator_suspend() 5710414c70cbSLiam Girdwood * 5711414c70cbSLiam Girdwood * Configure each regulator with it's suspend operating parameters for state. 5712414c70cbSLiam Girdwood */ 57130380cf7dSpascal paillet static int regulator_suspend(struct device *dev) 5714414c70cbSLiam Girdwood { 5715cd7e36abSMarek Szyprowski struct regulator_dev *rdev = dev_to_rdev(dev); 5716f7efad10SChunyan Zhang suspend_state_t state = pm_suspend_target_state; 5717cd7e36abSMarek Szyprowski int ret; 57180955f5beSStephen Boyd const struct regulator_state *rstate; 57190955f5beSStephen Boyd 57200955f5beSStephen Boyd rstate = regulator_get_suspend_state_check(rdev, state); 57210955f5beSStephen Boyd if (!rstate) 57220955f5beSStephen Boyd return 0; 5723414c70cbSLiam Girdwood 5724cd7e36abSMarek Szyprowski regulator_lock(rdev); 57250955f5beSStephen Boyd ret = __suspend_set_state(rdev, rstate); 5726cd7e36abSMarek Szyprowski regulator_unlock(rdev); 5727cd7e36abSMarek Szyprowski 5728cd7e36abSMarek Szyprowski return ret; 5729414c70cbSLiam Girdwood } 5730d3e4eccbSMark Brown 5731cd7e36abSMarek Szyprowski static int regulator_resume(struct device *dev) 573285f3b431STomeu Vizoso { 5733cd7e36abSMarek Szyprowski suspend_state_t state = pm_suspend_target_state; 573485f3b431STomeu Vizoso struct regulator_dev *rdev = dev_to_rdev(dev); 5735f7efad10SChunyan Zhang struct regulator_state *rstate; 5736cd7e36abSMarek Szyprowski int ret = 0; 5737f7efad10SChunyan Zhang 5738cd7e36abSMarek Szyprowski rstate = regulator_get_suspend_state(rdev, state); 5739f7efad10SChunyan Zhang if (rstate == NULL) 574035b5f14eSGeert Uytterhoeven return 0; 574185f3b431STomeu Vizoso 57420955f5beSStephen Boyd /* Avoid grabbing the lock if we don't need to */ 57430955f5beSStephen Boyd if (!rdev->desc->ops->resume) 57440955f5beSStephen Boyd return 0; 57450955f5beSStephen Boyd 574666cf9a7eSMaciej Purski regulator_lock(rdev); 574785f3b431STomeu Vizoso 57480955f5beSStephen Boyd if (rstate->enabled == ENABLE_IN_SUSPEND || 57490955f5beSStephen Boyd rstate->enabled == DISABLE_IN_SUSPEND) 57500380cf7dSpascal paillet ret = rdev->desc->ops->resume(rdev); 5751f7efad10SChunyan Zhang 575266cf9a7eSMaciej Purski regulator_unlock(rdev); 575385f3b431STomeu Vizoso 5754f7efad10SChunyan Zhang return ret; 575585f3b431STomeu Vizoso } 5756f7efad10SChunyan Zhang #else /* !CONFIG_SUSPEND */ 5757f7efad10SChunyan Zhang 57580380cf7dSpascal paillet #define regulator_suspend NULL 57590380cf7dSpascal paillet #define regulator_resume NULL 5760f7efad10SChunyan Zhang 5761f7efad10SChunyan Zhang #endif /* !CONFIG_SUSPEND */ 5762f7efad10SChunyan Zhang 5763f7efad10SChunyan Zhang #ifdef CONFIG_PM 5764f7efad10SChunyan Zhang static const struct dev_pm_ops __maybe_unused regulator_pm_ops = { 57650380cf7dSpascal paillet .suspend = regulator_suspend, 57660380cf7dSpascal paillet .resume = regulator_resume, 5767f7efad10SChunyan Zhang }; 5768f7efad10SChunyan Zhang #endif 5769f7efad10SChunyan Zhang 5770285c22deSMark Brown struct class regulator_class = { 5771f7efad10SChunyan Zhang .name = "regulator", 5772f7efad10SChunyan Zhang .dev_release = regulator_dev_release, 5773f7efad10SChunyan Zhang .dev_groups = regulator_dev_groups, 5774f7efad10SChunyan Zhang #ifdef CONFIG_PM 5775f7efad10SChunyan Zhang .pm = ®ulator_pm_ops, 5776f7efad10SChunyan Zhang #endif 5777f7efad10SChunyan Zhang }; 57787a32b589SMyungJoo Ham /** 5779ca725561SMark Brown * regulator_has_full_constraints - the system has fully specified constraints 5780ca725561SMark Brown * 5781ca725561SMark Brown * Calling this function will cause the regulator API to disable all 5782ca725561SMark Brown * regulators which have a zero use count and don't have an always_on 5783ca725561SMark Brown * constraint in a late_initcall. 5784ca725561SMark Brown * 5785ca725561SMark Brown * The intention is that this will become the default behaviour in a 5786ca725561SMark Brown * future kernel release so users are encouraged to use this facility 5787ca725561SMark Brown * now. 5788ca725561SMark Brown */ 5789ca725561SMark Brown void regulator_has_full_constraints(void) 5790ca725561SMark Brown { 5791ca725561SMark Brown has_full_constraints = 1; 5792ca725561SMark Brown } 5793ca725561SMark Brown EXPORT_SYMBOL_GPL(regulator_has_full_constraints); 5794ca725561SMark Brown 5795ca725561SMark Brown /** 5796414c70cbSLiam Girdwood * rdev_get_drvdata - get rdev regulator driver data 579769279fb9SMark Brown * @rdev: regulator 5798414c70cbSLiam Girdwood * 5799414c70cbSLiam Girdwood * Get rdev regulator driver private data. This call can be used in the 5800414c70cbSLiam Girdwood * regulator driver context. 5801414c70cbSLiam Girdwood */ 5802414c70cbSLiam Girdwood void *rdev_get_drvdata(struct regulator_dev *rdev) 5803414c70cbSLiam Girdwood { 5804414c70cbSLiam Girdwood return rdev->reg_data; 5805414c70cbSLiam Girdwood } 5806414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(rdev_get_drvdata); 5807414c70cbSLiam Girdwood 5808414c70cbSLiam Girdwood /** 5809414c70cbSLiam Girdwood * regulator_get_drvdata - get regulator driver data 5810414c70cbSLiam Girdwood * @regulator: regulator 5811414c70cbSLiam Girdwood * 5812414c70cbSLiam Girdwood * Get regulator driver private data. This call can be used in the consumer 5813414c70cbSLiam Girdwood * driver context when non API regulator specific functions need to be called. 5814414c70cbSLiam Girdwood */ 5815414c70cbSLiam Girdwood void *regulator_get_drvdata(struct regulator *regulator) 5816414c70cbSLiam Girdwood { 5817414c70cbSLiam Girdwood return regulator->rdev->reg_data; 5818414c70cbSLiam Girdwood } 5819414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_drvdata); 5820414c70cbSLiam Girdwood 5821414c70cbSLiam Girdwood /** 5822414c70cbSLiam Girdwood * regulator_set_drvdata - set regulator driver data 5823414c70cbSLiam Girdwood * @regulator: regulator 5824414c70cbSLiam Girdwood * @data: data 5825414c70cbSLiam Girdwood */ 5826414c70cbSLiam Girdwood void regulator_set_drvdata(struct regulator *regulator, void *data) 5827414c70cbSLiam Girdwood { 5828414c70cbSLiam Girdwood regulator->rdev->reg_data = data; 5829414c70cbSLiam Girdwood } 5830414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_drvdata); 5831414c70cbSLiam Girdwood 5832414c70cbSLiam Girdwood /** 5833d73e873bSMauro Carvalho Chehab * rdev_get_id - get regulator ID 583469279fb9SMark Brown * @rdev: regulator 5835414c70cbSLiam Girdwood */ 5836414c70cbSLiam Girdwood int rdev_get_id(struct regulator_dev *rdev) 5837414c70cbSLiam Girdwood { 5838414c70cbSLiam Girdwood return rdev->desc->id; 5839414c70cbSLiam Girdwood } 5840414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(rdev_get_id); 5841414c70cbSLiam Girdwood 5842a5766f11SLiam Girdwood struct device *rdev_get_dev(struct regulator_dev *rdev) 5843a5766f11SLiam Girdwood { 5844a5766f11SLiam Girdwood return &rdev->dev; 5845a5766f11SLiam Girdwood } 5846a5766f11SLiam Girdwood EXPORT_SYMBOL_GPL(rdev_get_dev); 5847a5766f11SLiam Girdwood 584803c87b95SBartosz Golaszewski struct regmap *rdev_get_regmap(struct regulator_dev *rdev) 584903c87b95SBartosz Golaszewski { 585003c87b95SBartosz Golaszewski return rdev->regmap; 585103c87b95SBartosz Golaszewski } 585203c87b95SBartosz Golaszewski EXPORT_SYMBOL_GPL(rdev_get_regmap); 585303c87b95SBartosz Golaszewski 5854a5766f11SLiam Girdwood void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) 5855a5766f11SLiam Girdwood { 5856a5766f11SLiam Girdwood return reg_init_data->driver_data; 5857a5766f11SLiam Girdwood } 5858a5766f11SLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_init_drvdata); 5859a5766f11SLiam Girdwood 5860ba55a974SMark Brown #ifdef CONFIG_DEBUG_FS 5861dbc55955SHaishan Zhou static int supply_map_show(struct seq_file *sf, void *data) 5862ba55a974SMark Brown { 5863ba55a974SMark Brown struct regulator_map *map; 5864ba55a974SMark Brown 5865ba55a974SMark Brown list_for_each_entry(map, ®ulator_map_list, list) { 5866dbc55955SHaishan Zhou seq_printf(sf, "%s -> %s.%s\n", 5867ba55a974SMark Brown rdev_get_name(map->regulator), map->dev_name, 5868ba55a974SMark Brown map->supply); 5869ba55a974SMark Brown } 5870ba55a974SMark Brown 5871dbc55955SHaishan Zhou return 0; 5872dbc55955SHaishan Zhou } 58733e60b4fcSYangtao Li DEFINE_SHOW_ATTRIBUTE(supply_map); 5874ba55a974SMark Brown 587585f3b431STomeu Vizoso struct summary_data { 587685f3b431STomeu Vizoso struct seq_file *s; 587785f3b431STomeu Vizoso struct regulator_dev *parent; 587885f3b431STomeu Vizoso int level; 587985f3b431STomeu Vizoso }; 588085f3b431STomeu Vizoso 588185f3b431STomeu Vizoso static void regulator_summary_show_subtree(struct seq_file *s, 588285f3b431STomeu Vizoso struct regulator_dev *rdev, 588385f3b431STomeu Vizoso int level); 588485f3b431STomeu Vizoso 588585f3b431STomeu Vizoso static int regulator_summary_show_children(struct device *dev, void *data) 588685f3b431STomeu Vizoso { 588785f3b431STomeu Vizoso struct regulator_dev *rdev = dev_to_rdev(dev); 588885f3b431STomeu Vizoso struct summary_data *summary_data = data; 588985f3b431STomeu Vizoso 589085f3b431STomeu Vizoso if (rdev->supply && rdev->supply->rdev == summary_data->parent) 589185f3b431STomeu Vizoso regulator_summary_show_subtree(summary_data->s, rdev, 589285f3b431STomeu Vizoso summary_data->level + 1); 589385f3b431STomeu Vizoso 589485f3b431STomeu Vizoso return 0; 589585f3b431STomeu Vizoso } 589685f3b431STomeu Vizoso 58977c225ec9SHeiko Stübner static void regulator_summary_show_subtree(struct seq_file *s, 58987c225ec9SHeiko Stübner struct regulator_dev *rdev, 58997c225ec9SHeiko Stübner int level) 59007c225ec9SHeiko Stübner { 59017c225ec9SHeiko Stübner struct regulation_constraints *c; 59027c225ec9SHeiko Stübner struct regulator *consumer; 590385f3b431STomeu Vizoso struct summary_data summary_data; 59047e4d9683SDouglas Anderson unsigned int opmode; 59057c225ec9SHeiko Stübner 59067c225ec9SHeiko Stübner if (!rdev) 59077c225ec9SHeiko Stübner return; 59087c225ec9SHeiko Stübner 59097e4d9683SDouglas Anderson opmode = _regulator_get_mode_unlocked(rdev); 591001de19d0SDouglas Anderson seq_printf(s, "%*s%-*s %3d %4d %6d %7s ", 59117c225ec9SHeiko Stübner level * 3 + 1, "", 59127c225ec9SHeiko Stübner 30 - level * 3, rdev_get_name(rdev), 591301de19d0SDouglas Anderson rdev->use_count, rdev->open_count, rdev->bypass_count, 59147e4d9683SDouglas Anderson regulator_opmode_to_str(opmode)); 59157c225ec9SHeiko Stübner 5916d22b85a1SDmitry Osipenko seq_printf(s, "%5dmV ", regulator_get_voltage_rdev(rdev) / 1000); 59177e4d9683SDouglas Anderson seq_printf(s, "%5dmA ", 59187e4d9683SDouglas Anderson _regulator_get_current_limit_unlocked(rdev) / 1000); 59197c225ec9SHeiko Stübner 59207c225ec9SHeiko Stübner c = rdev->constraints; 59217c225ec9SHeiko Stübner if (c) { 59227c225ec9SHeiko Stübner switch (rdev->desc->type) { 59237c225ec9SHeiko Stübner case REGULATOR_VOLTAGE: 59247c225ec9SHeiko Stübner seq_printf(s, "%5dmV %5dmV ", 59257c225ec9SHeiko Stübner c->min_uV / 1000, c->max_uV / 1000); 59267c225ec9SHeiko Stübner break; 59277c225ec9SHeiko Stübner case REGULATOR_CURRENT: 59287c225ec9SHeiko Stübner seq_printf(s, "%5dmA %5dmA ", 59297c225ec9SHeiko Stübner c->min_uA / 1000, c->max_uA / 1000); 59307c225ec9SHeiko Stübner break; 59317c225ec9SHeiko Stübner } 59327c225ec9SHeiko Stübner } 59337c225ec9SHeiko Stübner 59347c225ec9SHeiko Stübner seq_puts(s, "\n"); 59357c225ec9SHeiko Stübner 59367c225ec9SHeiko Stübner list_for_each_entry(consumer, &rdev->consumer_list, list) { 5937e42a46b6SLeonard Crestez if (consumer->dev && consumer->dev->class == ®ulator_class) 59387c225ec9SHeiko Stübner continue; 59397c225ec9SHeiko Stübner 59407c225ec9SHeiko Stübner seq_printf(s, "%*s%-*s ", 59417c225ec9SHeiko Stübner (level + 1) * 3 + 1, "", 5942e42a46b6SLeonard Crestez 30 - (level + 1) * 3, 59436b576eb0SMichał Mirosław consumer->supply_name ? consumer->supply_name : 5944e42a46b6SLeonard Crestez consumer->dev ? dev_name(consumer->dev) : "deviceless"); 59457c225ec9SHeiko Stübner 59467c225ec9SHeiko Stübner switch (rdev->desc->type) { 59477c225ec9SHeiko Stübner case REGULATOR_VOLTAGE: 59485451781dSDouglas Anderson seq_printf(s, "%3d %33dmA%c%5dmV %5dmV", 59495451781dSDouglas Anderson consumer->enable_count, 59507d3827b5SDouglas Anderson consumer->uA_load / 1000, 59515451781dSDouglas Anderson consumer->uA_load && !consumer->enable_count ? 59525451781dSDouglas Anderson '*' : ' ', 5953c360a6dfSChunyan Zhang consumer->voltage[PM_SUSPEND_ON].min_uV / 1000, 5954c360a6dfSChunyan Zhang consumer->voltage[PM_SUSPEND_ON].max_uV / 1000); 59557c225ec9SHeiko Stübner break; 59567c225ec9SHeiko Stübner case REGULATOR_CURRENT: 59577c225ec9SHeiko Stübner break; 59587c225ec9SHeiko Stübner } 59597c225ec9SHeiko Stübner 59607c225ec9SHeiko Stübner seq_puts(s, "\n"); 59617c225ec9SHeiko Stübner } 59627c225ec9SHeiko Stübner 596385f3b431STomeu Vizoso summary_data.s = s; 596485f3b431STomeu Vizoso summary_data.level = level; 596585f3b431STomeu Vizoso summary_data.parent = rdev; 59667c225ec9SHeiko Stübner 596785f3b431STomeu Vizoso class_for_each_device(®ulator_class, NULL, &summary_data, 596885f3b431STomeu Vizoso regulator_summary_show_children); 5969f8702f9eSDmitry Osipenko } 5970f8702f9eSDmitry Osipenko 5971f8702f9eSDmitry Osipenko struct summary_lock_data { 5972f8702f9eSDmitry Osipenko struct ww_acquire_ctx *ww_ctx; 5973f8702f9eSDmitry Osipenko struct regulator_dev **new_contended_rdev; 5974f8702f9eSDmitry Osipenko struct regulator_dev **old_contended_rdev; 5975f8702f9eSDmitry Osipenko }; 5976f8702f9eSDmitry Osipenko 5977f8702f9eSDmitry Osipenko static int regulator_summary_lock_one(struct device *dev, void *data) 5978f8702f9eSDmitry Osipenko { 5979f8702f9eSDmitry Osipenko struct regulator_dev *rdev = dev_to_rdev(dev); 5980f8702f9eSDmitry Osipenko struct summary_lock_data *lock_data = data; 5981f8702f9eSDmitry Osipenko int ret = 0; 5982f8702f9eSDmitry Osipenko 5983f8702f9eSDmitry Osipenko if (rdev != *lock_data->old_contended_rdev) { 5984f8702f9eSDmitry Osipenko ret = regulator_lock_nested(rdev, lock_data->ww_ctx); 5985f8702f9eSDmitry Osipenko 5986f8702f9eSDmitry Osipenko if (ret == -EDEADLK) 5987f8702f9eSDmitry Osipenko *lock_data->new_contended_rdev = rdev; 5988f8702f9eSDmitry Osipenko else 5989f8702f9eSDmitry Osipenko WARN_ON_ONCE(ret); 5990f8702f9eSDmitry Osipenko } else { 5991f8702f9eSDmitry Osipenko *lock_data->old_contended_rdev = NULL; 5992f8702f9eSDmitry Osipenko } 5993f8702f9eSDmitry Osipenko 5994f8702f9eSDmitry Osipenko return ret; 5995f8702f9eSDmitry Osipenko } 5996f8702f9eSDmitry Osipenko 5997f8702f9eSDmitry Osipenko static int regulator_summary_unlock_one(struct device *dev, void *data) 5998f8702f9eSDmitry Osipenko { 5999f8702f9eSDmitry Osipenko struct regulator_dev *rdev = dev_to_rdev(dev); 6000f8702f9eSDmitry Osipenko struct summary_lock_data *lock_data = data; 6001f8702f9eSDmitry Osipenko 6002f8702f9eSDmitry Osipenko if (lock_data) { 6003f8702f9eSDmitry Osipenko if (rdev == *lock_data->new_contended_rdev) 6004f8702f9eSDmitry Osipenko return -EDEADLK; 6005f8702f9eSDmitry Osipenko } 60067e4d9683SDouglas Anderson 60077e4d9683SDouglas Anderson regulator_unlock(rdev); 6008f8702f9eSDmitry Osipenko 6009f8702f9eSDmitry Osipenko return 0; 6010f8702f9eSDmitry Osipenko } 6011f8702f9eSDmitry Osipenko 6012f8702f9eSDmitry Osipenko static int regulator_summary_lock_all(struct ww_acquire_ctx *ww_ctx, 6013f8702f9eSDmitry Osipenko struct regulator_dev **new_contended_rdev, 6014f8702f9eSDmitry Osipenko struct regulator_dev **old_contended_rdev) 6015f8702f9eSDmitry Osipenko { 6016f8702f9eSDmitry Osipenko struct summary_lock_data lock_data; 6017f8702f9eSDmitry Osipenko int ret; 6018f8702f9eSDmitry Osipenko 6019f8702f9eSDmitry Osipenko lock_data.ww_ctx = ww_ctx; 6020f8702f9eSDmitry Osipenko lock_data.new_contended_rdev = new_contended_rdev; 6021f8702f9eSDmitry Osipenko lock_data.old_contended_rdev = old_contended_rdev; 6022f8702f9eSDmitry Osipenko 6023f8702f9eSDmitry Osipenko ret = class_for_each_device(®ulator_class, NULL, &lock_data, 6024f8702f9eSDmitry Osipenko regulator_summary_lock_one); 6025f8702f9eSDmitry Osipenko if (ret) 6026f8702f9eSDmitry Osipenko class_for_each_device(®ulator_class, NULL, &lock_data, 6027f8702f9eSDmitry Osipenko regulator_summary_unlock_one); 6028f8702f9eSDmitry Osipenko 6029f8702f9eSDmitry Osipenko return ret; 6030f8702f9eSDmitry Osipenko } 6031f8702f9eSDmitry Osipenko 6032f8702f9eSDmitry Osipenko static void regulator_summary_lock(struct ww_acquire_ctx *ww_ctx) 6033f8702f9eSDmitry Osipenko { 6034f8702f9eSDmitry Osipenko struct regulator_dev *new_contended_rdev = NULL; 6035f8702f9eSDmitry Osipenko struct regulator_dev *old_contended_rdev = NULL; 6036f8702f9eSDmitry Osipenko int err; 6037f8702f9eSDmitry Osipenko 6038ff9b34b6SDmitry Osipenko mutex_lock(®ulator_list_mutex); 6039ff9b34b6SDmitry Osipenko 6040f8702f9eSDmitry Osipenko ww_acquire_init(ww_ctx, ®ulator_ww_class); 6041f8702f9eSDmitry Osipenko 6042f8702f9eSDmitry Osipenko do { 6043f8702f9eSDmitry Osipenko if (new_contended_rdev) { 6044f8702f9eSDmitry Osipenko ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx); 6045f8702f9eSDmitry Osipenko old_contended_rdev = new_contended_rdev; 6046f8702f9eSDmitry Osipenko old_contended_rdev->ref_cnt++; 6047f8702f9eSDmitry Osipenko } 6048f8702f9eSDmitry Osipenko 6049f8702f9eSDmitry Osipenko err = regulator_summary_lock_all(ww_ctx, 6050f8702f9eSDmitry Osipenko &new_contended_rdev, 6051f8702f9eSDmitry Osipenko &old_contended_rdev); 6052f8702f9eSDmitry Osipenko 6053f8702f9eSDmitry Osipenko if (old_contended_rdev) 6054f8702f9eSDmitry Osipenko regulator_unlock(old_contended_rdev); 6055f8702f9eSDmitry Osipenko 6056f8702f9eSDmitry Osipenko } while (err == -EDEADLK); 6057f8702f9eSDmitry Osipenko 6058f8702f9eSDmitry Osipenko ww_acquire_done(ww_ctx); 6059f8702f9eSDmitry Osipenko } 6060f8702f9eSDmitry Osipenko 6061f8702f9eSDmitry Osipenko static void regulator_summary_unlock(struct ww_acquire_ctx *ww_ctx) 6062f8702f9eSDmitry Osipenko { 6063f8702f9eSDmitry Osipenko class_for_each_device(®ulator_class, NULL, NULL, 6064f8702f9eSDmitry Osipenko regulator_summary_unlock_one); 6065f8702f9eSDmitry Osipenko ww_acquire_fini(ww_ctx); 6066ff9b34b6SDmitry Osipenko 6067ff9b34b6SDmitry Osipenko mutex_unlock(®ulator_list_mutex); 60687c225ec9SHeiko Stübner } 606985f3b431STomeu Vizoso 607085f3b431STomeu Vizoso static int regulator_summary_show_roots(struct device *dev, void *data) 607185f3b431STomeu Vizoso { 607285f3b431STomeu Vizoso struct regulator_dev *rdev = dev_to_rdev(dev); 607385f3b431STomeu Vizoso struct seq_file *s = data; 607485f3b431STomeu Vizoso 607585f3b431STomeu Vizoso if (!rdev->supply) 607685f3b431STomeu Vizoso regulator_summary_show_subtree(s, rdev, 0); 607785f3b431STomeu Vizoso 607885f3b431STomeu Vizoso return 0; 60797c225ec9SHeiko Stübner } 60807c225ec9SHeiko Stübner 60817c225ec9SHeiko Stübner static int regulator_summary_show(struct seq_file *s, void *data) 60827c225ec9SHeiko Stübner { 6083f8702f9eSDmitry Osipenko struct ww_acquire_ctx ww_ctx; 6084f8702f9eSDmitry Osipenko 608501de19d0SDouglas Anderson seq_puts(s, " regulator use open bypass opmode voltage current min max\n"); 608601de19d0SDouglas Anderson seq_puts(s, "---------------------------------------------------------------------------------------\n"); 60877c225ec9SHeiko Stübner 6088f8702f9eSDmitry Osipenko regulator_summary_lock(&ww_ctx); 6089f8702f9eSDmitry Osipenko 609085f3b431STomeu Vizoso class_for_each_device(®ulator_class, NULL, s, 609185f3b431STomeu Vizoso regulator_summary_show_roots); 60927c225ec9SHeiko Stübner 6093f8702f9eSDmitry Osipenko regulator_summary_unlock(&ww_ctx); 6094f8702f9eSDmitry Osipenko 60957c225ec9SHeiko Stübner return 0; 60967c225ec9SHeiko Stübner } 60973e60b4fcSYangtao Li DEFINE_SHOW_ATTRIBUTE(regulator_summary); 60983e60b4fcSYangtao Li #endif /* CONFIG_DEBUG_FS */ 60997c225ec9SHeiko Stübner 6100414c70cbSLiam Girdwood static int __init regulator_init(void) 6101414c70cbSLiam Girdwood { 610234abbd68SMark Brown int ret; 610334abbd68SMark Brown 610434abbd68SMark Brown ret = class_register(®ulator_class); 610534abbd68SMark Brown 61061130e5b3SMark Brown debugfs_root = debugfs_create_dir("regulator", NULL); 610724751434SStephen Boyd if (!debugfs_root) 61081130e5b3SMark Brown pr_warn("regulator: Failed to create debugfs directory\n"); 6109ba55a974SMark Brown 61103e60b4fcSYangtao Li #ifdef CONFIG_DEBUG_FS 6111f4d562c6SMark Brown debugfs_create_file("supply_map", 0444, debugfs_root, NULL, 6112f4d562c6SMark Brown &supply_map_fops); 61131130e5b3SMark Brown 61147c225ec9SHeiko Stübner debugfs_create_file("regulator_summary", 0444, debugfs_root, 611585f3b431STomeu Vizoso NULL, ®ulator_summary_fops); 61163e60b4fcSYangtao Li #endif 611734abbd68SMark Brown regulator_dummy_init(); 611834abbd68SMark Brown 6119d8ca7d18SDmitry Osipenko regulator_coupler_register(&generic_regulator_coupler); 6120d8ca7d18SDmitry Osipenko 612134abbd68SMark Brown return ret; 6122414c70cbSLiam Girdwood } 6123414c70cbSLiam Girdwood 6124414c70cbSLiam Girdwood /* init early to allow our consumers to complete system booting */ 6125414c70cbSLiam Girdwood core_initcall(regulator_init); 6126ca725561SMark Brown 612755576cf1SMark Brown static int regulator_late_cleanup(struct device *dev, void *data) 6128ca725561SMark Brown { 6129609ca5f3SMark Brown struct regulator_dev *rdev = dev_to_rdev(dev); 6130609ca5f3SMark Brown struct regulation_constraints *c = rdev->constraints; 61314e2a354eSOliver Barta int ret; 6132ca725561SMark Brown 613366fda75fSMarkus Pargmann if (c && c->always_on) 6134609ca5f3SMark Brown return 0; 6135ca725561SMark Brown 61368a34e979SWEN Pingbo if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) 6137609ca5f3SMark Brown return 0; 6138e9535834SMark Brown 613966cf9a7eSMaciej Purski regulator_lock(rdev); 6140ca725561SMark Brown 6141ca725561SMark Brown if (rdev->use_count) 6142ca725561SMark Brown goto unlock; 6143ca725561SMark Brown 61444e2a354eSOliver Barta /* If reading the status failed, assume that it's off. */ 61454e2a354eSOliver Barta if (_regulator_is_enabled(rdev) <= 0) 6146ca725561SMark Brown goto unlock; 6147ca725561SMark Brown 614887b28417SMark Brown if (have_full_constraints()) { 6149609ca5f3SMark Brown /* We log since this may kill the system if it goes 615069b8821eSShubhankar Kuranagatti * wrong. 615169b8821eSShubhankar Kuranagatti */ 61525da84fd9SJoe Perches rdev_info(rdev, "disabling\n"); 615366fda75fSMarkus Pargmann ret = _regulator_do_disable(rdev); 61540d25d09dSJingoo Han if (ret != 0) 615561aab5adSMichał Mirosław rdev_err(rdev, "couldn't disable: %pe\n", ERR_PTR(ret)); 6156ca725561SMark Brown } else { 6157ca725561SMark Brown /* The intention is that in future we will 6158ca725561SMark Brown * assume that full constraints are provided 6159ca725561SMark Brown * so warn even if we aren't going to do 6160ca725561SMark Brown * anything here. 6161ca725561SMark Brown */ 61625da84fd9SJoe Perches rdev_warn(rdev, "incomplete constraints, leaving on\n"); 6163ca725561SMark Brown } 6164ca725561SMark Brown 6165ca725561SMark Brown unlock: 616666cf9a7eSMaciej Purski regulator_unlock(rdev); 6167609ca5f3SMark Brown 6168609ca5f3SMark Brown return 0; 6169ca725561SMark Brown } 6170ca725561SMark Brown 617155576cf1SMark Brown static void regulator_init_complete_work_function(struct work_struct *work) 6172609ca5f3SMark Brown { 6173609ca5f3SMark Brown /* 61743827b64dSJavier Martinez Canillas * Regulators may had failed to resolve their input supplies 61753827b64dSJavier Martinez Canillas * when were registered, either because the input supply was 61763827b64dSJavier Martinez Canillas * not registered yet or because its parent device was not 61773827b64dSJavier Martinez Canillas * bound yet. So attempt to resolve the input supplies for 61783827b64dSJavier Martinez Canillas * pending regulators before trying to disable unused ones. 61793827b64dSJavier Martinez Canillas */ 61803827b64dSJavier Martinez Canillas class_for_each_device(®ulator_class, NULL, NULL, 61813827b64dSJavier Martinez Canillas regulator_register_resolve_supply); 61823827b64dSJavier Martinez Canillas 6183609ca5f3SMark Brown /* If we have a full configuration then disable any regulators 6184609ca5f3SMark Brown * we have permission to change the status for and which are 6185609ca5f3SMark Brown * not in use or always_on. This is effectively the default 6186609ca5f3SMark Brown * for DT and ACPI as they have full constraints. 6187609ca5f3SMark Brown */ 6188609ca5f3SMark Brown class_for_each_device(®ulator_class, NULL, NULL, 6189609ca5f3SMark Brown regulator_late_cleanup); 619055576cf1SMark Brown } 619155576cf1SMark Brown 619255576cf1SMark Brown static DECLARE_DELAYED_WORK(regulator_init_complete_work, 619355576cf1SMark Brown regulator_init_complete_work_function); 619455576cf1SMark Brown 619555576cf1SMark Brown static int __init regulator_init_complete(void) 619655576cf1SMark Brown { 619755576cf1SMark Brown /* 619855576cf1SMark Brown * Since DT doesn't provide an idiomatic mechanism for 619955576cf1SMark Brown * enabling full constraints and since it's much more natural 620055576cf1SMark Brown * with DT to provide them just assume that a DT enabled 620155576cf1SMark Brown * system has full constraints. 620255576cf1SMark Brown */ 620355576cf1SMark Brown if (of_have_populated_dt()) 620455576cf1SMark Brown has_full_constraints = true; 620555576cf1SMark Brown 620655576cf1SMark Brown /* 62072a15483bSJohn Stultz * We punt completion for an arbitrary amount of time since 62082a15483bSJohn Stultz * systems like distros will load many drivers from userspace 62092a15483bSJohn Stultz * so consumers might not always be ready yet, this is 62102a15483bSJohn Stultz * particularly an issue with laptops where this might bounce 62112a15483bSJohn Stultz * the display off then on. Ideally we'd get a notification 62122a15483bSJohn Stultz * from userspace when this happens but we don't so just wait 62132a15483bSJohn Stultz * a bit and hope we waited long enough. It'd be better if 62142a15483bSJohn Stultz * we'd only do this on systems that need it, and a kernel 62152a15483bSJohn Stultz * command line option might be useful. 621655576cf1SMark Brown */ 62172a15483bSJohn Stultz schedule_delayed_work(®ulator_init_complete_work, 62182a15483bSJohn Stultz msecs_to_jiffies(30000)); 6219ca725561SMark Brown 6220ca725561SMark Brown return 0; 6221ca725561SMark Brown } 6222fd482a3eSSaravana Kannan late_initcall_sync(regulator_init_complete); 6223