regulator: Add regulator_get_exclusive() API

Some consumers require complete control of the regulator and can't
tolerate sharing it with other consumers, most commonly because they need
to have the regulator actually disabled so can't have other consumers
forcing it on. This new regulator_get_exclusive() API call allows these
consumers to explicitly request this, documenting the assumptions that
they are making.

In order to simplify coding of such consumers the use count for regulators
they request is forced to match the enabled state of the regulator when
it is requested. This is not possible for consumers which can share
regulators due to the need to keep track of the ownership of use counts.

A new API call is used rather than an additional argument to the existing
regulator_get() in order to avoid merge headaches with driver code in
other trees.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
This commit is contained in:
Mark Brown 2009-07-21 16:00:23 +01:00 коммит произвёл Liam Girdwood
Родитель c1b60873ca
Коммит 5ffbd136e6
3 изменённых файлов: 78 добавлений и 14 удалений

Просмотреть файл

@ -1025,25 +1025,15 @@ overflow_err:
return NULL; return NULL;
} }
/** /* Internal regulator request function */
* regulator_get - lookup and obtain a reference to a regulator. static struct regulator *_regulator_get(struct device *dev, const char *id,
* @dev: device for regulator "consumer" int exclusive)
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct regulator *regulator_get(struct device *dev, const char *id)
{ {
struct regulator_dev *rdev; struct regulator_dev *rdev;
struct regulator_map *map; struct regulator_map *map;
struct regulator *regulator = ERR_PTR(-ENODEV); struct regulator *regulator = ERR_PTR(-ENODEV);
const char *devname = NULL; const char *devname = NULL;
int ret;
if (id == NULL) { if (id == NULL) {
printk(KERN_ERR "regulator: get() with no identifier\n"); printk(KERN_ERR "regulator: get() with no identifier\n");
@ -1070,6 +1060,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
return regulator; return regulator;
found: found:
if (rdev->exclusive) {
regulator = ERR_PTR(-EPERM);
goto out;
}
if (exclusive && rdev->open_count) {
regulator = ERR_PTR(-EBUSY);
goto out;
}
if (!try_module_get(rdev->owner)) if (!try_module_get(rdev->owner))
goto out; goto out;
@ -1079,12 +1079,69 @@ found:
module_put(rdev->owner); module_put(rdev->owner);
} }
rdev->open_count++;
if (exclusive) {
rdev->exclusive = 1;
ret = _regulator_is_enabled(rdev);
if (ret > 0)
rdev->use_count = 1;
else
rdev->use_count = 0;
}
out: out:
mutex_unlock(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
return regulator; return regulator;
} }
/**
* regulator_get - lookup and obtain a reference to a regulator.
* @dev: device for regulator "consumer"
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct regulator *regulator_get(struct device *dev, const char *id)
{
return _regulator_get(dev, id, 0);
}
EXPORT_SYMBOL_GPL(regulator_get); EXPORT_SYMBOL_GPL(regulator_get);
/**
* regulator_get_exclusive - obtain exclusive access to a regulator.
* @dev: device for regulator "consumer"
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno. Other consumers will be
* unable to obtain this reference is held and the use count for the
* regulator will be initialised to reflect the current state of the
* regulator.
*
* This is intended for use by consumers which cannot tolerate shared
* use of the regulator such as those which need to force the
* regulator off for correct operation of the hardware they are
* controlling.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
{
return _regulator_get(dev, id, 1);
}
EXPORT_SYMBOL_GPL(regulator_get_exclusive);
/** /**
* regulator_put - "free" the regulator source * regulator_put - "free" the regulator source
* @regulator: regulator source * @regulator: regulator source
@ -1113,6 +1170,9 @@ void regulator_put(struct regulator *regulator)
list_del(&regulator->list); list_del(&regulator->list);
kfree(regulator); kfree(regulator);
rdev->open_count--;
rdev->exclusive = 0;
module_put(rdev->owner); module_put(rdev->owner);
mutex_unlock(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
} }

Просмотреть файл

@ -125,6 +125,8 @@ struct regulator_bulk_data {
/* regulator get and put */ /* regulator get and put */
struct regulator *__must_check regulator_get(struct device *dev, struct regulator *__must_check regulator_get(struct device *dev,
const char *id); const char *id);
struct regulator *__must_check regulator_get_exclusive(struct device *dev,
const char *id);
void regulator_put(struct regulator *regulator); void regulator_put(struct regulator *regulator);
/* regulator output control and status */ /* regulator output control and status */

Просмотреть файл

@ -162,6 +162,8 @@ struct regulator_desc {
struct regulator_dev { struct regulator_dev {
struct regulator_desc *desc; struct regulator_desc *desc;
int use_count; int use_count;
int open_count;
int exclusive;
/* lists we belong to */ /* lists we belong to */
struct list_head list; /* list of all regulators */ struct list_head list; /* list of all regulators */