summaryrefslogtreecommitdiff
path: root/drivers/base/pinctrl.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2013-01-22 21:56:14 +0400
committerLinus Walleij <linus.walleij@linaro.org>2013-01-23 19:39:51 +0400
commitab78029ecc347debbd737f06688d788bd9d60c1d (patch)
treeaffc1f843abc1897ccf2723cf077be343c2845e2 /drivers/base/pinctrl.c
parent684697cbbcd076b8fde78d8863e341700533b542 (diff)
downloadlinux-ab78029ecc347debbd737f06688d788bd9d60c1d.tar.xz
drivers/pinctrl: grab default handles from device core
This makes the device core auto-grab the pinctrl handle and set the "default" (PINCTRL_STATE_DEFAULT) state for every device that is present in the device model right before probe. This will account for the lion's share of embedded silicon devcies. A modification of the semantics for pinctrl_get() is also done: previously if the pinctrl handle for a certain device was already taken, the pinctrl core would return an error. Now, since the core may have already default-grabbed the handle and set its state to "default", if the handle was already taken, this will be disregarded and the located, previously instanitated handle will be returned to the caller. This way all code in drivers explicitly requesting their pinctrl handlers will still be functional, and drivers that want to explicitly retrieve and switch their handles can still do that. But if the desired functionality is just boilerplate of this type in the probe() function: struct pinctrl *p; p = devm_pinctrl_get_select_default(&dev); if (IS_ERR(p)) { if (PTR_ERR(p) == -EPROBE_DEFER) return -EPROBE_DEFER; dev_warn(&dev, "no pinctrl handle\n"); } The discussion began with the addition of such boilerplate to the omap4 keypad driver: http://marc.info/?l=linux-input&m=135091157719300&w=2 A previous approach using notifiers was discussed: http://marc.info/?l=linux-kernel&m=135263661110528&w=2 This failed because it could not handle deferred probes. This patch alone does not solve the entire dilemma faced: whether code should be distributed into the drivers or if it should be centralized to e.g. a PM domain. But it solves the immediate issue of the addition of boilerplate to a lot of drivers that just want to grab the default state. As mentioned, they can later explicitly retrieve the handle and set different states, and this could as well be done by e.g. PM domains as it is only related to a certain struct device * pointer. ChangeLog v4->v5 (Stephen): - Simplified the devicecore grab code. - Deleted a piece of documentation recommending that pins be mapped to a device rather than hogged. ChangeLog v3->v4 (Linus): - Drop overzealous NULL checks. - Move kref initialization to pinctrl_create(). - Seeking Tested-by from Stephen Warren so we do not disturb the Tegra platform. - Seeking ACK on this from Greg (and others who like it) so I can merge it through the pinctrl subsystem. ChangeLog v2->v3 (Linus): - Abstain from using IS_ERR_OR_NULL() in the driver core, Russell recently sent a patch to remove it. Handle the NULL case explicitly even though it's a bogus case. - Make sure we handle probe deferral correctly in the device core file. devm_kfree() the container on error so we don't waste memory for devices without pinctrl handles. - Introduce reference counting into the pinctrl core using <linux/kref.h> so that we don't release pinctrl handles that have been obtained for two or more places. ChangeLog v1->v2 (Linus): - Only store a pointer in the device struct, and only allocate this if it's really used by the device. Cc: Felipe Balbi <balbi@ti.com> Cc: Benoit Cousson <b-cousson@ti.com> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Mitch Bradley <wmb@firmworks.com> Cc: Ulf Hansson <ulf.hansson@linaro.org> Cc: Rafael J. Wysocki <rjw@sisk.pl> Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Cc: Rickard Andersson <rickard.andersson@stericsson.com> Cc: Russell King <linux@arm.linux.org.uk> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> [swarren: fixed and simplified error-handling in pinctrl_bind_pins(), to correctly handle deferred probe. Removed admonition from docs not to use pinctrl hogs for devices] Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/base/pinctrl.c')
-rw-r--r--drivers/base/pinctrl.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c
new file mode 100644
index 000000000000..67a274e86727
--- /dev/null
+++ b/drivers/base/pinctrl.c
@@ -0,0 +1,69 @@
+/*
+ * Driver core interface to the pinctrl subsystem.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ * Based on bits of regulator core, gpio core and clk core
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/device.h>
+#include <linux/pinctrl/devinfo.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/slab.h>
+
+/**
+ * pinctrl_bind_pins() - called by the device core before probe
+ * @dev: the device that is just about to probe
+ */
+int pinctrl_bind_pins(struct device *dev)
+{
+ int ret;
+
+ dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
+ if (!dev->pins)
+ return -ENOMEM;
+
+ dev->pins->p = devm_pinctrl_get(dev);
+ if (IS_ERR(dev->pins->p)) {
+ dev_dbg(dev, "no pinctrl handle\n");
+ ret = PTR_ERR(dev->pins->p);
+ goto cleanup_alloc;
+ }
+
+ dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(dev->pins->default_state)) {
+ dev_dbg(dev, "no default pinctrl state\n");
+ ret = 0;
+ goto cleanup_get;
+ }
+
+ ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state);
+ if (ret) {
+ dev_dbg(dev, "failed to activate default pinctrl state\n");
+ goto cleanup_get;
+ }
+
+ return 0;
+
+ /*
+ * If no pinctrl handle or default state was found for this device,
+ * let's explicitly free the pin container in the device, there is
+ * no point in keeping it around.
+ */
+cleanup_get:
+ devm_pinctrl_put(dev->pins->p);
+cleanup_alloc:
+ devm_kfree(dev, dev->pins);
+ dev->pins = NULL;
+
+ /* Only return deferrals */
+ if (ret != -EPROBE_DEFER)
+ ret = 0;
+
+ return ret;
+}