From: Michael Bringmann <[email protected]>

Signed-off-by: Michael Bringmann <[email protected]>
---
 arch/arm/mach-axxia/i2c.c | 213 +++++++++++++++++++++++++++++++++-------------
 1 file changed, 156 insertions(+), 57 deletions(-)

diff --git a/arch/arm/mach-axxia/i2c.c b/arch/arm/mach-axxia/i2c.c
index ef90a5a..5f9eff3 100644
--- a/arch/arm/mach-axxia/i2c.c
+++ b/arch/arm/mach-axxia/i2c.c
@@ -23,11 +23,15 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/of_address.h>
 #include <linux/i2c.h>
 #include <linux/i2c-axxia.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
 
 #include <mach/irqs.h>
 
@@ -39,62 +43,110 @@
 
 static const char name[] = "axxia_ai2c";
 
-#define I2C_RESOURCE_BUILDER(base, irq)                        \
-       {                                               \
-               .start  = (base),                       \
-               .end    = (base) + AXXIA_I2C_SIZE,      \
-               .flags  = IORESOURCE_MEM,               \
-       },                                              \
-       {                                               \
-               .start  = (irq),                        \
-               .flags  = IORESOURCE_IRQ,               \
-       },
-
-        /* Filler values for now; real values will be filled in
-         * based on chip type / chip version / etc. */
-static struct resource i2c_resources[][2] = {
-       { I2C_RESOURCE_BUILDER(0, 0) },
-};
-
-#define I2C_DEV_BUILDER(bus_id, res, data)             \
-       {                                               \
-               .id     = (bus_id),                     \
-               .name   = name,                         \
-               .num_resources  = ARRAY_SIZE(res),      \
-               .resource       = (res),                \
-               .dev            = {                     \
-                       .platform_data  = (data),       \
-               },                                      \
-       }
 
-static struct axxia_i2c_bus_platform_data i2c_pdata[ARCH_AXXIA_MAX_I2C_BUSSES];
-static struct platform_device axxia_i2c_devices[ARCH_AXXIA_MAX_I2C_BUSSES] =
-{
-    I2C_DEV_BUILDER(ARCH_AXXIA_MAX_I2C_BUS_NR, i2c_resources[0], 
&i2c_pdata[0]),
-};
+static struct axxia_i2c_bus_platform_data       *axxia_i2cx_ports;
+static unsigned int                              axxia_i2cx_port_count;
+static struct platform_device                   *axxia_i2cx_devices;
+static struct platform_device                  **axxia_i2cx_device_ptrs;
 
 
 static inline
 int
 axxia_add_i2c_bus(
-    int         ndx,
-    int         bus_id)
+       struct device_node          *np,
+       struct platform_device      *pdev,
+       int                          ndx,
+       int                          bus_id)
 {
-    struct platform_device              *pdev;
-    struct axxia_i2c_bus_platform_data  *pdata;
-    struct resource                     *res;
+       struct axxia_i2c_bus_platform_data  *pdata;
+       const u32                            pval;
+       const char                          *val;
+       int                                  portno;
+
+       /* Get the port number from the device-tree */
+       if (!of_property_read_u32(np, "port", (u32 *)&pval)) {
+               portno = pval;
+       } else {
+               printk(KERN_ERR "I2C: Can't find port number for %s\n",
+                       np->full_name);
+               return -ENXIO;
+       }
+       if (portno > axxia_i2cx_port_count) {
+               printk(KERN_ERR "I2C: port number out of range for %s\n",
+                       np->full_name);
+               return -ENXIO;
+       }
+
+       pdata = &axxia_i2cx_ports[ndx];
+       pdata->node  = of_node_get(np);
+
+       pdata->index = portno;
+
+       /* Verify device type */
+       val = of_get_property(np, "device_type", NULL);
+       if (strcmp(val, "i2c")) {
+               printk(KERN_ERR "I2C%d: missing or incorrect device_type for 
%s\n",
+                       portno, np->full_name);
+               return -ENXIO;
+       }
+
+       /* Get or insert bus name */
+       val = of_get_property(np, "bus_name", NULL);
+       if (val)
+               strncpy(pdata->name, val, MAX_AXXIA_I2C_HWMOD_NAME_LEN);
+       else
+               sprintf(pdata->name, "i2c%d", portno);
 
-    pdev = &axxia_i2c_devices[ndx];
-    res = pdev->resource;
-    res[0].start = AXXIA1_I2C_BASE;
-    res[0].end = res[0].start + AXXIA_I2C_SIZE;
-    res[1].start = 0;           /* I2C interrup handle? */
-    pdata = &i2c_pdata[ndx];
+       pdata->rev = AXXIA_I2C_IP_VERSION_2;        /* AXM55xx */
 
-    pdata->rev = AXXIA_I2C_IP_VERSION_2;
-    pdata->flags = 0;
+       pdata->flags = AXXIA_I2C_FLAGS_NONE;
 
-    return platform_device_register(pdev);
+       /* Get the bus number from the device-tree */
+       if (!of_property_read_u32(np, "bus", (u32 *)&pval))
+               pdata->bus_nr = pval;
+       else
+               pdata->bus_nr = ~0;
+
+       /* Fetch config space registers address */
+       if (of_address_to_resource(np, 0, &pdata->dev_space)) {
+               printk(KERN_ERR "%s: Can't get I2C device space !",
+                       np->full_name);
+               return -ENXIO;
+       }
+       pdata->dev_space.flags = IORESOURCE_MEM;
+
+       /* Hookup an interrupt handler -- TBD, maybe later */
+       pdata->int_space.start = irq_of_parse_and_map(np, 0);
+       pdata->int_space.flags = IORESOURCE_IRQ;
+
+       if (pdata->bus_nr == ~0) {
+               printk(KERN_INFO
+                       "I2C Port %d found; bus#=<auto> '%s'\n",
+                       portno, pdata->name);
+       } else {
+               printk(KERN_INFO
+                       "I2C Port %d found; bus#=i%d '%s'\n",
+                       portno, pdata->bus_nr, pdata->name);
+       }
+       printk(KERN_INFO
+           "  dev_space start = 0x%012llx, end = 0x%012llx\n",
+           pdata->dev_space.start, pdata->dev_space.end);
+       printk(KERN_INFO
+           "  mappedIrq#=%x\n", (unsigned int)pdata->int_space.start);
+
+       /* Fill in the device */
+       pdev->id = ndx;
+       pdev->name = name;
+       pdev->num_resources = 2;
+       pdev->resource = &pdata->dev_space;
+       pdev->dev.platform_data = pdata;
+
+       /* printk(KERN_INFO
+           "pdev: id=%d name='%s' n_r=%d res=%p d.p_d=%p\n",
+           pdev->id, pdev->name, pdev->num_resources,
+           pdev->resource, pdev->dev.platform_data); */
+
+       return 0;
 }
 
 
@@ -105,17 +157,64 @@ axxia_add_i2c_bus(
  */
 int __init
 axxia_register_i2c_busses(
-    void)
+       void)
 {
-    int         i;
-    int         err;
-
-    for (i=0; i < ARCH_AXXIA_MAX_I2C_BUSSES; i++)
-    {
-        err = axxia_add_i2c_bus(i, i+ARCH_AXXIA_MAX_I2C_BUS_NR);
-        if (err)
-            return err;
-    }
+       int                 i;
+       int                 err;
+       struct device_node *np;
+
+       /* How many of these devices will be needed? */
+       axxia_i2cx_port_count = 0;
+       for_each_compatible_node(np, NULL, "lsi,api2c")
+               axxia_i2cx_port_count++;
+
+       if (axxia_i2cx_port_count == 0)
+               return -ENXIO;
+
+       /* Allocate memory */
+       axxia_i2cx_ports = kzalloc(axxia_i2cx_port_count*
+                                  sizeof(struct axxia_i2c_bus_platform_data),
+                                  GFP_KERNEL);
+       if (!axxia_i2cx_ports) {
+               printk(KERN_WARNING "I2C: failed to allocate ports array\n");
+               return -ENOMEM;
+       }
+       memset(axxia_i2cx_ports, 0,
+              axxia_i2cx_port_count*
+              sizeof(struct axxia_i2c_bus_platform_data));
+
+       axxia_i2cx_devices = kzalloc(axxia_i2cx_port_count*
+                                    sizeof(struct platform_device),
+                                    GFP_KERNEL);
+       if (!axxia_i2cx_devices) {
+               printk(KERN_WARNING "I2C: failed to allocate devices array\n");
+               return -ENOMEM;
+       }
+       memset(axxia_i2cx_devices, 0,
+              axxia_i2cx_port_count*sizeof(struct platform_device));
+
+       axxia_i2cx_device_ptrs = kzalloc(axxia_i2cx_port_count*
+                                        sizeof(struct platform_device *),
+                                        GFP_KERNEL);
+       if (!axxia_i2cx_device_ptrs) {
+               printk(KERN_WARNING
+                       "I2C: failed to allocate device ptrs array\n");
+               return -ENOMEM;
+       }
+       memset(axxia_i2cx_device_ptrs, 0,
+              axxia_i2cx_port_count*sizeof(struct platform_device *));
+
+       /* Now parse and fill in the device entries */
+       i = 0;
+       for_each_compatible_node(np, NULL, "lsi,api2c")
+       {
+           axxia_i2cx_device_ptrs[i] = &axxia_i2cx_devices[i];
+
+           err = axxia_add_i2c_bus(np, axxia_i2cx_device_ptrs[i],
+                                   i, i+ARCH_AXXIA_MAX_I2C_BUS_NR);
+           if (err == 0)
+               i++;
+       }
 
-    return 0;
+       return platform_add_devices(axxia_i2cx_device_ptrs, i);
 }
-- 
1.8.3

_______________________________________________
linux-yocto mailing list
[email protected]
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to