Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d4ca1fb authored by Stephen Warren's avatar Stephen Warren Committed by Linus Walleij
Browse files

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: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 2aeefe02
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -276,3 +276,7 @@ REGULATOR
  devm_regulator_get()
  devm_regulator_put()
  devm_regulator_bulk_get()

PINCTRL
  devm_pinctrl_get()
  devm_pinctrl_put()
+29 −19
Original line number Diff line number Diff line
@@ -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;

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.
+56 −0
Original line number Diff line number Diff line
@@ -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)
{
+44 −0
Original line number Diff line number Diff line
@@ -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,