162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * devres.c -- Voltage/Current Regulator framework devres implementation. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2013 Linaro Ltd 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/regmap.h> 1162306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1262306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "internal.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic void devm_regulator_release(struct device *dev, void *res) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci regulator_put(*(struct regulator **)res); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic struct regulator *_devm_regulator_get(struct device *dev, const char *id, 2362306a36Sopenharmony_ci int get_type) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct regulator **ptr, *regulator; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); 2862306a36Sopenharmony_ci if (!ptr) 2962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci regulator = _regulator_get(dev, id, get_type); 3262306a36Sopenharmony_ci if (!IS_ERR(regulator)) { 3362306a36Sopenharmony_ci *ptr = regulator; 3462306a36Sopenharmony_ci devres_add(dev, ptr); 3562306a36Sopenharmony_ci } else { 3662306a36Sopenharmony_ci devres_free(ptr); 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci return regulator; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/** 4362306a36Sopenharmony_ci * devm_regulator_get - Resource managed regulator_get() 4462306a36Sopenharmony_ci * @dev: device to supply 4562306a36Sopenharmony_ci * @id: supply name or regulator ID. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Managed regulator_get(). Regulators returned from this function are 4862306a36Sopenharmony_ci * automatically regulator_put() on driver detach. See regulator_get() for more 4962306a36Sopenharmony_ci * information. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistruct regulator *devm_regulator_get(struct device *dev, const char *id) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci return _devm_regulator_get(dev, id, NORMAL_GET); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_get); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/** 5862306a36Sopenharmony_ci * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive() 5962306a36Sopenharmony_ci * @dev: device to supply 6062306a36Sopenharmony_ci * @id: supply name or regulator ID. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * Managed regulator_get_exclusive(). Regulators returned from this function 6362306a36Sopenharmony_ci * are automatically regulator_put() on driver detach. See regulator_get() for 6462306a36Sopenharmony_ci * more information. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistruct regulator *devm_regulator_get_exclusive(struct device *dev, 6762306a36Sopenharmony_ci const char *id) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return _devm_regulator_get(dev, id, EXCLUSIVE_GET); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_get_exclusive); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void regulator_action_disable(void *d) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct regulator *r = (struct regulator *)d; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci regulator_disable(r); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int _devm_regulator_get_enable(struct device *dev, const char *id, 8162306a36Sopenharmony_ci int get_type) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct regulator *r; 8462306a36Sopenharmony_ci int ret; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci r = _devm_regulator_get(dev, id, get_type); 8762306a36Sopenharmony_ci if (IS_ERR(r)) 8862306a36Sopenharmony_ci return PTR_ERR(r); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ret = regulator_enable(r); 9162306a36Sopenharmony_ci if (!ret) 9262306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, ®ulator_action_disable, r); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (ret) 9562306a36Sopenharmony_ci devm_regulator_put(r); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return ret; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/** 10162306a36Sopenharmony_ci * devm_regulator_get_enable_optional - Resource managed regulator get and enable 10262306a36Sopenharmony_ci * @dev: device to supply 10362306a36Sopenharmony_ci * @id: supply name or regulator ID. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * Get and enable regulator for duration of the device life-time. 10662306a36Sopenharmony_ci * regulator_disable() and regulator_put() are automatically called on driver 10762306a36Sopenharmony_ci * detach. See regulator_get_optional() and regulator_enable() for more 10862306a36Sopenharmony_ci * information. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ciint devm_regulator_get_enable_optional(struct device *dev, const char *id) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci return _devm_regulator_get_enable(dev, id, OPTIONAL_GET); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_get_enable_optional); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/** 11762306a36Sopenharmony_ci * devm_regulator_get_enable - Resource managed regulator get and enable 11862306a36Sopenharmony_ci * @dev: device to supply 11962306a36Sopenharmony_ci * @id: supply name or regulator ID. 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Get and enable regulator for duration of the device life-time. 12262306a36Sopenharmony_ci * regulator_disable() and regulator_put() are automatically called on driver 12362306a36Sopenharmony_ci * detach. See regulator_get() and regulator_enable() for more 12462306a36Sopenharmony_ci * information. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ciint devm_regulator_get_enable(struct device *dev, const char *id) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci return _devm_regulator_get_enable(dev, id, NORMAL_GET); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_get_enable); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/** 13362306a36Sopenharmony_ci * devm_regulator_get_optional - Resource managed regulator_get_optional() 13462306a36Sopenharmony_ci * @dev: device to supply 13562306a36Sopenharmony_ci * @id: supply name or regulator ID. 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * Managed regulator_get_optional(). Regulators returned from this 13862306a36Sopenharmony_ci * function are automatically regulator_put() on driver detach. See 13962306a36Sopenharmony_ci * regulator_get_optional() for more information. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_cistruct regulator *devm_regulator_get_optional(struct device *dev, 14262306a36Sopenharmony_ci const char *id) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci return _devm_regulator_get(dev, id, OPTIONAL_GET); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_get_optional); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int devm_regulator_match(struct device *dev, void *res, void *data) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct regulator **r = res; 15162306a36Sopenharmony_ci if (!r || !*r) { 15262306a36Sopenharmony_ci WARN_ON(!r || !*r); 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci return *r == data; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/** 15962306a36Sopenharmony_ci * devm_regulator_put - Resource managed regulator_put() 16062306a36Sopenharmony_ci * @regulator: regulator to free 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * Deallocate a regulator allocated with devm_regulator_get(). Normally 16362306a36Sopenharmony_ci * this function will not need to be called and the resource management 16462306a36Sopenharmony_ci * code will ensure that the resource is freed. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_civoid devm_regulator_put(struct regulator *regulator) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci int rc; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci rc = devres_release(regulator->dev, devm_regulator_release, 17162306a36Sopenharmony_ci devm_regulator_match, regulator); 17262306a36Sopenharmony_ci if (rc != 0) 17362306a36Sopenharmony_ci WARN_ON(rc); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_put); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistruct regulator_bulk_devres { 17862306a36Sopenharmony_ci struct regulator_bulk_data *consumers; 17962306a36Sopenharmony_ci int num_consumers; 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void devm_regulator_bulk_release(struct device *dev, void *res) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct regulator_bulk_devres *devres = res; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci regulator_bulk_free(devres->num_consumers, devres->consumers); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int _devm_regulator_bulk_get(struct device *dev, int num_consumers, 19062306a36Sopenharmony_ci struct regulator_bulk_data *consumers, 19162306a36Sopenharmony_ci enum regulator_get_type get_type) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct regulator_bulk_devres *devres; 19462306a36Sopenharmony_ci int ret; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci devres = devres_alloc(devm_regulator_bulk_release, 19762306a36Sopenharmony_ci sizeof(*devres), GFP_KERNEL); 19862306a36Sopenharmony_ci if (!devres) 19962306a36Sopenharmony_ci return -ENOMEM; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci ret = _regulator_bulk_get(dev, num_consumers, consumers, get_type); 20262306a36Sopenharmony_ci if (!ret) { 20362306a36Sopenharmony_ci devres->consumers = consumers; 20462306a36Sopenharmony_ci devres->num_consumers = num_consumers; 20562306a36Sopenharmony_ci devres_add(dev, devres); 20662306a36Sopenharmony_ci } else { 20762306a36Sopenharmony_ci devres_free(devres); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return ret; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/** 21462306a36Sopenharmony_ci * devm_regulator_bulk_get - managed get multiple regulator consumers 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * @dev: device to supply 21762306a36Sopenharmony_ci * @num_consumers: number of consumers to register 21862306a36Sopenharmony_ci * @consumers: configuration of consumers; clients are stored here. 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * @return 0 on success, an errno on failure. 22162306a36Sopenharmony_ci * 22262306a36Sopenharmony_ci * This helper function allows drivers to get several regulator 22362306a36Sopenharmony_ci * consumers in one operation with management, the regulators will 22462306a36Sopenharmony_ci * automatically be freed when the device is unbound. If any of the 22562306a36Sopenharmony_ci * regulators cannot be acquired then any regulators that were 22662306a36Sopenharmony_ci * allocated will be freed before returning to the caller. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ciint devm_regulator_bulk_get(struct device *dev, int num_consumers, 22962306a36Sopenharmony_ci struct regulator_bulk_data *consumers) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci return _devm_regulator_bulk_get(dev, num_consumers, consumers, NORMAL_GET); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_bulk_get); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/** 23662306a36Sopenharmony_ci * devm_regulator_bulk_get_exclusive - managed exclusive get of multiple 23762306a36Sopenharmony_ci * regulator consumers 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * @dev: device to supply 24062306a36Sopenharmony_ci * @num_consumers: number of consumers to register 24162306a36Sopenharmony_ci * @consumers: configuration of consumers; clients are stored here. 24262306a36Sopenharmony_ci * 24362306a36Sopenharmony_ci * @return 0 on success, an errno on failure. 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * This helper function allows drivers to exclusively get several 24662306a36Sopenharmony_ci * regulator consumers in one operation with management, the regulators 24762306a36Sopenharmony_ci * will automatically be freed when the device is unbound. If any of 24862306a36Sopenharmony_ci * the regulators cannot be acquired then any regulators that were 24962306a36Sopenharmony_ci * allocated will be freed before returning to the caller. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ciint devm_regulator_bulk_get_exclusive(struct device *dev, int num_consumers, 25262306a36Sopenharmony_ci struct regulator_bulk_data *consumers) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci return _devm_regulator_bulk_get(dev, num_consumers, consumers, EXCLUSIVE_GET); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_bulk_get_exclusive); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/** 25962306a36Sopenharmony_ci * devm_regulator_bulk_get_const - devm_regulator_bulk_get() w/ const data 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * @dev: device to supply 26262306a36Sopenharmony_ci * @num_consumers: number of consumers to register 26362306a36Sopenharmony_ci * @in_consumers: const configuration of consumers 26462306a36Sopenharmony_ci * @out_consumers: in_consumers is copied here and this is passed to 26562306a36Sopenharmony_ci * devm_regulator_bulk_get(). 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * This is a convenience function to allow bulk regulator configuration 26862306a36Sopenharmony_ci * to be stored "static const" in files. 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * Return: 0 on success, an errno on failure. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ciint devm_regulator_bulk_get_const(struct device *dev, int num_consumers, 27362306a36Sopenharmony_ci const struct regulator_bulk_data *in_consumers, 27462306a36Sopenharmony_ci struct regulator_bulk_data **out_consumers) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci *out_consumers = devm_kmemdup(dev, in_consumers, 27762306a36Sopenharmony_ci num_consumers * sizeof(*in_consumers), 27862306a36Sopenharmony_ci GFP_KERNEL); 27962306a36Sopenharmony_ci if (*out_consumers == NULL) 28062306a36Sopenharmony_ci return -ENOMEM; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return devm_regulator_bulk_get(dev, num_consumers, *out_consumers); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_bulk_get_const); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int devm_regulator_bulk_match(struct device *dev, void *res, 28762306a36Sopenharmony_ci void *data) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct regulator_bulk_devres *match = res; 29062306a36Sopenharmony_ci struct regulator_bulk_data *target = data; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * We check the put uses same consumer list as the get did. 29462306a36Sopenharmony_ci * We _could_ scan all entries in consumer array and check the 29562306a36Sopenharmony_ci * regulators match but ATM I don't see the need. We can change this 29662306a36Sopenharmony_ci * later if needed. 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci return match->consumers == target; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/** 30262306a36Sopenharmony_ci * devm_regulator_bulk_put - Resource managed regulator_bulk_put() 30362306a36Sopenharmony_ci * @consumers: consumers to free 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * Deallocate regulators allocated with devm_regulator_bulk_get(). Normally 30662306a36Sopenharmony_ci * this function will not need to be called and the resource management 30762306a36Sopenharmony_ci * code will ensure that the resource is freed. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_civoid devm_regulator_bulk_put(struct regulator_bulk_data *consumers) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci int rc; 31262306a36Sopenharmony_ci struct regulator *regulator = consumers[0].consumer; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci rc = devres_release(regulator->dev, devm_regulator_bulk_release, 31562306a36Sopenharmony_ci devm_regulator_bulk_match, consumers); 31662306a36Sopenharmony_ci if (rc != 0) 31762306a36Sopenharmony_ci WARN_ON(rc); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_bulk_put); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void devm_regulator_bulk_disable(void *res) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct regulator_bulk_devres *devres = res; 32462306a36Sopenharmony_ci int i; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci for (i = 0; i < devres->num_consumers; i++) 32762306a36Sopenharmony_ci regulator_disable(devres->consumers[i].consumer); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci/** 33162306a36Sopenharmony_ci * devm_regulator_bulk_get_enable - managed get'n enable multiple regulators 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci * @dev: device to supply 33462306a36Sopenharmony_ci * @num_consumers: number of consumers to register 33562306a36Sopenharmony_ci * @id: list of supply names or regulator IDs 33662306a36Sopenharmony_ci * 33762306a36Sopenharmony_ci * @return 0 on success, an errno on failure. 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * This helper function allows drivers to get several regulator 34062306a36Sopenharmony_ci * consumers in one operation with management, the regulators will 34162306a36Sopenharmony_ci * automatically be freed when the device is unbound. If any of the 34262306a36Sopenharmony_ci * regulators cannot be acquired then any regulators that were 34362306a36Sopenharmony_ci * allocated will be freed before returning to the caller. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ciint devm_regulator_bulk_get_enable(struct device *dev, int num_consumers, 34662306a36Sopenharmony_ci const char * const *id) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct regulator_bulk_devres *devres; 34962306a36Sopenharmony_ci struct regulator_bulk_data *consumers; 35062306a36Sopenharmony_ci int i, ret; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci devres = devm_kmalloc(dev, sizeof(*devres), GFP_KERNEL); 35362306a36Sopenharmony_ci if (!devres) 35462306a36Sopenharmony_ci return -ENOMEM; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci devres->consumers = devm_kcalloc(dev, num_consumers, sizeof(*consumers), 35762306a36Sopenharmony_ci GFP_KERNEL); 35862306a36Sopenharmony_ci consumers = devres->consumers; 35962306a36Sopenharmony_ci if (!consumers) 36062306a36Sopenharmony_ci return -ENOMEM; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci devres->num_consumers = num_consumers; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) 36562306a36Sopenharmony_ci consumers[i].supply = id[i]; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci ret = devm_regulator_bulk_get(dev, num_consumers, consumers); 36862306a36Sopenharmony_ci if (ret) 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 37262306a36Sopenharmony_ci ret = regulator_enable(consumers[i].consumer); 37362306a36Sopenharmony_ci if (ret) 37462306a36Sopenharmony_ci goto unwind; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci ret = devm_add_action(dev, devm_regulator_bulk_disable, devres); 37862306a36Sopenharmony_ci if (!ret) 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ciunwind: 38262306a36Sopenharmony_ci while (--i >= 0) 38362306a36Sopenharmony_ci regulator_disable(consumers[i].consumer); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci devm_regulator_bulk_put(consumers); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_bulk_get_enable); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic void devm_rdev_release(struct device *dev, void *res) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci regulator_unregister(*(struct regulator_dev **)res); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/** 39762306a36Sopenharmony_ci * devm_regulator_register - Resource managed regulator_register() 39862306a36Sopenharmony_ci * @dev: device to supply 39962306a36Sopenharmony_ci * @regulator_desc: regulator to register 40062306a36Sopenharmony_ci * @config: runtime configuration for regulator 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * Called by regulator drivers to register a regulator. Returns a 40362306a36Sopenharmony_ci * valid pointer to struct regulator_dev on success or an ERR_PTR() on 40462306a36Sopenharmony_ci * error. The regulator will automatically be released when the device 40562306a36Sopenharmony_ci * is unbound. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_cistruct regulator_dev *devm_regulator_register(struct device *dev, 40862306a36Sopenharmony_ci const struct regulator_desc *regulator_desc, 40962306a36Sopenharmony_ci const struct regulator_config *config) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct regulator_dev **ptr, *rdev; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ptr = devres_alloc(devm_rdev_release, sizeof(*ptr), 41462306a36Sopenharmony_ci GFP_KERNEL); 41562306a36Sopenharmony_ci if (!ptr) 41662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci rdev = regulator_register(dev, regulator_desc, config); 41962306a36Sopenharmony_ci if (!IS_ERR(rdev)) { 42062306a36Sopenharmony_ci *ptr = rdev; 42162306a36Sopenharmony_ci devres_add(dev, ptr); 42262306a36Sopenharmony_ci } else { 42362306a36Sopenharmony_ci devres_free(ptr); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return rdev; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_register); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistruct regulator_supply_alias_match { 43162306a36Sopenharmony_ci struct device *dev; 43262306a36Sopenharmony_ci const char *id; 43362306a36Sopenharmony_ci}; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic int devm_regulator_match_supply_alias(struct device *dev, void *res, 43662306a36Sopenharmony_ci void *data) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct regulator_supply_alias_match *match = res; 43962306a36Sopenharmony_ci struct regulator_supply_alias_match *target = data; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return match->dev == target->dev && strcmp(match->id, target->id) == 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic void devm_regulator_destroy_supply_alias(struct device *dev, void *res) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct regulator_supply_alias_match *match = res; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci regulator_unregister_supply_alias(match->dev, match->id); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci/** 45262306a36Sopenharmony_ci * devm_regulator_register_supply_alias - Resource managed 45362306a36Sopenharmony_ci * regulator_register_supply_alias() 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * @dev: device to supply 45662306a36Sopenharmony_ci * @id: supply name or regulator ID 45762306a36Sopenharmony_ci * @alias_dev: device that should be used to lookup the supply 45862306a36Sopenharmony_ci * @alias_id: supply name or regulator ID that should be used to lookup the 45962306a36Sopenharmony_ci * supply 46062306a36Sopenharmony_ci * 46162306a36Sopenharmony_ci * The supply alias will automatically be unregistered when the source 46262306a36Sopenharmony_ci * device is unbound. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ciint devm_regulator_register_supply_alias(struct device *dev, const char *id, 46562306a36Sopenharmony_ci struct device *alias_dev, 46662306a36Sopenharmony_ci const char *alias_id) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct regulator_supply_alias_match *match; 46962306a36Sopenharmony_ci int ret; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci match = devres_alloc(devm_regulator_destroy_supply_alias, 47262306a36Sopenharmony_ci sizeof(struct regulator_supply_alias_match), 47362306a36Sopenharmony_ci GFP_KERNEL); 47462306a36Sopenharmony_ci if (!match) 47562306a36Sopenharmony_ci return -ENOMEM; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci match->dev = dev; 47862306a36Sopenharmony_ci match->id = id; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci ret = regulator_register_supply_alias(dev, id, alias_dev, alias_id); 48162306a36Sopenharmony_ci if (ret < 0) { 48262306a36Sopenharmony_ci devres_free(match); 48362306a36Sopenharmony_ci return ret; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci devres_add(dev, match); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_register_supply_alias); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic void devm_regulator_unregister_supply_alias(struct device *dev, 49362306a36Sopenharmony_ci const char *id) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct regulator_supply_alias_match match; 49662306a36Sopenharmony_ci int rc; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci match.dev = dev; 49962306a36Sopenharmony_ci match.id = id; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci rc = devres_release(dev, devm_regulator_destroy_supply_alias, 50262306a36Sopenharmony_ci devm_regulator_match_supply_alias, &match); 50362306a36Sopenharmony_ci if (rc != 0) 50462306a36Sopenharmony_ci WARN_ON(rc); 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci/** 50862306a36Sopenharmony_ci * devm_regulator_bulk_register_supply_alias - Managed register 50962306a36Sopenharmony_ci * multiple aliases 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * @dev: device to supply 51262306a36Sopenharmony_ci * @id: list of supply names or regulator IDs 51362306a36Sopenharmony_ci * @alias_dev: device that should be used to lookup the supply 51462306a36Sopenharmony_ci * @alias_id: list of supply names or regulator IDs that should be used to 51562306a36Sopenharmony_ci * lookup the supply 51662306a36Sopenharmony_ci * @num_id: number of aliases to register 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * @return 0 on success, an errno on failure. 51962306a36Sopenharmony_ci * 52062306a36Sopenharmony_ci * This helper function allows drivers to register several supply 52162306a36Sopenharmony_ci * aliases in one operation, the aliases will be automatically 52262306a36Sopenharmony_ci * unregisters when the source device is unbound. If any of the 52362306a36Sopenharmony_ci * aliases cannot be registered any aliases that were registered 52462306a36Sopenharmony_ci * will be removed before returning to the caller. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ciint devm_regulator_bulk_register_supply_alias(struct device *dev, 52762306a36Sopenharmony_ci const char *const *id, 52862306a36Sopenharmony_ci struct device *alias_dev, 52962306a36Sopenharmony_ci const char *const *alias_id, 53062306a36Sopenharmony_ci int num_id) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci int i; 53362306a36Sopenharmony_ci int ret; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci for (i = 0; i < num_id; ++i) { 53662306a36Sopenharmony_ci ret = devm_regulator_register_supply_alias(dev, id[i], 53762306a36Sopenharmony_ci alias_dev, 53862306a36Sopenharmony_ci alias_id[i]); 53962306a36Sopenharmony_ci if (ret < 0) 54062306a36Sopenharmony_ci goto err; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci return 0; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cierr: 54662306a36Sopenharmony_ci dev_err(dev, 54762306a36Sopenharmony_ci "Failed to create supply alias %s,%s -> %s,%s\n", 54862306a36Sopenharmony_ci id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci while (--i >= 0) 55162306a36Sopenharmony_ci devm_regulator_unregister_supply_alias(dev, id[i]); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci return ret; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_bulk_register_supply_alias); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistruct regulator_notifier_match { 55862306a36Sopenharmony_ci struct regulator *regulator; 55962306a36Sopenharmony_ci struct notifier_block *nb; 56062306a36Sopenharmony_ci}; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic int devm_regulator_match_notifier(struct device *dev, void *res, 56362306a36Sopenharmony_ci void *data) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct regulator_notifier_match *match = res; 56662306a36Sopenharmony_ci struct regulator_notifier_match *target = data; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return match->regulator == target->regulator && match->nb == target->nb; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic void devm_regulator_destroy_notifier(struct device *dev, void *res) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct regulator_notifier_match *match = res; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci regulator_unregister_notifier(match->regulator, match->nb); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/** 57962306a36Sopenharmony_ci * devm_regulator_register_notifier - Resource managed 58062306a36Sopenharmony_ci * regulator_register_notifier 58162306a36Sopenharmony_ci * 58262306a36Sopenharmony_ci * @regulator: regulator source 58362306a36Sopenharmony_ci * @nb: notifier block 58462306a36Sopenharmony_ci * 58562306a36Sopenharmony_ci * The notifier will be registers under the consumer device and be 58662306a36Sopenharmony_ci * automatically be unregistered when the source device is unbound. 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ciint devm_regulator_register_notifier(struct regulator *regulator, 58962306a36Sopenharmony_ci struct notifier_block *nb) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci struct regulator_notifier_match *match; 59262306a36Sopenharmony_ci int ret; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci match = devres_alloc(devm_regulator_destroy_notifier, 59562306a36Sopenharmony_ci sizeof(struct regulator_notifier_match), 59662306a36Sopenharmony_ci GFP_KERNEL); 59762306a36Sopenharmony_ci if (!match) 59862306a36Sopenharmony_ci return -ENOMEM; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci match->regulator = regulator; 60162306a36Sopenharmony_ci match->nb = nb; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci ret = regulator_register_notifier(regulator, nb); 60462306a36Sopenharmony_ci if (ret < 0) { 60562306a36Sopenharmony_ci devres_free(match); 60662306a36Sopenharmony_ci return ret; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci devres_add(regulator->dev, match); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return 0; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_register_notifier); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/** 61662306a36Sopenharmony_ci * devm_regulator_unregister_notifier - Resource managed 61762306a36Sopenharmony_ci * regulator_unregister_notifier() 61862306a36Sopenharmony_ci * 61962306a36Sopenharmony_ci * @regulator: regulator source 62062306a36Sopenharmony_ci * @nb: notifier block 62162306a36Sopenharmony_ci * 62262306a36Sopenharmony_ci * Unregister a notifier registered with devm_regulator_register_notifier(). 62362306a36Sopenharmony_ci * Normally this function will not need to be called and the resource 62462306a36Sopenharmony_ci * management code will ensure that the resource is freed. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_civoid devm_regulator_unregister_notifier(struct regulator *regulator, 62762306a36Sopenharmony_ci struct notifier_block *nb) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct regulator_notifier_match match; 63062306a36Sopenharmony_ci int rc; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci match.regulator = regulator; 63362306a36Sopenharmony_ci match.nb = nb; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci rc = devres_release(regulator->dev, devm_regulator_destroy_notifier, 63662306a36Sopenharmony_ci devm_regulator_match_notifier, &match); 63762306a36Sopenharmony_ci if (rc != 0) 63862306a36Sopenharmony_ci WARN_ON(rc); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic void regulator_irq_helper_drop(void *res) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci regulator_irq_helper_cancel(&res); 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/** 64862306a36Sopenharmony_ci * devm_regulator_irq_helper - resource managed registration of IRQ based 64962306a36Sopenharmony_ci * regulator event/error notifier 65062306a36Sopenharmony_ci * 65162306a36Sopenharmony_ci * @dev: device to which lifetime the helper's lifetime is 65262306a36Sopenharmony_ci * bound. 65362306a36Sopenharmony_ci * @d: IRQ helper descriptor. 65462306a36Sopenharmony_ci * @irq: IRQ used to inform events/errors to be notified. 65562306a36Sopenharmony_ci * @irq_flags: Extra IRQ flags to be OR'ed with the default 65662306a36Sopenharmony_ci * IRQF_ONESHOT when requesting the (threaded) irq. 65762306a36Sopenharmony_ci * @common_errs: Errors which can be flagged by this IRQ for all rdevs. 65862306a36Sopenharmony_ci * When IRQ is re-enabled these errors will be cleared 65962306a36Sopenharmony_ci * from all associated regulators 66062306a36Sopenharmony_ci * @per_rdev_errs: Optional error flag array describing errors specific 66162306a36Sopenharmony_ci * for only some of the regulators. These errors will be 66262306a36Sopenharmony_ci * or'ed with common errors. If this is given the array 66362306a36Sopenharmony_ci * should contain rdev_amount flags. Can be set to NULL 66462306a36Sopenharmony_ci * if there is no regulator specific error flags for this 66562306a36Sopenharmony_ci * IRQ. 66662306a36Sopenharmony_ci * @rdev: Array of pointers to regulators associated with this 66762306a36Sopenharmony_ci * IRQ. 66862306a36Sopenharmony_ci * @rdev_amount: Amount of regulators associated with this IRQ. 66962306a36Sopenharmony_ci * 67062306a36Sopenharmony_ci * Return: handle to irq_helper or an ERR_PTR() encoded error code. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_civoid *devm_regulator_irq_helper(struct device *dev, 67362306a36Sopenharmony_ci const struct regulator_irq_desc *d, int irq, 67462306a36Sopenharmony_ci int irq_flags, int common_errs, 67562306a36Sopenharmony_ci int *per_rdev_errs, 67662306a36Sopenharmony_ci struct regulator_dev **rdev, int rdev_amount) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci void *ptr; 67962306a36Sopenharmony_ci int ret; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci ptr = regulator_irq_helper(dev, d, irq, irq_flags, common_errs, 68262306a36Sopenharmony_ci per_rdev_errs, rdev, rdev_amount); 68362306a36Sopenharmony_ci if (IS_ERR(ptr)) 68462306a36Sopenharmony_ci return ptr; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, regulator_irq_helper_drop, ptr); 68762306a36Sopenharmony_ci if (ret) 68862306a36Sopenharmony_ci return ERR_PTR(ret); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci return ptr; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_regulator_irq_helper); 693