浏览代码

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>
Stephen Warren 13 年之前
父节点
当前提交
6d4ca1fb46
共有 4 个文件被更改,包括 133 次插入19 次删除
  1. 4 0
      Documentation/driver-model/devres.txt
  2. 29 19
      Documentation/pinctrl.txt
  3. 56 0
      drivers/pinctrl/core.c
  4. 44 0
      include/linux/pinctrl/consumer.h

+ 4 - 0
Documentation/driver-model/devres.txt

@@ -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()

+ 29 - 19
Documentation/pinctrl.txt

@@ -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,
-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
 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.

+ 56 - 0
drivers/pinctrl/core.c

@@ -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)
 {
 {

+ 44 - 0
include/linux/pinctrl/consumer.h

@@ -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,