From: b29396@freescale.com (Dong Aisheng)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 6/6] pinctrl: add pinctrl gpio binding support
Date: Fri, 25 May 2012 21:36:20 +0800 [thread overview]
Message-ID: <1337952980-14621-6-git-send-email-b29396@freescale.com> (raw)
In-Reply-To: <1337952980-14621-1-git-send-email-b29396@freescale.com>
From: Dong Aisheng <dong.aisheng@linaro.org>
This patch implements a standard common binding for pinctrl gpio ranges.
Each SoC can add gpio ranges through device tree by adding a gpio-maps property
under their pinctrl devices node with the format:
<&gpio $gpio-specifier $pin_offset $count>
while the gpio phandle and gpio-specifier are the standard approach
to represent a gpio in device tree.
Then we can cooperate it with the gpio xlate function to get the gpio number
from device tree to set up the gpio ranges map.
Then the pinctrl driver can call pinctrl_dt_add_gpio_ranges(pctldev, node)
to parse and register the gpio ranges from device tree.
Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
---
Personally i'm not very satisfied with current solution due to a few reasons:
1) i can not user standard gpio api to get gpio number
2) i need to reinvent a new api of_parse_phandles_with_args_ext which i'm not
sure if it can be accepted by DT maintainer.
If i did not invent that API, i need to rewrite a lot of duplicated code
with slight differences with the exist functions like of_get_named_gpio_flags
and of_parse_phandle_with_args for the special pinctrl gpio maps format.
So i just sent it out first to see people's comment and if any better solution.
One alternative solution is that that the gpio-maps into two parts:
pinctrl-gpios = <&gpio_phandle gpio-specifier ..>
pinctrl-gpio-maps = <pin_id count ..>
Then we can reuse the standard gpio api altough it's not better than the
original one.
Comments are welcome!
ChangeLog v3->v4:
* using standard gpio parsing approach to get the gpio number from device
tree. The gpio-maps becomes a little slightly different as before:
<&gpio $gpio_specifier $pin_offset $npin>.
The $gpio_specifier length is controller dependent which is specified by
'#gpio-cells' in in gpio controller node.
ChangeLog v2->v3:
* standardise the gpio ranges node name to 'gpio-maps'. Each SoC should use this
node name to define gpio ranges.
* defer probe if can not get gpiochip from node in case gpio driver is still
not loaded.
* some other minor fixes suggested by Stephen Warren.
ChangeLog v1->v2:
* introduce standard binding for gpio range.
---
.../bindings/pinctrl/pinctrl-bindings.txt | 22 +++++
drivers/pinctrl/devicetree.c | 95 ++++++++++++++++++++
include/linux/pinctrl/pinctrl.h | 11 +++
3 files changed, 128 insertions(+), 0 deletions(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
index c95ea82..e999be5 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
@@ -126,3 +126,25 @@ device; they may be grandchildren, for example. Whether this is legal, and
whether there is any interaction between the child and intermediate parent
nodes, is again defined entirely by the binding for the individual pin
controller device.
+
+=== pinctrl gpio ranges ===
+Some pins in pinctrl device can also be multiplexed as gpio. With a gpio range
+map, user can know which pin in the range can be used as gpio.
+
+Required properties:
+gpio-maps: integers array, each entry in the array represents a gpio range
+with the format: <&gpio $gpio-specifier $pin_offset $count>
+- gpio: phandle pointing at gpio device node
+- gpio-specifier: array of #gpio-cells specifying specific gpio, the length is
+ controller specific. Usually it may be two cells for simple gpio.
+- pin_offset: integer, the pin offset or pin id
+- npins: integer, the gpio ranges starting from pin_offset
+
+For example:
+pincontroller {
+ /* gpio-specifier is two cells */
+ gpio-maps = <&gpio1 0 0 0 32
+ &gpio2 0 0 0 30
+ &gpio3 1 0 100 1
+ ....>;
+};
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index fcb1de4..bc5f0f8 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -17,7 +17,9 @@
*/
#include <linux/device.h>
+#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
@@ -247,3 +249,96 @@ err:
pinctrl_dt_free_maps(p);
return ret;
}
+
+/*
+ * pinctrl_dt_add_gpio_range() - parse and register GPIO ranges from device tree
+ * @pctldev: pin controller device to add the range to
+ * @np: the device node contains the gpio-maps node
+ * The format of gpio-maps should be:
+ * <&gpio $gpio-specifier $pin_offset $count>
+ * The gpio-specifier length is controller dependent which is specified by
+ * #gpio-cells in in gpio controller node.
+ */
+int pinctrl_dt_add_gpio_ranges(struct pinctrl_dev *pctldev,
+ struct device_node *np)
+{
+ struct pinctrl_gpio_range *ranges;
+ unsigned int gpio_offset, pin_offset, npins;
+ struct device_node *np_gpio;
+ struct of_phandle_args gpiospec;
+ struct property *prop;
+ const __be32 *list;
+ phandle phandle;
+ int nranges = 0;
+ int size;
+ int i;
+ int ret;
+
+ if (!np) {
+ dev_err(pctldev->dev, "no device node\n");
+ return -EINVAL;
+ }
+
+ /* count gpio ranges */
+ do {
+ ret = of_parse_phandle_with_args_ext(np, "gpio-maps", "#gpio-cells",
+ nranges, 2, NULL);
+ if (ret)
+ break;
+ } while (++nranges);
+
+ if (!nranges) {
+ dev_err(pctldev->dev, "no gpio ranges found\n");
+ return -ENODEV;
+ }
+
+ /* setup gpio ranges table */
+ ranges = devm_kzalloc(pctldev->dev, nranges * sizeof(*ranges),
+ GFP_KERNEL);
+ for (i = 0; i < nranges; i++) {
+ ret = of_parse_phandle_with_args_ext(np, "gpio-maps", "#gpio-cells",
+ i, 2, &gpiospec);
+ if (ret)
+ return ret;
+
+ ranges[i].gc = of_node_to_gpiochip(gpiospec.np);
+ if (!ranges[i].gc) {
+ dev_err(pctldev->dev,
+ "can not find gpio chip of node(%s)\n",
+ gpiospec.np->full_name);
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
+
+ if (!ranges[i].gc->of_xlate) {
+ dev_err(pctldev->dev,
+ "no of_xlate function found for gpio(%s)\n",
+ gpiospec.np->full_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ranges[i].name = dev_name(pctldev->dev);
+ ranges[i].base = ranges[i].gc->of_xlate(ranges[i].gc, &gpiospec, NULL);
+ if (ranges[i].base < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ranges[i].base += ranges[i].gc->base;
+ ranges[i].pin_base = gpiospec.args[gpiospec.args_count - 2];
+ ranges[i].npins = gpiospec.args[gpiospec.args_count - 1];
+
+ gpiochip_put(ranges[i].gc);
+ of_node_put(gpiospec.np);
+ }
+
+ pinctrl_add_gpio_ranges(pctldev, ranges, nranges);
+
+ return 0;
+
+out:
+ of_node_put(gpiospec.np);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_dt_add_gpio_ranges);
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 3b894a6..947ab9f 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -135,6 +135,17 @@ extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range);
extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
+#ifdef CONFIG_OF
+extern int pinctrl_dt_add_gpio_ranges(struct pinctrl_dev *pctldev,
+ struct device_node *np);
+#else
+static inline int pinctrl_dt_add_gpio_ranges(struct pinctrl_dev *pctldev,
+ struct device_node *np);
+{
+ return 0;
+}
+#endif /* !CONFIG_OF */
+
#else
struct pinctrl_dev;
--
1.7.0.4
next prev parent reply other threads:[~2012-05-25 13:36 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-05-25 13:36 [PATCH v4 1/6] gpio: fix a typo of comment message Dong Aisheng
2012-05-25 13:36 ` [PATCH v4 2/6] gpio: re-add of_node_to_gpiochip function Dong Aisheng
2012-05-26 0:01 ` Grant Likely
2012-05-26 16:15 ` Dong Aisheng
2012-05-25 13:36 ` [PATCH v4 3/6] of: release node fix for of_parse_phandle_with_args Dong Aisheng
2012-05-26 0:09 ` Grant Likely
2012-05-25 13:36 ` [PATCH v4 4/6] gpio: introduce lock mechanism for gpiochip_find Dong Aisheng
2012-05-26 0:25 ` Grant Likely
2012-05-26 16:17 ` Dong Aisheng
2012-05-30 4:10 ` Dong Aisheng
2012-05-30 6:33 ` Grant Likely
2012-05-25 13:36 ` [PATCH v4 5/6] of: add of_parse_phandle_with_args_ext function Dong Aisheng
2012-05-25 16:50 ` Stephen Warren
2012-05-25 13:36 ` Dong Aisheng [this message]
2012-05-25 17:03 ` [PATCH v4 6/6] pinctrl: add pinctrl gpio binding support Stephen Warren
2012-05-26 16:52 ` Dong Aisheng
2012-05-27 15:39 ` Stephen Warren
2012-05-30 3:01 ` Dong Aisheng
2012-05-30 3:52 ` Stephen Warren
2012-05-30 6:35 ` Grant Likely
2012-05-26 0:29 ` Grant Likely
2012-05-26 16:58 ` Dong Aisheng
2012-05-30 6:46 ` Grant Likely
2012-05-30 7:29 ` Dong Aisheng
2012-05-25 23:57 ` [PATCH v4 1/6] gpio: fix a typo of comment message Grant Likely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1337952980-14621-6-git-send-email-b29396@freescale.com \
--to=b29396@freescale.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).