pinctrl: implement devm_pinctrl_get()/put()
These functions allow the driver core to automatically clean up any allocations made by drivers, thus leading to simplified drivers. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
2aeefe0233
commit
6d4ca1fb46
@ -276,3 +276,7 @@ REGULATOR
|
|||||||
devm_regulator_get()
|
devm_regulator_get()
|
||||||
devm_regulator_put()
|
devm_regulator_put()
|
||||||
devm_regulator_bulk_get()
|
devm_regulator_bulk_get()
|
||||||
|
|
||||||
|
PINCTRL
|
||||||
|
devm_pinctrl_get()
|
||||||
|
devm_pinctrl_put()
|
||||||
|
@ -945,13 +945,13 @@ case), we define a mapping like this:
|
|||||||
The result of grabbing this mapping from the device with something like
|
The result of grabbing this mapping from the device with something like
|
||||||
this (see next paragraph):
|
this (see next paragraph):
|
||||||
|
|
||||||
p = pinctrl_get(dev);
|
p = devm_pinctrl_get(dev);
|
||||||
s = pinctrl_lookup_state(p, "8bit");
|
s = pinctrl_lookup_state(p, "8bit");
|
||||||
ret = pinctrl_select_state(p, s);
|
ret = pinctrl_select_state(p, s);
|
||||||
|
|
||||||
or more simply:
|
or more simply:
|
||||||
|
|
||||||
p = pinctrl_get_select(dev, "8bit");
|
p = devm_pinctrl_get_select(dev, "8bit");
|
||||||
|
|
||||||
Will be that you activate all the three bottom records in the mapping at
|
Will be that you activate all the three bottom records in the mapping at
|
||||||
once. Since they share the same name, pin controller device, function and
|
once. Since they share the same name, pin controller device, function and
|
||||||
@ -985,7 +985,7 @@ foo_probe()
|
|||||||
/* Allocate a state holder named "foo" etc */
|
/* Allocate a state holder named "foo" etc */
|
||||||
struct foo_state *foo = ...;
|
struct foo_state *foo = ...;
|
||||||
|
|
||||||
foo->p = pinctrl_get(&device);
|
foo->p = devm_pinctrl_get(&device);
|
||||||
if (IS_ERR(foo->p)) {
|
if (IS_ERR(foo->p)) {
|
||||||
/* FIXME: clean up "foo" here */
|
/* FIXME: clean up "foo" here */
|
||||||
return PTR_ERR(foo->p);
|
return PTR_ERR(foo->p);
|
||||||
@ -993,24 +993,17 @@ foo_probe()
|
|||||||
|
|
||||||
foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
|
foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
|
||||||
if (IS_ERR(foo->s)) {
|
if (IS_ERR(foo->s)) {
|
||||||
pinctrl_put(foo->p);
|
|
||||||
/* FIXME: clean up "foo" here */
|
/* FIXME: clean up "foo" here */
|
||||||
return PTR_ERR(s);
|
return PTR_ERR(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = pinctrl_select_state(foo->s);
|
ret = pinctrl_select_state(foo->s);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pinctrl_put(foo->p);
|
|
||||||
/* FIXME: clean up "foo" here */
|
/* FIXME: clean up "foo" here */
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foo_remove()
|
|
||||||
{
|
|
||||||
pinctrl_put(state->p);
|
|
||||||
}
|
|
||||||
|
|
||||||
This get/lookup/select/put sequence can just as well be handled by bus drivers
|
This get/lookup/select/put sequence can just as well be handled by bus drivers
|
||||||
if you don't want each and every driver to handle it and you know the
|
if you don't want each and every driver to handle it and you know the
|
||||||
arrangement on your bus.
|
arrangement on your bus.
|
||||||
@ -1022,6 +1015,11 @@ The semantics of the pinctrl APIs are:
|
|||||||
kernel memory to hold the pinmux state. All mapping table parsing or similar
|
kernel memory to hold the pinmux state. All mapping table parsing or similar
|
||||||
slow operations take place within this API.
|
slow operations take place within this API.
|
||||||
|
|
||||||
|
- devm_pinctrl_get() is a variant of pinctrl_get() that causes pinctrl_put()
|
||||||
|
to be called automatically on the retrieved pointer when the associated
|
||||||
|
device is removed. It is recommended to use this function over plain
|
||||||
|
pinctrl_get().
|
||||||
|
|
||||||
- pinctrl_lookup_state() is called in process context to obtain a handle to a
|
- pinctrl_lookup_state() is called in process context to obtain a handle to a
|
||||||
specific state for a the client device. This operation may be slow too.
|
specific state for a the client device. This operation may be slow too.
|
||||||
|
|
||||||
@ -1034,14 +1032,25 @@ The semantics of the pinctrl APIs are:
|
|||||||
|
|
||||||
- pinctrl_put() frees all information associated with a pinctrl handle.
|
- pinctrl_put() frees all information associated with a pinctrl handle.
|
||||||
|
|
||||||
|
- devm_pinctrl_put() is a variant of pinctrl_put() that may be used to
|
||||||
|
explicitly destroy a pinctrl object returned by devm_pinctrl_get().
|
||||||
|
However, use of this function will be rare, due to the automatic cleanup
|
||||||
|
that will occur even without calling it.
|
||||||
|
|
||||||
|
pinctrl_get() must be paired with a plain pinctrl_put().
|
||||||
|
pinctrl_get() may not be paired with devm_pinctrl_put().
|
||||||
|
devm_pinctrl_get() can optionally be paired with devm_pinctrl_put().
|
||||||
|
devm_pinctrl_get() may not be paired with plain pinctrl_put().
|
||||||
|
|
||||||
Usually the pin control core handled the get/put pair and call out to the
|
Usually the pin control core handled the get/put pair and call out to the
|
||||||
device drivers bookkeeping operations, like checking available functions and
|
device drivers bookkeeping operations, like checking available functions and
|
||||||
the associated pins, whereas the enable/disable pass on to the pin controller
|
the associated pins, whereas the enable/disable pass on to the pin controller
|
||||||
driver which takes care of activating and/or deactivating the mux setting by
|
driver which takes care of activating and/or deactivating the mux setting by
|
||||||
quickly poking some registers.
|
quickly poking some registers.
|
||||||
|
|
||||||
The pins are allocated for your device when you issue the pinctrl_get() call,
|
The pins are allocated for your device when you issue the devm_pinctrl_get()
|
||||||
after this you should be able to see this in the debugfs listing of all pins.
|
call, after this you should be able to see this in the debugfs listing of all
|
||||||
|
pins.
|
||||||
|
|
||||||
NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the
|
NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the
|
||||||
requested pinctrl handles, for example if the pinctrl driver has not yet
|
requested pinctrl handles, for example if the pinctrl driver has not yet
|
||||||
@ -1092,13 +1101,13 @@ it, disables and releases it, and muxes it in on the pins defined by group B:
|
|||||||
|
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
|
|
||||||
foo_switch()
|
struct pinctrl *p;
|
||||||
{
|
struct pinctrl_state *s1, *s2;
|
||||||
struct pinctrl *p;
|
|
||||||
struct pinctrl_state *s1, *s2;
|
|
||||||
|
|
||||||
|
foo_probe()
|
||||||
|
{
|
||||||
/* Setup */
|
/* Setup */
|
||||||
p = pinctrl_get(&device);
|
p = devm_pinctrl_get(&device);
|
||||||
if (IS_ERR(p))
|
if (IS_ERR(p))
|
||||||
...
|
...
|
||||||
|
|
||||||
@ -1109,7 +1118,10 @@ foo_switch()
|
|||||||
s2 = pinctrl_lookup_state(foo->p, "pos-B");
|
s2 = pinctrl_lookup_state(foo->p, "pos-B");
|
||||||
if (IS_ERR(s2))
|
if (IS_ERR(s2))
|
||||||
...
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
foo_switch()
|
||||||
|
{
|
||||||
/* Enable on position A */
|
/* Enable on position A */
|
||||||
ret = pinctrl_select_state(s1);
|
ret = pinctrl_select_state(s1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -1123,8 +1135,6 @@ foo_switch()
|
|||||||
...
|
...
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
pinctrl_put(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
The above has to be done from process context.
|
The above has to be done from process context.
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <linux/sysfs.h>
|
#include <linux/sysfs.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/pinctrl/pinctrl.h>
|
#include <linux/pinctrl/pinctrl.h>
|
||||||
#include <linux/pinctrl/machine.h>
|
#include <linux/pinctrl/machine.h>
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
@ -801,6 +802,61 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pinctrl_select_state);
|
EXPORT_SYMBOL_GPL(pinctrl_select_state);
|
||||||
|
|
||||||
|
static void devm_pinctrl_release(struct device *dev, void *res)
|
||||||
|
{
|
||||||
|
pinctrl_put(*(struct pinctrl **)res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct devm_pinctrl_get() - Resource managed pinctrl_get()
|
||||||
|
* @dev: the device to obtain the handle for
|
||||||
|
*
|
||||||
|
* If there is a need to explicitly destroy the returned struct pinctrl,
|
||||||
|
* devm_pinctrl_put() should be used, rather than plain pinctrl_put().
|
||||||
|
*/
|
||||||
|
struct pinctrl *devm_pinctrl_get(struct device *dev)
|
||||||
|
{
|
||||||
|
struct pinctrl **ptr, *p;
|
||||||
|
|
||||||
|
ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);
|
||||||
|
if (!ptr)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
p = pinctrl_get(dev);
|
||||||
|
if (!IS_ERR(p)) {
|
||||||
|
*ptr = p;
|
||||||
|
devres_add(dev, ptr);
|
||||||
|
} else {
|
||||||
|
devres_free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devm_pinctrl_get);
|
||||||
|
|
||||||
|
static int devm_pinctrl_match(struct device *dev, void *res, void *data)
|
||||||
|
{
|
||||||
|
struct pinctrl **p = res;
|
||||||
|
|
||||||
|
return *p == data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* devm_pinctrl_put() - Resource managed pinctrl_put()
|
||||||
|
* @p: the pinctrl handle to release
|
||||||
|
*
|
||||||
|
* Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally
|
||||||
|
* this function will not need to be called and the resource management
|
||||||
|
* code will ensure that the resource is freed.
|
||||||
|
*/
|
||||||
|
void devm_pinctrl_put(struct pinctrl *p)
|
||||||
|
{
|
||||||
|
WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
|
||||||
|
devm_pinctrl_match, p));
|
||||||
|
pinctrl_put(p);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devm_pinctrl_put);
|
||||||
|
|
||||||
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
|
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
|
||||||
bool dup, bool locked)
|
bool dup, bool locked)
|
||||||
{
|
{
|
||||||
|
@ -36,6 +36,9 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
|
|||||||
const char *name);
|
const char *name);
|
||||||
extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
|
extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
|
||||||
|
|
||||||
|
extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
|
||||||
|
extern void devm_pinctrl_put(struct pinctrl *p);
|
||||||
|
|
||||||
#else /* !CONFIG_PINCTRL */
|
#else /* !CONFIG_PINCTRL */
|
||||||
|
|
||||||
static inline int pinctrl_request_gpio(unsigned gpio)
|
static inline int pinctrl_request_gpio(unsigned gpio)
|
||||||
@ -79,6 +82,15 @@ static inline int pinctrl_select_state(struct pinctrl *p,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void devm_pinctrl_put(struct pinctrl *p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_PINCTRL */
|
#endif /* CONFIG_PINCTRL */
|
||||||
|
|
||||||
static inline struct pinctrl * __must_check pinctrl_get_select(
|
static inline struct pinctrl * __must_check pinctrl_get_select(
|
||||||
@ -113,6 +125,38 @@ static inline struct pinctrl * __must_check pinctrl_get_select_default(
|
|||||||
return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
|
return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct pinctrl * __must_check devm_pinctrl_get_select(
|
||||||
|
struct device *dev, const char *name)
|
||||||
|
{
|
||||||
|
struct pinctrl *p;
|
||||||
|
struct pinctrl_state *s;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
p = devm_pinctrl_get(dev);
|
||||||
|
if (IS_ERR(p))
|
||||||
|
return p;
|
||||||
|
|
||||||
|
s = pinctrl_lookup_state(p, name);
|
||||||
|
if (IS_ERR(s)) {
|
||||||
|
devm_pinctrl_put(p);
|
||||||
|
return ERR_PTR(PTR_ERR(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pinctrl_select_state(p, s);
|
||||||
|
if (ret < 0) {
|
||||||
|
devm_pinctrl_put(p);
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct pinctrl * __must_check devm_pinctrl_get_select_default(
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
return devm_pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PINCONF
|
#ifdef CONFIG_PINCONF
|
||||||
|
|
||||||
extern int pin_config_get(const char *dev_name, const char *name,
|
extern int pin_config_get(const char *dev_name, const char *name,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user