linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Rafał Miłecki" <zajec5@gmail.com>
To: Linus Walleij <linus.walleij@linaro.org>,
	Rob Herring <robh+dt@kernel.org>
Cc: "Tony Lindgren" <tony@atomide.com>,
	"Andy Shevchenko" <andy.shevchenko@gmail.com>,
	linux-gpio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	"Florian Fainelli" <f.fainelli@gmail.com>,
	bcm-kernel-feedback-list@broadcom.com,
	"Rafał Miłecki" <rafal@milecki.pl>
Subject: [PATCH V2 4/6] pinctrl: support reading pins, groups & functions from DT
Date: Thu, 25 Nov 2021 00:04:37 +0100	[thread overview]
Message-ID: <20211124230439.17531-5-zajec5@gmail.com> (raw)
In-Reply-To: <20211124230439.17531-1-zajec5@gmail.com>

From: Rafał Miłecki <rafal@milecki.pl>

DT binding allows specifying pins, groups & functions now. That allows
storing them in DT instead of hardcoding in drivers.

This adds support for DT as data source to recently introduced API.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
V2: Update pinctrl_generic_dt_load_pins() to support new binding
---
 drivers/pinctrl/core.c       |   6 ++
 drivers/pinctrl/devicetree.c | 131 +++++++++++++++++++++++++++++++++++
 drivers/pinctrl/devicetree.h |  29 ++++++++
 drivers/pinctrl/pinmux.c     |   4 ++
 4 files changed, 170 insertions(+)

diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 53b3e8b54a9b..4c39ca338896 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -517,6 +517,9 @@ EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
 
 int pinctrl_generic_load_pins(struct pinctrl_desc *pctldesc, struct device *dev)
 {
+	if (dev->of_node)
+		return pinctrl_generic_dt_load_pins(pctldesc, dev);
+
 	return -ENOENT;
 }
 EXPORT_SYMBOL_GPL(pinctrl_generic_load_pins);
@@ -525,6 +528,9 @@ EXPORT_SYMBOL_GPL(pinctrl_generic_load_pins);
 
 int pinctrl_generic_load_groups(struct pinctrl_dev *pctldev)
 {
+	if (pctldev->dev->of_node)
+		return pinctrl_generic_load_dt_groups(pctldev);
+
 	return -ENOENT;
 }
 EXPORT_SYMBOL_GPL(pinctrl_generic_load_groups);
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index 3fb238714718..5e511e61449a 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -12,6 +12,7 @@
 
 #include "core.h"
 #include "devicetree.h"
+#include "pinmux.h"
 
 /**
  * struct pinctrl_dt_map - mapping table chunk parsed from device tree
@@ -27,6 +28,136 @@ struct pinctrl_dt_map {
 	unsigned num_maps;
 };
 
+int pinctrl_generic_dt_load_pins(struct pinctrl_desc *pctldesc,
+				struct device *dev)
+{
+	struct pinctrl_pin_desc *descs;
+	struct device_node *pins;
+	struct device_node *np;
+	int err = 0;
+	int i = 0;
+
+	pins = of_get_child_by_name(dev->of_node, "pins");
+	if (!pins) {
+		dev_err(dev, "failed to find \"pins\" DT node\n");
+		err = -ENOENT;
+		goto err_out;
+	}
+
+	pctldesc->npins = of_get_available_child_count(pins);
+
+	descs = devm_kcalloc(dev, pctldesc->npins, sizeof(*descs), GFP_KERNEL);
+	if (!descs) {
+		err = -ENOMEM;
+		goto err_put_node;
+	}
+
+	for_each_available_child_of_node(pins, np) {
+		descs[i].name = np->name;
+
+		if (of_property_read_u32(np, "number", &descs[i].number)) {
+			dev_err(dev, "missing \"number\" property in %pOF\n", np);
+			err = -ENOENT;
+			goto err_put_node;
+		}
+
+		i++;
+	}
+
+	pctldesc->pins = descs;
+
+err_put_node:
+	of_node_put(pins);
+err_out:
+	return err;
+}
+
+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
+
+int pinctrl_generic_load_dt_groups(struct pinctrl_dev *pctldev)
+{
+	struct device *dev = pctldev->dev;
+	struct device_node *groups;
+	struct device_node *np;
+	int err = 0;
+
+	groups = of_get_child_by_name(dev->of_node, "groups");
+	if (!groups) {
+		dev_err(dev, "failed to find \"groups\" DT node\n");
+		err = -ENOENT;
+		goto err_out;
+	}
+
+	for_each_available_child_of_node(groups, np) {
+		int num_pins;
+		u32 *pins;
+
+		num_pins = of_property_count_u32_elems(np, "pins");
+		pins = devm_kmalloc_array(dev, num_pins, sizeof(*pins), GFP_KERNEL);
+		if (!pins) {
+			err = -ENOMEM;
+			goto err_put_node;
+		}
+
+		if (of_property_read_u32_array(np, "pins", pins, num_pins)) {
+			err = -EIO;
+			goto err_put_node;
+		}
+
+		pinctrl_generic_add_group(pctldev, np->name, pins, num_pins, np);
+	}
+
+err_put_node:
+	of_node_put(groups);
+err_out:
+	return err;
+}
+
+#endif
+
+#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
+int pinmux_generic_load_dt_functions(struct pinctrl_dev *pctldev)
+{
+	struct device *dev = pctldev->dev;
+	struct device_node *functions;
+	struct device_node *np;
+	int err = 0;
+
+	functions = of_get_child_by_name(dev->of_node, "functions");
+	if (!functions) {
+		dev_err(dev, "failed to find \"functions\" DT node\n");
+		err = -ENOENT;
+		goto err_out;
+	}
+
+	for_each_available_child_of_node(functions, np) {
+		int num_groups = of_count_phandle_with_args(np, "groups", NULL);
+		struct of_phandle_iterator it;
+		const char **groups;
+		int ret;
+		int i;
+
+		groups = devm_kmalloc_array(dev, num_groups, sizeof(*groups), GFP_KERNEL);
+		if (!groups) {
+			err = -ENOMEM;
+			goto err_put_node;
+		}
+
+		i = 0;
+		of_for_each_phandle(&it, ret, np, "groups", NULL, 0) {
+			groups[i++] = it.node->name;
+		}
+
+		pinmux_generic_add_function(pctldev, np->name, groups, num_groups, np);
+	}
+
+err_put_node:
+	of_node_put(functions);
+err_out:
+	return err;
+}
+#endif
+
 static void dt_free_map(struct pinctrl_dev *pctldev,
 		     struct pinctrl_map *map, unsigned num_maps)
 {
diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h
index efa80779de4f..156f13896c39 100644
--- a/drivers/pinctrl/devicetree.h
+++ b/drivers/pinctrl/devicetree.h
@@ -9,6 +9,15 @@ struct of_phandle_args;
 
 #ifdef CONFIG_OF
 
+int pinctrl_generic_dt_load_pins(struct pinctrl_desc *pctldesc,
+				struct device *dev);
+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
+int pinctrl_generic_load_dt_groups(struct pinctrl_dev *pctldev);
+#endif
+#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
+int pinmux_generic_load_dt_functions(struct pinctrl_dev *pctldev);
+#endif
+
 void pinctrl_dt_free_maps(struct pinctrl *p);
 int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev);
 
@@ -21,6 +30,26 @@ int pinctrl_parse_index_with_args(const struct device_node *np,
 
 #else
 
+static inline int pinctrl_generic_dt_load_pins(struct pinctrl_desc *pctldesc,
+					      struct device *dev)
+{
+	return -EOPNOTSUPP;
+}
+
+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
+static inline int pinctrl_generic_load_dt_groups(struct pinctrl_dev *pctldev)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
+#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
+static inline int pinmux_generic_load_dt_functions(struct pinctrl_dev *pctldev)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 static inline int pinctrl_dt_to_map(struct pinctrl *p,
 				    struct pinctrl_dev *pctldev)
 {
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index ef7d2cbf0946..36a1d1af4a20 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -27,6 +27,7 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/pinmux.h>
 #include "core.h"
+#include "devicetree.h"
 #include "pinmux.h"
 
 int pinmux_check_ops(struct pinctrl_dev *pctldev)
@@ -790,6 +791,9 @@ void pinmux_init_device_debugfs(struct dentry *devroot,
 
 int pinmux_generic_load_functions(struct pinctrl_dev *pctldev)
 {
+	if (pctldev->dev->of_node)
+		return pinmux_generic_load_dt_functions(pctldev);
+
 	return -ENOENT;
 }
 EXPORT_SYMBOL_GPL(pinmux_generic_load_functions);
-- 
2.31.1


  parent reply	other threads:[~2021-11-24 23:05 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-24 23:04 [PATCH V2 0/6] pinctrl: support platform (e.g. DT) stored pins, groups & functions Rafał Miłecki
2021-11-24 23:04 ` [PATCH V2 1/6] dt-bindings: pinctrl: support specifying " Rafał Miłecki
2021-11-25  8:49   ` Tony Lindgren
2021-11-25 12:28     ` Rafał Miłecki
2021-11-26  1:03       ` Linus Walleij
2021-11-24 23:04 ` [PATCH V2 2/6] dt-bindings: pinctrl: brcm,ns-pinmux: extend example Rafał Miłecki
2021-11-25 21:26   ` Rob Herring
2021-11-24 23:04 ` [PATCH V2 3/6] pinctrl: prepare API for reading pins, groups & functions Rafał Miłecki
2021-11-24 23:04 ` Rafał Miłecki [this message]
2021-11-25  9:49   ` [PATCH V2 4/6] pinctrl: support reading pins, groups & functions from DT Andy Shevchenko
2021-11-25  9:51     ` Andy Shevchenko
2021-11-24 23:04 ` [PATCH V2 5/6] pinctrl: bcm: pinctrl-ns: supoprt DT specified pins, groups & functions Rafał Miłecki
2021-11-24 23:04 ` [PATCH V2 6/6] ARM: dts: BCM5301X: add pinctrl " Rafał Miłecki
2021-11-25  9:58 ` [PATCH V2 0/6] pinctrl: support platform (e.g. DT) stored " Andy Shevchenko
2021-12-09 14:30   ` Rafał Miłecki

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=20211124230439.17531-5-zajec5@gmail.com \
    --to=zajec5@gmail.com \
    --cc=andy.shevchenko@gmail.com \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=devicetree@vger.kernel.org \
    --cc=f.fainelli@gmail.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=rafal@milecki.pl \
    --cc=robh+dt@kernel.org \
    --cc=tony@atomide.com \
    /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).