[PATCH 4/4] pinctrl: at91-pio4: Add support for pinctrl config subnodes

Sergiu Moga sergiu.moga at microchip.com
Thu Sep 1 16:22:42 CEST 2022


Previously, in order for the `pinctrl-*` DT node properties
to be properly processed, the pinctrl's subnodes were limited
to only having the `pinmux` property as well as other additional
properties (slew-rate, bias-disable, etc.). Now, with this patch
the pinctrl driver is made to work similarly to the one from Linux.
It can now distinguish between one subnode and a subnode with multiple
subnodes.

Signed-off-by: Sergiu Moga <sergiu.moga at microchip.com>
---
 drivers/pinctrl/pinctrl-at91-pio4.c | 73 ++++++++++++++++++++++++-----
 1 file changed, 61 insertions(+), 12 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index e434a38f1f..50e3dd449a 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -15,6 +15,7 @@
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <dm/uclass-internal.h>
 #include <mach/atmel_pio4.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -151,12 +152,11 @@ static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
 
 #define MAX_PINMUX_ENTRIES	40
 
-static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+static int atmel_process_config_dev(struct udevice *dev, struct udevice *config)
 {
 	struct atmel_pio4_plat *plat = dev_get_plat(dev);
-	struct atmel_pio4_port *bank_base;
-	const void *blob = gd->fdt_blob;
 	int node = dev_of_offset(config);
+	struct atmel_pio4_port *bank_base;
 	u32 offset, func, bank, line;
 	u32 cells[MAX_PINMUX_ENTRIES];
 	u32 i, conf;
@@ -164,18 +164,17 @@ static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
 
 	conf = atmel_pinctrl_get_pinconf(config, plat);
 
-	count = fdtdec_get_int_array_count(blob, node, "pinmux",
+	/*
+	 * The only case where this function returns a negative error value
+	 * is when there is no "pinmux" property attached to this node
+	 */
+	count = fdtdec_get_int_array_count(gd->fdt_blob, node, "pinmux",
 					   cells, ARRAY_SIZE(cells));
-	if (count < 0) {
-		printf("%s: bad pinmux array %d\n", __func__, count);
-		return -EINVAL;
-	}
+	if (count < 0)
+		return count;
 
-	if (count > MAX_PINMUX_ENTRIES) {
-		printf("%s: unsupported pinmux array count %d\n",
-		       __func__, count);
+	if (count > MAX_PINMUX_ENTRIES)
 		return -EINVAL;
-	}
 
 	for (i = 0 ; i < count; i++) {
 		offset = ATMEL_GET_PIN_NO(cells[i]);
@@ -195,6 +194,56 @@ static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
 	return 0;
 }
 
+static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+{
+	int node = dev_of_offset(config);
+	struct udevice *subconfig;
+	int subnode, subnode_count = 0, ret;
+
+	/*
+	 * If this function returns a negative error code then that means
+	 * that either the "pinmux" property of the node is missing, which is
+	 * the case for pinctrl nodes that do not have all the pins with the
+	 * same configuration and are split in multiple subnodes, or something
+	 * else went wrong and we have to stop. For the latter case, it would
+	 * mean that the node failed even though it has no subnodes.
+	 */
+	ret = atmel_process_config_dev(dev, config);
+	if (!ret)
+		return ret;
+
+	/*
+	 * If we reach here, it means that the subnode pinctrl's DT has multiple
+	 * subnodes. If it does not, then something else went wrong in the
+	 * previous call to atmel_process_config_dev.
+	 */
+	fdt_for_each_subnode(subnode, gd->fdt_blob, node) {
+		/* Get subnode as an udevice */
+		ret = uclass_find_device_by_of_offset(UCLASS_PINCONFIG, subnode,
+						      &subconfig);
+		if (ret)
+			return ret;
+
+		/*
+		 * If this time the function returns an error code on a subnode
+		 * then something is totally wrong so abort.
+		 */
+		ret = atmel_process_config_dev(dev, subconfig);
+		if (ret)
+			return ret;
+
+		subnode_count++;
+	}
+
+	/*
+	 * If we somehow got here and we do not have any subnodes, abort.
+	 */
+	if (!subnode_count)
+		return -EINVAL;
+
+	return 0;
+}
+
 const struct pinctrl_ops atmel_pinctrl_ops  = {
 	.set_state = atmel_pinctrl_set_state,
 };
-- 
2.25.1



More information about the U-Boot mailing list