]> Pileus Git - ~andy/linux/commitdiff
pinctrl: implement devm_pinctrl_get()/put()
authorStephen Warren <swarren@nvidia.com>
Mon, 16 Apr 2012 16:51:00 +0000 (10:51 -0600)
committerLinus Walleij <linus.walleij@linaro.org>
Wed, 18 Apr 2012 11:53:13 +0000 (13:53 +0200)
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>
Documentation/driver-model/devres.txt
Documentation/pinctrl.txt
drivers/pinctrl/core.c
include/linux/pinctrl/consumer.h

index 2a596a4fc23eeb03f1c04cbcc9415b121adfdc04..ef4fa7b423d22904436db0400fa8e69ba7f73d5f 100644 (file)
@@ -276,3 +276,7 @@ REGULATOR
   devm_regulator_get()
   devm_regulator_put()
   devm_regulator_bulk_get()
+
+PINCTRL
+  devm_pinctrl_get()
+  devm_pinctrl_put()
index 4431c3e727ba49d632116fb078dcbd80704bca51..e40f4b4e1977c73d1f6984c705c1065878ad4ad4 100644 (file)
@@ -945,13 +945,13 @@ case), we define a mapping like this:
 The result of grabbing this mapping from the device with something like
 this (see next paragraph):
 
-       p = pinctrl_get(dev);
+       p = devm_pinctrl_get(dev);
        s = pinctrl_lookup_state(p, "8bit");
        ret = pinctrl_select_state(p, s);
 
 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
 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 */
        struct foo_state *foo = ...;
 
-       foo->p = pinctrl_get(&device);
+       foo->p = devm_pinctrl_get(&device);
        if (IS_ERR(foo->p)) {
                /* FIXME: clean up "foo" here */
                return PTR_ERR(foo->p);
@@ -993,24 +993,17 @@ foo_probe()
 
        foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
        if (IS_ERR(foo->s)) {
-               pinctrl_put(foo->p);
                /* FIXME: clean up "foo" here */
                return PTR_ERR(s);
        }
 
        ret = pinctrl_select_state(foo->s);
        if (ret < 0) {
-               pinctrl_put(foo->p);
                /* FIXME: clean up "foo" here */
                return ret;
        }
 }
 
-foo_remove()
-{
-       pinctrl_put(state->p);
-}
-
 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
 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
   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
   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.
 
+- 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
 device drivers bookkeeping operations, like checking available functions and
 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
 quickly poking some registers.
 
-The pins are allocated for your device when you issue the pinctrl_get() call,
-after this you should be able to see this in the debugfs listing of all pins.
+The pins are allocated for your device when you issue the devm_pinctrl_get()
+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
 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>
 
-foo_switch()
-{
-       struct pinctrl *p;
-       struct pinctrl_state *s1, *s2;
+struct pinctrl *p;
+struct pinctrl_state *s1, *s2;
 
+foo_probe()
+{
        /* Setup */
-       p = pinctrl_get(&device);
+       p = devm_pinctrl_get(&device);
        if (IS_ERR(p))
                ...
 
@@ -1109,7 +1118,10 @@ foo_switch()
        s2 = pinctrl_lookup_state(foo->p, "pos-B");
        if (IS_ERR(s2))
                ...
+}
 
+foo_switch()
+{
        /* Enable on position A */
        ret = pinctrl_select_state(s1);
        if (ret < 0)
@@ -1123,8 +1135,6 @@ foo_switch()
            ...
 
        ...
-
-       pinctrl_put(p);
 }
 
 The above has to be done from process context.
index 59027ab8347a42c4dcc617949c5bf7f07cff1918..2eaa1876534b24ddc2730393228924fd015e8a47 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sysfs.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/machine.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);
 
+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,
                         bool dup, bool locked)
 {
index 191e7268848170ad2a8889ba4c0a559860c75fa0..6dd96fb45482b00b0ede76c92f83fc6bd76f0f2f 100644 (file)
@@ -36,6 +36,9 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
                                                        const char *name);
 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 */
 
 static inline int pinctrl_request_gpio(unsigned gpio)
@@ -79,6 +82,15 @@ static inline int pinctrl_select_state(struct pinctrl *p,
        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 */
 
 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);
 }
 
+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
 
 extern int pin_config_get(const char *dev_name, const char *name,