lkml.org 
[lkml]   [2014]   [Jun]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 25/36] ARM: OMAP2+: gpmc: Support multiple Chip Selects per device
    Date
    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@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


    \
     
     \ /
      Last update: 2014-06-11 11:41    [W:3.123 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site