Some devices (e.g. tusb6010) need 2 chip selects to work with
2 separate IOMEM resources. Allow such use case. The user just
needs to call gpmc_generic_init() for as many chip selects
with the same platform_device pointer. The GPMC driver will
take care of fixing up the memory resources.

Signed-off-by: Roger Quadros <rog...@ti.com>
---
 arch/arm/mach-omap2/gpmc.c | 134 ++++++++++++++++++++++++++++++---------------
 1 file changed, 91 insertions(+), 43 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 5563360..34545ca 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -1388,9 +1388,14 @@ static int gpmc_nand_setup(struct platform_device 
*parent_pdev,
 
 static void gpmc_probe_legacy(struct platform_device *pdev)
 {
-       int i, rc;
+       int i, rc, j;
        struct device *dev = &pdev->dev;
        struct gpmc_omap_platform_data *gpmc_pdata;
+       struct resource *mem_res;
+       unsigned long cs_base;
+       resource_size_t size;
+       struct gpmc_timings gpmc_timings;
+       struct gpmc_omap_cs_data *cs;
 
        gpmc_pdata = dev->platform_data;
        gpmc_cs_num = GPMC_CS_NUM;
@@ -1400,52 +1405,10 @@ static void gpmc_probe_legacy(struct platform_device 
*pdev)
                return;
 
        for (i = 0; i < GPMC_CS_NUM; i++) {
-               struct resource *mem_res;
-               unsigned long cs_base;
-               resource_size_t size;
-               struct gpmc_timings gpmc_timings;
-               struct gpmc_omap_cs_data *cs;
-
                cs = &gpmc_pdata->cs[i];
                if (!cs->valid)
                        continue;
 
-               /*
-                * Request a CS space. Use size from
-                * platform device's MEM resource
-                */
-               if (!cs->pdev)
-                       goto skip_mem;
-
-               mem_res = cs->pdev->resource;
-               if (cs->pdev->num_resources < 1 ||
-                   resource_type(mem_res) != IORESOURCE_MEM) {
-                       dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
-                       continue;
-               }
-
-               size = mem_res->end - mem_res->start + 1;
-               if (gpmc_cs_request(i, size, &cs_base)) {
-                       dev_err(dev, "Couldn't request resource for CS %d\n",
-                               i);
-                       continue;
-               }
-
-               mem_res->start = cs_base;
-               mem_res->end = cs_base + size - 1;
-
-               /* FIXME: When do we need to call gpmc_cs_remap()? */
-skip_mem:
-
-               /* Customized NAND setup */
-               if (cs->is_nand) {
-                       if (gpmc_nand_setup(pdev, cs)) {
-                               dev_err(dev, "Error setting up NAND on CS %d\n",
-                                       i);
-                               continue;
-                       }
-               }
-
                if (cs->settings) {
                        if (gpmc_cs_program_settings(i, cs->settings)) {
                                dev_err(dev,
@@ -1474,10 +1437,95 @@ skip_mem:
                                continue;
                        }
                }
+       }
+
+       /*
+        * All Chip Selects must be configured before platform devices are
+        * created as some devices (e.g. tusb6010) can use multiple
+        * Chip selects.
+        */
+
+       /* Fixup Memory resources */
+       for (i = 0; i < GPMC_CS_NUM; i++) {
+               int required_resources;
+
+               cs = &gpmc_pdata->cs[i];
+               if (!cs->valid)
+                       continue;
 
                if (!cs->pdev)
                        continue;
 
+               /* Customized NAND setup */
+               if (cs->is_nand) {
+                       if (gpmc_nand_setup(pdev, cs)) {
+                               dev_err(dev, "Error setting up NAND on CS %d\n",
+                                       i);
+                               continue;
+                       }
+               }
+
+               mem_res = cs->pdev->resource;
+
+               /*
+                * If device is present multiple times, fix the subsequent
+                * resources
+                */
+               required_resources = 1;
+               for (j = 0; j < i; j++) {
+                       if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+                               mem_res++;
+                               required_resources++;
+                       }
+               }
+
+               if (cs->pdev->num_resources < required_resources ||
+                   resource_type(mem_res) != IORESOURCE_MEM) {
+                       dev_err(dev, "Invalid IOMEM resource for CS %d\n", i);
+                       continue;
+               }
+
+               /*
+                * Request a CS space. Use size from
+                * platform device's MEM resource
+                */
+               size = mem_res->end - mem_res->start + 1;
+               if (gpmc_cs_request(i, size, &cs_base)) {
+                       dev_err(dev, "Couldn't request resource for CS %d\n",
+                               i);
+                       continue;
+               }
+
+               mem_res->start = cs_base;
+               mem_res->end = cs_base + size - 1;
+       }
+
+       /* create the platform devices */
+       for (i = 0; i < GPMC_CS_NUM; i++) {
+               bool registered;
+
+               cs = &gpmc_pdata->cs[i];
+               if (!cs->valid)
+                       continue;
+
+               if (!cs->pdev)
+                       continue;
+
+               /*
+                * same device can be present on multiple CS, don't
+                * register device more than once.
+                */
+               registered = false;
+               for (j = 0; j < i; j++) {
+                       if (gpmc_pdata->cs[j].pdev == cs->pdev) {
+                               registered = true;
+                               break;
+                       }
+               }
+
+               if (registered)
+                       continue;
+
                cs->pdev->dev.parent = dev;
                rc = platform_device_register(cs->pdev);
                if (rc < 0) {
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to