[PATCH 25/36] ARM: OMAP2+: gpmc: Support multiple Chip Selects per device

From: Roger Quadros
Date: Wed Jun 11 2014 - 04:59:00 EST


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 <rogerq@xxxxxx>
---
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/