[PATCH V2 4/6] pinctrl: support reading pins, groups & functions from DT
Rafał Miłecki
zajec5 at gmail.com
Wed Nov 24 15:04:37 PST 2021
From: Rafał Miłecki <rafal at 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 at 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
More information about the linux-arm-kernel
mailing list