On Tue, Jun 21, 2011 at 01:13:50PM -0600, Grant Likely wrote:
[...]
> >
> >  /**
> > + *     of_get_device_index - Get device index by looking up "aliases" node
> > + *     @np:    Pointer to device node that asks for device index
> > + *     @name:  The device alias without index number
> > + *
> > + *     Returns the device index if find it, else returns -ENODEV.
> > + */
> > +int of_get_device_index(struct device_node *np, const char *alias)
> > +{
> > +       struct device_node *aliases = of_find_node_by_name(NULL, "aliases");
> > +       struct property *prop;
> > +       char name[32];
> > +       int index = 0;
> > +
> > +       if (!aliases)
> > +               return -ENODEV;
> > +
> > +       while (1) {
> > +               snprintf(name, sizeof(name), "%s%d", alias, index);
> > +               prop = of_find_property(aliases, name, NULL);
> > +               if (!prop)
> > +                       return -ENODEV;
> > +               if (np == of_find_node_by_path(prop->value))
> > +                       break;
> > +               index++;
> > +       }
> 
> Rather than parsing the alias strings everytime, it would probably be
> better to preprocess all the properties in the aliases node and create
> a lookup table of alias->node references that can be walked quickly
> and trivially.
> 
> Also, when obtaining an enumeration for a device, you'll need to be
> careful about what number gets returned.  If the node doesn't match a
> given alias, but aliases do exist for other devices of like type, then
> you need to be careful not to assign a number already assigned to
> another device via an alias (this of course assumes the driver
> supports dynamics enumeration, which many drivers will).  It would be
> 

Grant, please take a look at the second shot below.  Please let me
know what you think.

diff --git a/arch/arm/boot/dts/imx51-babbage.dts 
b/arch/arm/boot/dts/imx51-babbage.dts
index 7976932..f4a5c3c 100644
--- a/arch/arm/boot/dts/imx51-babbage.dts
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -18,6 +18,12 @@
        compatible = "fsl,imx51-babbage", "fsl,imx51";
        interrupt-parent = <&tzic>;
 
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+               serial2 = &uart2;
+       };
+
        chosen {
                bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 
rootwait";
        };
@@ -47,29 +53,29 @@
                        reg = <0x70000000 0x40000>;
                        ranges;
 
-                       uart@7000c000 {
-                               compatible = "fsl,imx51-uart", "fsl,imx-uart";
+                       uart2: uart@7000c000 {
+                               compatible = "fsl,imx51-uart", "fsl,imx21-uart";
                                reg = <0x7000c000 0x4000>;
                                interrupts = <33>;
                                id = <3>;
                                fsl,has-rts-cts;
                        };
                };
 
-               uart@73fbc000 {
-                       compatible = "fsl,imx51-uart", "fsl,imx-uart";
+               uart0: uart@73fbc000 {
+                       compatible = "fsl,imx51-uart", "fsl,imx21-uart";
                        reg = <0x73fbc000 0x4000>;
                        interrupts = <31>;
                        id = <1>;
                        fsl,has-rts-cts;
                };
 
-               uart@73fc0000 {
-                       compatible = "fsl,imx51-uart", "fsl,imx-uart";
+               uart1: uart@73fc0000 {
+                       compatible = "fsl,imx51-uart", "fsl,imx21-uart";
                        reg = <0x73fc0000 0x4000>;
                        interrupts = <32>;
                        id = <2>;
                        fsl,has-rts-cts;
                };
        };
 
diff --git a/arch/arm/mach-mx5/imx51-dt.c b/arch/arm/mach-mx5/imx51-dt.c
index 8bfdb91..e6c7298 100644
--- a/arch/arm/mach-mx5/imx51-dt.c
+++ b/arch/arm/mach-mx5/imx51-dt.c
@@ -40,6 +40,8 @@ static const struct of_device_id tzic_of_match[] __initconst 
= {
 
 static void __init imx51_dt_init(void)
 {
+       of_scan_aliases();
+
        irq_domain_generate_simple(tzic_of_match, MX51_TZIC_BASE_ADDR, 0);
 
        of_platform_populate(NULL, of_default_bus_match_table,
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 632ebae..90349a2 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -17,12 +17,27 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
+#include <linux/ctype.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 
+struct alias_devname {
+       char devname[32];
+       struct list_head link;
+       struct list_head head;
+};
+
+struct alias_devid {
+       int devid;
+       struct device_node *node;
+       struct list_head link;
+};
+
+static LIST_HEAD(aliases_lookup);
+
 struct device_node *allnodes;
 struct device_node *of_chosen;
 
@@ -922,3 +937,170 @@ out_unlock:
 }
 #endif /* defined(CONFIG_OF_DYNAMIC) */
 
+/*
+ * get_alias_dev_name_id - Get device name and id from alias name
+ *
+ * an: The alias name passed in
+ * dn: The pointer used to return device name
+ *
+ * Returns device id which should be the number at the end of alias
+ * name, otherwise returns -1.
+ */
+static int get_alias_name_id(char *an, char *dn)
+{
+       int len = strlen(an);
+       char *end = an + len;
+
+       while (isdigit(*--end))
+               len--;
+
+       end++;
+       strncpy(dn, an, len);
+       dn[len] = '\0';
+
+       return strlen(end) ? simple_strtol(end, NULL, 10) : -1;
+}
+
+/*
+ * get_an_available_devid - Get an available devid for the given devname
+ *
+ * adn:        The pointer to the given alias_devname
+ *
+ * Returns the available devid
+ */
+static int get_an_available_devid(struct alias_devname *adn)
+{
+       int devid = 0;
+       struct alias_devid *adi;
+
+       while (1) {
+               bool used = false;
+               list_for_each_entry(adi, &adn->head, link) {
+                       if (adi->devid == devid) {
+                               used = true;
+                               break;
+                       }
+               }
+
+               if (!used)
+                       break;
+
+               devid++;
+       }
+
+       return devid;
+}
+
+/*
+ * of_scan_aliases - Scan all properties of aliases node and populate the
+ *                  global lookup table with the device name and id info
+ *
+ * Returns the number of aliases properties found, or error code in error case.
+ */
+int of_scan_aliases(void)
+{
+       struct device_node *aliases = of_find_node_by_name(NULL, "aliases");
+       struct property *pp;
+       struct alias_devname *adn;
+       struct alias_devid *adi;
+       int ret = 0;
+
+       if (!aliases) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       for (pp = aliases->properties; pp != NULL; pp = pp->next) {
+               bool found = false;
+               char devname[32];
+               int devid = get_alias_name_id(pp->name, devname);
+
+               /* We do not want to proceed this sentinel one */
+               if (!strcmp(pp->name, "name") && !strcmp(pp->value, "aliases"))
+                       break;
+
+               /* See if the devname already exists */
+               list_for_each_entry(adn, &aliases_lookup, link) {
+                       if (!strcmp(adn->devname, devname)) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               /*
+                * Create the entry for this devname if not found,
+                * and add it into aliases_lookup
+                */
+               if (!found) {
+                       adn = kzalloc(sizeof(*adn), GFP_KERNEL);
+                       if (!adn) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+
+                       strcpy(adn->devname, devname);
+                       INIT_LIST_HEAD(&adn->head);
+                       list_add_tail(&adn->link, &aliases_lookup);
+               }
+
+               /*
+                * Save the devid as one entry of the list for this
+                * specified devname
+                */
+               adi = kzalloc(sizeof(*adi), GFP_KERNEL);
+               if (!adi) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               adi->devid = (devid == -1) ? get_an_available_devid(adn) :
+                                            devid;
+               adi->node = of_find_node_by_path(pp->value);
+
+               list_add_tail(&adi->link, &adn->head);
+               ret++;
+       }
+
+out:
+       return ret;
+}
+
+/**
+ *     of_get_device_id - Get device id by looking up "aliases" node
+ *     @np:    Pointer to device node that asks for device id
+ *     @name:  The device alias name
+ *
+ *     Returns the device id if find it, else returns -ENODEV.
+ */
+int of_get_device_id(struct device_node *np, const char *name)
+{
+       struct alias_devname *adn;
+       struct alias_devid *adi;
+       bool found = false;
+       int ret;
+
+       list_for_each_entry(adn, &aliases_lookup, link) {
+               if (!strcmp(adn->devname, name)) {
+                       found = true;
+                       break;
+               }
+       }
+
+       if (!found) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       found = false;
+       list_for_each_entry(adi, &adn->head, link) {
+               if (np == adi->node) {
+                       found = true;
+                       break;
+               }
+       }
+
+       ret = found ? adi->devid : -ENODEV;
+out:
+       return ret;
+}
+EXPORT_SYMBOL(of_get_device_id);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 2769353..062639e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1225,43 +1265,33 @@ static int serial_imx_resume(struct platform_device 
*dev)
        return 0;
 }
 
 static int serial_imx_probe_dt(struct imx_port *sport,
                struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
-       const __be32 *line;
+       int line;
 
        if (!node)
                return -ENODEV;
 
-       line = of_get_property(node, "id", NULL);
-       if (!line)
+       line = of_get_device_id(node, "serial");
+       if (IS_ERR_VALUE(line))
                return -ENODEV;
 
-       sport->port.line = be32_to_cpup(line) - 1;
+       sport->port.line = line;
 
diff --git a/include/linux/of.h b/include/linux/of.h
index bfc0ed1..270c671 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -213,6 +213,9 @@ extern int of_parse_phandles_with_args(struct device_node 
*np,
        const char *list_name, const char *cells_name, int index,
        struct device_node **out_node, const void **out_args);
 
+extern int of_scan_aliases(void);
+extern int of_get_device_id(struct device_node *np, const char *name);
+
 extern int of_machine_is_compatible(const char *compat);
 
 extern int prom_add_property(struct device_node* np, struct property* prop);

-- 
Regards,
Shawn

_______________________________________________
devicetree-discuss mailing list
[email protected]
https://lists.ozlabs.org/listinfo/devicetree-discuss

Reply via email to