#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;
#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;
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]);
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,
};