6909 lines · 177.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later//// core.c  --  Voltage/Current Regulator framework.//// Copyright 2007, 2008 Wolfson Microelectronics PLC.// Copyright 2008 SlimLogic Ltd.//// Author: Liam Girdwood <lrg@slimlogic.co.uk> #include <linux/kernel.h>#include <linux/init.h>#include <linux/debugfs.h>#include <linux/device.h>#include <linux/slab.h>#include <linux/async.h>#include <linux/err.h>#include <linux/mutex.h>#include <linux/suspend.h>#include <linux/delay.h>#include <linux/gpio/consumer.h>#include <linux/of.h>#include <linux/reboot.h>#include <linux/regmap.h>#include <linux/regulator/of_regulator.h>#include <linux/regulator/consumer.h>#include <linux/regulator/coupler.h>#include <linux/regulator/driver.h>#include <linux/regulator/machine.h>#include <linux/module.h>#include <linux/workqueue.h> #define CREATE_TRACE_POINTS#include <trace/events/regulator.h> #include "dummy.h"#include "internal.h"#include "regnl.h" static DEFINE_WW_CLASS(regulator_ww_class);static DEFINE_MUTEX(regulator_nesting_mutex);static DEFINE_MUTEX(regulator_list_mutex);static LIST_HEAD(regulator_map_list);static LIST_HEAD(regulator_ena_gpio_list);static LIST_HEAD(regulator_supply_alias_list);static LIST_HEAD(regulator_coupler_list);static bool has_full_constraints; static const struct bus_type regulator_bus; static struct dentry *debugfs_root; /* * struct regulator_map * * Used to provide symbolic supply names to devices. */struct regulator_map {	struct list_head list;	const char *dev_name;   /* The dev_name() for the consumer */	const char *supply;	struct regulator_dev *regulator;}; /* * struct regulator_enable_gpio * * Management for shared enable GPIO pin */struct regulator_enable_gpio {	struct list_head list;	struct gpio_desc *gpiod;	u32 enable_count;	/* a number of enabled shared GPIO */	u32 request_count;	/* a number of requested shared GPIO */}; /* * struct regulator_supply_alias * * Used to map lookups for a supply onto an alternative device. */struct regulator_supply_alias {	struct list_head list;	struct device *src_dev;	const char *src_supply;	struct device *alias_dev;	const char *alias_supply;}; /* * Work item used to forward regulator events. * * @work: workqueue entry * @rdev: regulator device to notify (consumer receiving the forwarded event) * @event: event code to be forwarded */struct regulator_event_work {	struct work_struct work;	struct regulator_dev *rdev;	unsigned long event;}; static int _regulator_enable(struct regulator *regulator);static int _regulator_is_enabled(struct regulator_dev *rdev);static int _regulator_disable(struct regulator *regulator);static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags);static int _regulator_get_current_limit(struct regulator_dev *rdev);static unsigned int _regulator_get_mode(struct regulator_dev *rdev);static int _notifier_call_chain(struct regulator_dev *rdev,				  unsigned long event, void *data);static int _regulator_do_set_voltage(struct regulator_dev *rdev,				     int min_uV, int max_uV);static int regulator_balance_voltage(struct regulator_dev *rdev,				     suspend_state_t state);static struct regulator *create_regulator(struct regulator_dev *rdev,					  struct device *dev,					  const char *supply_name);static void destroy_regulator(struct regulator *regulator);static void _regulator_put(struct regulator *regulator); const char *rdev_get_name(struct regulator_dev *rdev){	if (rdev->constraints && rdev->constraints->name)		return rdev->constraints->name;	else if (rdev->desc->name)		return rdev->desc->name;	else		return "";}EXPORT_SYMBOL_GPL(rdev_get_name); static bool have_full_constraints(void){	return has_full_constraints || of_have_populated_dt();} static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops){	if (!rdev->constraints) {		rdev_err(rdev, "no constraints\n");		return false;	} 	if (rdev->constraints->valid_ops_mask & ops)		return true; 	return false;} /** * regulator_lock_nested - lock a single regulator * @rdev:		regulator source * @ww_ctx:		w/w mutex acquire context * * This function can be called many times by one task on * a single regulator and its mutex will be locked only * once. If a task, which is calling this function is other * than the one, which initially locked the mutex, it will * wait on mutex. * * Return: 0 on success or a negative error number on failure. */static inline int regulator_lock_nested(struct regulator_dev *rdev,					struct ww_acquire_ctx *ww_ctx){	bool lock = false;	int ret = 0; 	mutex_lock(&regulator_nesting_mutex); 	if (!ww_mutex_trylock(&rdev->mutex, ww_ctx)) {		if (rdev->mutex_owner == current)			rdev->ref_cnt++;		else			lock = true; 		if (lock) {			mutex_unlock(&regulator_nesting_mutex);			ret = ww_mutex_lock(&rdev->mutex, ww_ctx);			mutex_lock(&regulator_nesting_mutex);		}	} else {		lock = true;	} 	if (lock && ret != -EDEADLK) {		rdev->ref_cnt++;		rdev->mutex_owner = current;	} 	mutex_unlock(&regulator_nesting_mutex); 	return ret;} /** * regulator_lock - lock a single regulator * @rdev:		regulator source * * This function can be called many times by one task on * a single regulator and its mutex will be locked only * once. If a task, which is calling this function is other * than the one, which initially locked the mutex, it will * wait on mutex. */static void regulator_lock(struct regulator_dev *rdev){	regulator_lock_nested(rdev, NULL);} /** * regulator_unlock - unlock a single regulator * @rdev:		regulator_source * * This function unlocks the mutex when the * reference counter reaches 0. */static void regulator_unlock(struct regulator_dev *rdev){	mutex_lock(&regulator_nesting_mutex); 	if (--rdev->ref_cnt == 0) {		rdev->mutex_owner = NULL;		ww_mutex_unlock(&rdev->mutex);	} 	WARN_ON_ONCE(rdev->ref_cnt < 0); 	mutex_unlock(&regulator_nesting_mutex);} /** * regulator_lock_two - lock two regulators * @rdev1:		first regulator * @rdev2:		second regulator * @ww_ctx:		w/w mutex acquire context * * Locks both rdevs using the regulator_ww_class. */static void regulator_lock_two(struct regulator_dev *rdev1,			       struct regulator_dev *rdev2,			       struct ww_acquire_ctx *ww_ctx){	struct regulator_dev *held, *contended;	int ret; 	ww_acquire_init(ww_ctx, &regulator_ww_class); 	/* Try to just grab both of them */	ret = regulator_lock_nested(rdev1, ww_ctx);	WARN_ON(ret);	ret = regulator_lock_nested(rdev2, ww_ctx);	if (ret != -EDEADLK) {		WARN_ON(ret);		goto exit;	} 	held = rdev1;	contended = rdev2;	while (true) {		regulator_unlock(held); 		ww_mutex_lock_slow(&contended->mutex, ww_ctx);		contended->ref_cnt++;		contended->mutex_owner = current;		swap(held, contended);		ret = regulator_lock_nested(contended, ww_ctx); 		if (ret != -EDEADLK) {			WARN_ON(ret);			break;		}	} exit:	ww_acquire_done(ww_ctx);} /** * regulator_unlock_two - unlock two regulators * @rdev1:		first regulator * @rdev2:		second regulator * @ww_ctx:		w/w mutex acquire context * * The inverse of regulator_lock_two(). */ static void regulator_unlock_two(struct regulator_dev *rdev1,				 struct regulator_dev *rdev2,				 struct ww_acquire_ctx *ww_ctx){	regulator_unlock(rdev2);	regulator_unlock(rdev1);	ww_acquire_fini(ww_ctx);} static bool regulator_supply_is_couple(struct regulator_dev *rdev){	struct regulator_dev *c_rdev;	int i; 	for (i = 1; i < rdev->coupling_desc.n_coupled; i++) {		c_rdev = rdev->coupling_desc.coupled_rdevs[i]; 		if (rdev->supply->rdev == c_rdev)			return true;	} 	return false;} static void regulator_unlock_recursive(struct regulator_dev *rdev,				       unsigned int n_coupled){	struct regulator_dev *c_rdev, *supply_rdev;	int i, supply_n_coupled; 	for (i = n_coupled; i > 0; i--) {		c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1]; 		if (!c_rdev)			continue; 		if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {			supply_rdev = c_rdev->supply->rdev;			supply_n_coupled = supply_rdev->coupling_desc.n_coupled; 			regulator_unlock_recursive(supply_rdev,						   supply_n_coupled);		} 		regulator_unlock(c_rdev);	}} static int regulator_lock_recursive(struct regulator_dev *rdev,				    struct regulator_dev **new_contended_rdev,				    struct regulator_dev **old_contended_rdev,				    struct ww_acquire_ctx *ww_ctx){	struct regulator_dev *c_rdev;	int i, err; 	for (i = 0; i < rdev->coupling_desc.n_coupled; i++) {		c_rdev = rdev->coupling_desc.coupled_rdevs[i]; 		if (!c_rdev)			continue; 		if (c_rdev != *old_contended_rdev) {			err = regulator_lock_nested(c_rdev, ww_ctx);			if (err) {				if (err == -EDEADLK) {					*new_contended_rdev = c_rdev;					goto err_unlock;				} 				/* shouldn't happen */				WARN_ON_ONCE(err != -EALREADY);			}		} else {			*old_contended_rdev = NULL;		} 		if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {			err = regulator_lock_recursive(c_rdev->supply->rdev,						       new_contended_rdev,						       old_contended_rdev,						       ww_ctx);			if (err) {				regulator_unlock(c_rdev);				goto err_unlock;			}		}	} 	return 0; err_unlock:	regulator_unlock_recursive(rdev, i); 	return err;} /** * regulator_unlock_dependent - unlock regulator's suppliers and coupled *				regulators * @rdev:			regulator source * @ww_ctx:			w/w mutex acquire context * * Unlock all regulators related with rdev by coupling or supplying. */static void regulator_unlock_dependent(struct regulator_dev *rdev,				       struct ww_acquire_ctx *ww_ctx){	regulator_unlock_recursive(rdev, rdev->coupling_desc.n_coupled);	ww_acquire_fini(ww_ctx);} /** * regulator_lock_dependent - lock regulator's suppliers and coupled regulators * @rdev:			regulator source * @ww_ctx:			w/w mutex acquire context * * This function as a wrapper on regulator_lock_recursive(), which locks * all regulators related with rdev by coupling or supplying. */static void regulator_lock_dependent(struct regulator_dev *rdev,				     struct ww_acquire_ctx *ww_ctx){	struct regulator_dev *new_contended_rdev = NULL;	struct regulator_dev *old_contended_rdev = NULL;	int err; 	mutex_lock(&regulator_list_mutex); 	ww_acquire_init(ww_ctx, &regulator_ww_class); 	do {		if (new_contended_rdev) {			ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx);			old_contended_rdev = new_contended_rdev;			old_contended_rdev->ref_cnt++;			old_contended_rdev->mutex_owner = current;		} 		err = regulator_lock_recursive(rdev,					       &new_contended_rdev,					       &old_contended_rdev,					       ww_ctx); 		if (old_contended_rdev)			regulator_unlock(old_contended_rdev); 	} while (err == -EDEADLK); 	ww_acquire_done(ww_ctx); 	mutex_unlock(&regulator_list_mutex);} /* Platform voltage constraint check */int regulator_check_voltage(struct regulator_dev *rdev,			    int *min_uV, int *max_uV){	BUG_ON(*min_uV > *max_uV); 	if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {		rdev_err(rdev, "voltage operation not allowed\n");		return -EPERM;	} 	if (*max_uV > rdev->constraints->max_uV)		*max_uV = rdev->constraints->max_uV;	if (*min_uV < rdev->constraints->min_uV)		*min_uV = rdev->constraints->min_uV; 	if (*min_uV > *max_uV) {		rdev_err(rdev, "unsupportable voltage range: %d-%duV\n",			 *min_uV, *max_uV);		return -EINVAL;	} 	return 0;} /* return 0 if the state is valid */static int regulator_check_states(suspend_state_t state){	return (state > PM_SUSPEND_MAX || state == PM_SUSPEND_TO_IDLE);} /* Make sure we select a voltage that suits the needs of all * regulator consumers */int regulator_check_consumers(struct regulator_dev *rdev,			      int *min_uV, int *max_uV,			      suspend_state_t state){	struct regulator *regulator;	struct regulator_voltage *voltage; 	list_for_each_entry(regulator, &rdev->consumer_list, list) {		voltage = &regulator->voltage[state];		/*		 * Assume consumers that didn't say anything are OK		 * with anything in the constraint range.		 */		if (!voltage->min_uV && !voltage->max_uV)			continue; 		if (*max_uV > voltage->max_uV)			*max_uV = voltage->max_uV;		if (*min_uV < voltage->min_uV)			*min_uV = voltage->min_uV;	} 	if (*min_uV > *max_uV) {		rdev_err(rdev, "Restricting voltage, %u-%uuV\n",			*min_uV, *max_uV);		return -EINVAL;

Lines 1–500 of 6909.