Platform will provide driver with configuration details for
each CS like configuration, timing, interrupts. Setup GPMC
based on it. Platform data also provides platform data &
resources used for connected peripheral (eg. gpio irq).
GPMC driver tunnels those information to respective driver.

Signed-off-by: Afzal Mohammed <af...@ti.com>
---
 arch/arm/mach-omap2/gpmc.c |  146 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 146 insertions(+)

diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9073a8a..281bd23 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -155,6 +155,8 @@ struct gpmc_peripheral {
        struct platform_device  *pdev;
 };
 
+static struct gpmc_peripheral gpmc_peripheral[GPMC_CS_NUM];
+static unsigned gpmc_num_peripheral;
 static unsigned gpmc_waitpin_map;
 
 static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ];
@@ -1235,6 +1237,39 @@ static int gpmc_setup_cs_waitpin(struct gpmc_peripheral 
*g_per, unsigned cs,
        return 0;
 }
 
+static int gpmc_setup_cs_config_timing(struct gpmc_peripheral *g_per,
+                                               struct gpmc_cs_data *cs)
+{
+       int ret;
+
+       /* some boards rely on bootloader for configuration */
+       if (cs->have_config) {
+               gpmc_setup_cs_config(cs->cs, cs->config);
+               ret = gpmc_setup_cs_waitpin(g_per, cs->cs, cs->config);
+               if (IS_ERR_VALUE(ret)) {
+                       dev_err(gpmc_dev, "error: waitpin on CS %d\n", cs->cs);
+                       return ret;
+               }
+       } else
+               gpmc_print_cs_config(cs->cs);
+
+       /* some boards rely on bootloader for timing */
+       if (cs->time_ctrl.type == has_period) {
+               ret = gpmc_cs_set_timings(cs->cs, &cs->time_ctrl.timings);
+               if (IS_ERR_VALUE(ret)) {
+                       dev_err(gpmc_dev, "error: timing on CS: %d\n", cs->cs);
+                       return ret;
+               }
+               gpmc_cs_misc_timings(cs->cs, &cs->time_ctrl.bool_timings);
+       } else if (cs->time_ctrl.type == has_clock) {
+               gpmc_cs_set_register_timings(cs->cs, &cs->time_ctrl.timings);
+               gpmc_cs_misc_timings(cs->cs, &cs->time_ctrl.bool_timings);
+       } else
+               gpmc_print_cs_timings(cs->cs);
+
+       return 0;
+}
+
 static inline unsigned gpmc_bit_to_irq(unsigned bitmask)
 {
        return bitmask;
@@ -1307,10 +1342,100 @@ static int gpmc_setup_waitpin(struct gpmc_peripheral 
*g_per)
        return 0;
 }
 
+static __devinit int gpmc_setup_cs(struct gpmc_peripheral *g_per,
+                               struct gpmc_cs_data *cs, struct resource *res)
+{
+       int num, ret;
+
+       num = gpmc_setup_cs_mem(cs, res);
+       if (IS_ERR_VALUE(num))
+               return num;
+
+       ret = gpmc_setup_cs_config_timing(g_per, cs);
+       if (IS_ERR_VALUE(ret))
+               return ret;
+
+       num += gpmc_setup_cs_irq(cs, res + num);
+
+       return num;
+}
+
+static __devinit int gpmc_setup_device(struct gpmc_peripheral *g_per,
+                                       struct gpmc_device_pdata *gdp)
+{
+       int i, n, ret;
+       struct gpmc_cs_data *cs;
+
+       for (i = 0, n = gdp->num_cs, cs = gdp->cs_data;
+                               i < gdp->num_cs; i++, cs++)
+               n += hweight32(cs->irq_config);
+
+       g_per->gpmc_res = devm_kzalloc(gpmc_dev, sizeof(*g_per->gpmc_res) * n,
+                                                               GFP_KERNEL);
+       if (g_per->gpmc_res == NULL) {
+               dev_err(gpmc_dev, "error: memory allocation\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0, cs = gdp->cs_data, g_per->gpmc_res_cnt = 0;
+                       i < gdp->num_cs; cs++, i++) {
+               ret = gpmc_setup_cs(g_per, cs,
+                                       g_per->gpmc_res + g_per->gpmc_res_cnt);
+               if (IS_ERR_VALUE(ret) ||
+                               IS_ERR_VALUE(gpmc_setup_waitpin(g_per))) {
+                       dev_err(gpmc_dev, "error: setup for %s\n", gdp->name);
+                       devm_kfree(gpmc_dev, g_per->gpmc_res);
+                       g_per->gpmc_res = NULL;
+                       g_per->gpmc_res_cnt = 0;
+                       return -EINVAL;
+               } else
+                       g_per->gpmc_res_cnt += ret;
+       }
+
+       g_per->name = gdp->name;
+       g_per->id = gdp->id;
+       g_per->pdata = gdp->pdata;
+       g_per->pdata_size = gdp->pdata_size;
+       g_per->per_res = gdp->per_res;
+       g_per->per_res_cnt = gdp->per_res_cnt;
+
+       return 0;
+}
+
+static __devinit
+struct platform_device *gpmc_create_device(struct gpmc_peripheral *p)
+{
+       int num = p->per_res_cnt + p->gpmc_res_cnt;
+       struct resource *res;
+       struct platform_device *pdev;
+
+       res = devm_kzalloc(gpmc_dev, sizeof(struct resource) * num,
+                                                               GFP_KERNEL);
+       if (!res) {
+               dev_err(gpmc_dev, "error: allocating memory\n");
+               return NULL;
+       }
+
+       memcpy((char *)res, (const char *) p->gpmc_res,
+                               sizeof(struct resource) * p->gpmc_res_cnt);
+       memcpy((char *)(res + p->gpmc_res_cnt), (const char *)p->per_res,
+                               sizeof(struct resource) * p->per_res_cnt);
+
+       p->pdev = platform_device_register_resndata(gpmc_dev, p->name, p->id,
+                                       res, num, p->pdata, p->pdata_size);
+
+       devm_kfree(gpmc_dev, res);
+
+       return pdev;
+}
+
 static __devinit int gpmc_probe(struct platform_device *pdev)
 {
        u32 l;
        struct resource *res;
+       struct gpmc_pdata *gp = dev_get_platdata(&pdev->dev);
+       struct gpmc_device_pdata **gdq = NULL;
+       struct gpmc_peripheral *g_per = NULL;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL)
@@ -1342,11 +1467,32 @@ static __devinit int gpmc_probe(struct platform_device 
*pdev)
        if (IS_ERR_VALUE(gpmc_setup_irq()))
                dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
 
+       /* Traverse NULL terminated array of peripheral pointers and setup */
+       for (gdq = gp->device_pdata, g_per = gpmc_peripheral; *gdq; gdq++)
+               if (IS_ERR_VALUE(gpmc_setup_device(g_per, *gdq)))
+                       dev_err(gpmc_dev, "gpmc setup on %s failed\n",
+                                                               (*gdq)->name);
+               else
+                       g_per++;
+       gpmc_num_peripheral = g_per - gpmc_peripheral;
+
+       for (l = 0, g_per = gpmc_peripheral;
+                       l < gpmc_num_peripheral; l++, g_per++)
+               if (IS_ERR(gpmc_create_device(g_per)))
+                       dev_err(gpmc_dev, "device creation on %s failed\n",
+                                                               g_per->name);
+
        return 0;
 }
 
 static __exit int gpmc_remove(struct platform_device *pdev)
 {
+       struct gpmc_peripheral *g_per = gpmc_peripheral;
+
+       for (; gpmc_num_peripheral; g_per++, gpmc_num_peripheral--)
+               platform_device_unregister(g_per->pdev);
+
+       gpmc_waitpin_map = 0;
        gpmc_free_irq();
        gpmc_mem_exit();
        gpmc_dev = NULL;
-- 
1.7.10.2

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

Reply via email to