mfd: Make MFD core code Device Tree and IRQ domain aware
authorLee Jones <lee.jones@linaro.org>
Fri, 29 Jun 2012 17:01:03 +0000 (19:01 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Sun, 8 Jul 2012 22:16:08 +0000 (00:16 +0200)
During Device Tree enablement of the ab8500 and db8500-prcmu drivers,
a decision was made to omit registration through the MFD API and use
Device Tree directly. However, because MFD devices have a different
address space and the ab8500 and db8500 both use I2C to communicate,
this causes issues with address translation during execution of
of_platform_populate(). So the solution is to make the MFD core aware
of Device Tree and have it assign the correct node pointers instead.

To make this work the MFD core also needs to be awere of IRQ domains,
as Device Tree insists on IRQ domain compatibility. So, instead of
providing an irq-base via platform code, in the DT case we simply
look up the IRQ domain and map to the correct virtual IRQ.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/mfd/Kconfig
drivers/mfd/mfd-core.c
include/linux/mfd/core.h

index 8b56c1998ab2c88075a8f13e2a8a5450a3cdb8ae..d43876c6da23a83752fb12f33ff516fdd34e4cb3 100644 (file)
@@ -7,6 +7,7 @@ menu "Multifunction device drivers"
 
 config MFD_CORE
        tristate
+       select IRQ_DOMAIN
        default n
 
 config MFD_88PM860X
index ffc3d48676ae67c5c838700d212310025ec8f2da..0c3a01cde2f7615960fb2c9cc20ba7489bf00fbd 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
 
 int mfd_cell_enable(struct platform_device *pdev)
 {
@@ -76,6 +78,8 @@ static int mfd_add_device(struct device *parent, int id,
 {
        struct resource *res;
        struct platform_device *pdev;
+       struct device_node *np = NULL;
+       struct irq_domain *domain = NULL;
        int ret = -ENOMEM;
        int r;
 
@@ -89,6 +93,16 @@ static int mfd_add_device(struct device *parent, int id,
 
        pdev->dev.parent = parent;
 
+       if (parent->of_node && cell->of_compatible) {
+               for_each_child_of_node(parent->of_node, np) {
+                       if (of_device_is_compatible(np, cell->of_compatible)) {
+                               pdev->dev.of_node = np;
+                               domain = irq_find_host(parent->of_node);
+                               break;
+                       }
+               }
+       }
+
        if (cell->pdata_size) {
                ret = platform_device_add_data(pdev,
                                        cell->platform_data, cell->pdata_size);
@@ -112,10 +126,18 @@ static int mfd_add_device(struct device *parent, int id,
                        res[r].end = mem_base->start +
                                cell->resources[r].end;
                } else if (cell->resources[r].flags & IORESOURCE_IRQ) {
-                       res[r].start = irq_base +
-                               cell->resources[r].start;
-                       res[r].end   = irq_base +
-                               cell->resources[r].end;
+                       if (domain) {
+                               /* Unable to create mappings for IRQ ranges. */
+                               WARN_ON(cell->resources[r].start !=
+                                       cell->resources[r].end);
+                               res[r].start = res[r].end = irq_create_mapping(
+                                       domain, cell->resources[r].start);
+                       } else {
+                               res[r].start = irq_base +
+                                       cell->resources[r].start;
+                               res[r].end   = irq_base +
+                                       cell->resources[r].end;
+                       }
                } else {
                        res[r].parent = cell->resources[r].parent;
                        res[r].start = cell->resources[r].start;
index 4e76163dd8624dec3dba23b7bdebb32ce8ad2d11..99b7eb1961b6e50538d1f6a27d4a994ea87348a2 100644 (file)
@@ -36,6 +36,7 @@ struct mfd_cell {
        /* platform data passed to the sub devices drivers */
        void                    *platform_data;
        size_t                  pdata_size;
+       const char              *of_compatible;
 
        /*
         * These resources can be specified relative to the parent device.