RE: [PATCH 9/9] OMAP:GPIO: Implement GPIO as a platform device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Original Message-----
> From: Kevin Hilman [mailto:khilman@xxxxxxxxxxxxxxxxxxx]
> Sent: Thursday, May 06, 2010 2:30 AM
> To: Varadarajan, Charulatha
> Cc: linux-omap@xxxxxxxxxxxxxxx; Nayak, Rajendra; paul@xxxxxxxxx; tony@xxxxxxxxxxx
> Subject: Re: [PATCH 9/9] OMAP:GPIO: Implement GPIO as a platform device
>
> "Varadarajan, Charulatha" <charu@xxxxxx> writes:
>
> >> -----Original Message-----
> >> From: Kevin Hilman [mailto:khilman@xxxxxxxxxxxxxxxxxxx]
> >> Sent: Saturday, May 01, 2010 5:34 AM
> >> To: Varadarajan, Charulatha
> >> Cc: linux-omap@xxxxxxxxxxxxxxx; Nayak, Rajendra; paul@xxxxxxxxx;
> tony@xxxxxxxxxxx
> >> Subject: Re: [PATCH 9/9] OMAP:GPIO: Implement GPIO as a platform device
> >>
> >> Charulatha V <charu@xxxxxx> writes:
> >>
> >> > This patch implements GPIO as a early platform device. Also it
> >> > implements OMAP2PLUS specific GPIO as HWMOD FW adapted driver.
> >>
> >> Should include a summary explanation of why you're converting to an
> >> early platform device as well.
> >
> > Okay.
> >
> >>
> >> > Inorder to convert GPIO as platform device, modifications are
> >> > required in clockxxxx_data.c files so that device names can be
> >> > used to obtain clock instead of getting clocks by name/NULL ptr.
> >>
> >> ok
> >>
> >> > Currently early platform device register does not do device_pm_init.
> >> > Hence pm_runtime functions are not used to enable the GPIO device
> >> > since gpio is early platform device.
> >>
> >> OK for now, since this isn't using runtime PM, but maybe we need a
> >> late_initcall() here to do the device_pm_init() + pm_runtime_enable()
> >>
> >> This change log needs more description of the intended init sequence.
> >> Right now it seems that there are multiple init paths.  Now that GPIO
> >> is an early_platform_device, we should be able to at least make
> >> omap_gpio_init() static and remove its usage from all the board files.
> >
> > This was the implementation that I initially did in my previous patch
> > series. The following needs to be considered:
> >
> > 1. omap2_init_devices() might be too late for early_gpio_init() to
> > be placed in it.
> >
> > 2. omap_init_irq() needs to be completed before calling early_gpio_init().
> > So, if early_gpio_init() is called from omap2_init_common_hw(), we need to
> > have omap_init_irq() called before omap2_init_common_hw(). But Tony
> > objected this approach mentioning that board might not boot up as
> > omap2_init_common_hw() has to be done asap.
> >
> > That's why, I had not moved the omap_gpio_init() usage from board files.
>
> OK... for now.  I'd still like to see GPIO init consolidated as there's
> no (good) reason why every board file has to init GPIOs when it's common
> for all SoCs, but this doesn't necessarily have to be done in your series.
> Although, if you do it for OMAP1 (as proposed below) you should do similar
> for OMAP2+.

Okay. Will use arch/subsys_initcall for starting the GPIO as per Tony's
suggestion.

>
> >>
> >> Also, the driver and device separation and init is totally mixed
> >> together and very confusing. The platform_driver is in
> >
> > Agreed. Please see my comment at the end of this patch in reply to your
> > other similar comment.
> >
> >
> >> plat-omap/gpio.c and should be doing the driver init:
> >> [early_]platform_driver_register() and _probe(). The platform_device
> >> setup is in mach-omapX/gpio*.c and where the device init should be, in
> >> this case early_platform_add_devices().
> >
> > In early_gpio_init, omap_device_build() (device specific) and
> > early_platform_driver_register_all() (driver specific), _probe() are
> > done in a sequence. This is because early_gpio_init needs to be called
> > asap and if we try to split this device specific and driver specific
> > early_inits, we will end up having two init calls for each early drivers.
> >
> > I feel that multiple function calls for early_init (one for driver probe and
> > one for device register) should be avoided as we need to find the right place
> > to call them.
>
> But your driver probe is already in a separate init path (via
> arch_initcall) from your device init path omap_gpio_init().
>
> My problem is that there is a 2nd driver init path:
> board file -> [driver]omap_gpio_init() -> [device] <soc>_gpio_init()
>
> The fact that it goes through the driver is what I don't like.
>

Okay.

> >>
> >>
> >> > Signed-off-by: Charulatha V <charu@xxxxxx>
> >> > Signed-off-by: Rajendra Nayak <rnayak@xxxxxx>
> >> > ---
> >> >  arch/arm/mach-omap1/Makefile           |    6 +
> >> >  arch/arm/mach-omap1/clock_data.c       |    2 +-
> >> >  arch/arm/mach-omap2/Makefile           |    2 +-
> >> >  arch/arm/mach-omap2/clock2420_data.c   |   10 +-
> >> >  arch/arm/mach-omap2/clock2430_data.c   |   14 +-
> >> >  arch/arm/mach-omap2/clock3xxx_data.c   |   24 +-
> >> >  arch/arm/mach-omap2/clock44xx_data.c   |   24 +-
> >> >  arch/arm/plat-omap/gpio.c              |  405 ++++++++++++------------------
> --
> >> >  arch/arm/plat-omap/include/plat/gpio.h |   21 ++
> >> >  9 files changed, 220 insertions(+), 288 deletions(-)
> >>
> >> [...]
> >>
> >> > @@ -1621,6 +1501,34 @@ static void __init omap_gpio_show_rev(void)
> >> >   */
> >> >  static struct lock_class_key gpio_lock_class;
> >> >
> >> > +static int init_gpio_info(void)
> >> > +{
> >> > +   gpio_bank_bits = 32;
> >> > +
> >> > +   if (cpu_is_omap15xx()) {
> >> > +           gpio_bank_count = 2;
> >> > +           gpio_bank_bits = 16;
> >> > +   } else if (cpu_is_omap16xx()) {
> >> > +           gpio_bank_count = 5;
> >> > +           gpio_bank_bits = 16;
> >> > +   } else if (cpu_is_omap7xx())
> >> > +           gpio_bank_count = 7;
> >> > +   else if (cpu_is_omap242x())
> >> > +           gpio_bank_count = 4;
> >> > +   else if (cpu_is_omap243x())
> >> > +           gpio_bank_count = 5;
> >> > +   else if (cpu_is_omap34xx() || cpu_is_omap44xx())
> >> > +           gpio_bank_count = OMAP34XX_NR_GPIOS;
> >>
> >> Both the bank count and bank bits could be part of platform_data
> >> and set in the SoC specific init.  This is the GPIO driver part
> >> and we're trying to make this as SoC independent as possible.  Anytime
> >> you need to add a cpu_is* or #ifdef in this code indicates something
> >> that should be part of SoC specific init and passed in.
> >
> > bank count and bank bits are not specific to each device, but SoC specific.
> > Hence I did not consider passing it as part of platform_data, because this
> information would be duplicated across all devices in that SoC.
> >
> > It would be good if we have a way to pass the SoC specific data which is
> > common for all the devices rather than duplicating them by sending them via
> > platform_data.
> >
> > Anyways, I can move it to platform_data if there is no other way.
>
> Probably the right place for the SoC specifics is attached to the SoC
> specific hwmod using the dev_attr pointer.  That struct can then
> be passed in via platform_data.
>
> You can see how Thara did this for SmartReflex as an example.

Okay.

>
> >>
> >> > +   gpio_bank = kzalloc(gpio_bank_count * sizeof(struct gpio_bank),
> >> > +                           GFP_KERNEL);
> >> > +   if (!gpio_bank) {
> >> > +           pr_err("Memory allocation failed for gpio_bank\n");
> >> > +           return -ENOMEM;
> >> > +   }
> >> > +   return 0;
> >> > +}
> >> > +
> >> >  static void omap_gpio_mod_init(struct gpio_bank *bank, int id)
> >> >  {
> >> >     if (cpu_class_is_omap2()) {
> >> > @@ -1686,16 +1594,9 @@ static void omap_gpio_mod_init(struct gpio_bank *bank,
> >> int id)
> >> >
> >> >  static void __init omap_gpio_chip_init(struct gpio_bank *bank)
> >> >  {
> >> > -   int j, gpio_bank_bits = 16;
> >> > +   int j;
> >> >     static int gpio;
> >> >
> >> > -   if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX)
> >> > -           gpio_bank_bits = 32; /* 7xx has 32-bit GPIOs */
> >> > -
> >> > -   if ((bank->method == METHOD_GPIO_24XX) ||
> >> > -                   (bank->method == METHOD_GPIO_44XX))
> >> > -           gpio_bank_bits = 32;
> >> > -
> >> >     bank->mod_usage = 0;
> >> >     /* REVISIT eventually switch from OMAP-specific gpio structs
> >> >      * over to the generic ones
> >> > @@ -1737,140 +1638,103 @@ static void __init omap_gpio_chip_init(struct
> >> gpio_bank *bank)
> >> >     set_irq_data(bank->irq, bank);
> >> >  }
> >> >
> >> > -static int __init _omap_gpio_init(void)
> >> > +static inline void get_gpio_dbck(struct platform_device *pdev,
> >> > +                           struct gpio_bank *bank)
> >> >  {
> >> > -   int i;
> >> > -   int gpio = 0;
> >> > +   if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
> >> > +           bank->dbck = clk_get(&pdev->dev, "dbck");
> >> > +           if (IS_ERR(bank->dbck))
> >> > +                   pr_err("GPIO: Could not get dbck\n");
> >> > +   }
> >> > +}
> >> > +static int __devinit omap_gpio_probe(struct platform_device *pdev)
> >> > +{
> >> > +   static int gpio_init_done;
> >> > +   struct omap_gpio_platform_data *pdata;
> >> > +   int id;
> >> >     struct gpio_bank *bank;
> >> > -   int bank_size = SZ_8K;  /* Module 4KB + L4 4KB except on omap1 */
> >> > -   char clk_name[11];
> >> > +   struct resource *res;
> >> >
> >> > -   initialized = 1;
> >> > +   if (!gpio_init_done)
> >> > +           init_gpio_info();
> >> >
> >> > -#if defined(CONFIG_ARCH_OMAP1)
> >> > -   if (cpu_is_omap15xx()) {
> >> > -           gpio_ick = clk_get(NULL, "arm_gpio_ck");
> >> > -           if (IS_ERR(gpio_ick))
> >> > -                   printk("Could not get arm_gpio_ck\n");
> >> > -           else
> >> > -                   clk_enable(gpio_ick);
> >> > +   if (!pdev || !pdev->dev.platform_data) {
> >> > +           pr_err("GPIO device initialize without"
> >> > +                                   "platform data\n");
> >> > +           return -EINVAL;
> >> >     }
> >> > -#endif
> >> > -#if defined(CONFIG_ARCH_OMAP2)
> >> > -   if (cpu_class_is_omap2()) {
> >> > -           gpio_ick = clk_get(NULL, "gpios_ick");
> >> > -           if (IS_ERR(gpio_ick))
> >> > -                   printk("Could not get gpios_ick\n");
> >> > -           else
> >> > -                   clk_enable(gpio_ick);
> >> > -           gpio_fck = clk_get(NULL, "gpios_fck");
> >> > -           if (IS_ERR(gpio_fck))
> >> > -                   printk("Could not get gpios_fck\n");
> >> > -           else
> >> > -                   clk_enable(gpio_fck);
> >> >
> >> > -           /*
> >> > -            * On 2430 & 3430 GPIO 5 uses CORE L4 ICLK
> >> > -            */
> >> > -#if defined(CONFIG_ARCH_OMAP2430)
> >> > -           if (cpu_is_omap2430()) {
> >> > -                   gpio5_ick = clk_get(NULL, "gpio5_ick");
> >> > -                   if (IS_ERR(gpio5_ick))
> >> > -                           printk("Could not get gpio5_ick\n");
> >> > -                   else
> >> > -                           clk_enable(gpio5_ick);
> >> > -                   gpio5_fck = clk_get(NULL, "gpio5_fck");
> >> > -                   if (IS_ERR(gpio5_fck))
> >> > -                           printk("Could not get gpio5_fck\n");
> >> > -                   else
> >> > -                           clk_enable(gpio5_fck);
> >> > -           }
> >> > -#endif
> >> > -   }
> >> > -#endif
> >> > +   pdata = pdev->dev.platform_data;
> >> >
> >> > -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
> >> > -   if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
> >> > -           for (i = 0; i < OMAP34XX_NR_GPIOS; i++) {
> >> > -                   sprintf(clk_name, "gpio%d_ick", i + 1);
> >> > -                   gpio_iclks[i] = clk_get(NULL, clk_name);
> >> > -                   if (IS_ERR(gpio_iclks[i]))
> >> > -                           printk(KERN_ERR "Could not get %s\n", clk_name);
> >> > -                   else
> >> > -                           clk_enable(gpio_iclks[i]);
> >> > -           }
> >> > +   id = pdev->id;
> >> > +   if (id > gpio_bank_count) {
> >> > +           pr_err("Invalid GPIO device id (%d)\n", id);
> >> > +           return -EINVAL;
> >> >     }
> >> > -#endif
> >> >
> >> > +   bank = &gpio_bank[id];
> >> >
> >> > -#ifdef CONFIG_ARCH_OMAP15XX
> >> > -   if (cpu_is_omap15xx()) {
> >> > -           gpio_bank_count = 2;
> >> > -           gpio_bank = gpio_bank_1510;
> >> > -           bank_size = SZ_2K;
> >> > -   }
> >> > -#endif
> >> > -#if defined(CONFIG_ARCH_OMAP16XX)
> >> > -   if (cpu_is_omap16xx()) {
> >> > -           gpio_bank_count = 5;
> >> > -           gpio_bank = gpio_bank_1610;
> >> > -           bank_size = SZ_2K;
> >> > -   }
> >> > -#endif
> >> > -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
> >> > -   if (cpu_is_omap7xx()) {
> >> > -           gpio_bank_count = 7;
> >> > -           gpio_bank = gpio_bank_7xx;
> >> > -           bank_size = SZ_2K;
> >> > -   }
> >> > -#endif
> >> > -#ifdef CONFIG_ARCH_OMAP2
> >> > -   if (cpu_is_omap242x()) {
> >> > -           gpio_bank_count = 4;
> >> > -           gpio_bank = gpio_bank_242x;
> >> > -   }
> >> > -   if (cpu_is_omap243x()) {
> >> > -           gpio_bank_count = 5;
> >> > -           gpio_bank = gpio_bank_243x;
> >> > -   }
> >> > -#endif
> >> > -#ifdef CONFIG_ARCH_OMAP3
> >> > -   if (cpu_is_omap34xx()) {
> >> > -           gpio_bank_count = OMAP34XX_NR_GPIOS;
> >> > -           gpio_bank = gpio_bank_34xx;
> >> > +   if (bank->initialized == 1) {
> >>
> >> is_early_platform_device() can be used to tell if the _probe() is
> >> being called as part of early platform driver probe or "regular".
> >
> > Okay.
> >
> >>
> >> > +           /*
> >> > +            * Currently, for early platform_devices,
> >> > +            * clk_get() using dev ptr does not seem to be working
> >> > +            * Hence getting dbck during regular device probe
> >> > +            */
> >>
> >> Need a better explanation here.  "does not seem to work" is not
> >> quite good enough.
> >
> > Okay.
> > The reason for "does not seem to work" is that device_initialize()
> > is not called as part of omap_early_device_register and the clk_get
> > could not find the clock using dev pointer.
>
> OK, should be as part of this comment if you keep it here.
>
> >>
> >> > +           get_gpio_dbck(pdev, bank);
> >>
> >> In any case, maybe it's better to defer the clk_get() into
> >> the debounce setup and only use if needed.
> >
> > Then, this needs to be done only in omap_set_gpio_debounce() which does
> > not have pdev->dev info. I can take care of this.
>
> OK good. That's probably cleaner than doing it at init time anyways.
>
> >>
> >> > +           return 0;
> >> >     }
> >> > -#endif
> >> > -#ifdef CONFIG_ARCH_OMAP4
> >> > -   if (cpu_is_omap44xx()) {
> >> > -           gpio_bank_count = OMAP34XX_NR_GPIOS;
> >> > -           gpio_bank = gpio_bank_44xx;
> >> > +
> >> > +   res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> >> > +   if (unlikely(!res)) {
> >> > +           pr_err("GPIO Bank %i Invalid IRQ resource\n", id);
> >> > +           return -ENODEV;
> >> >     }
> >> > -#endif
> >> > -   for (i = 0; i < gpio_bank_count; i++) {
> >> > +   bank->irq = res->start;
> >> > +   bank->virtual_irq_start = pdata->virtual_irq_start;
> >> > +   bank->base = pdata->base;
> >>
> >> Why are you using pdata->base for OMAP2+ base addresses...
> > Thanks for pointing this. I will correct it.
> >
> >>
> >> > +   bank->method = pdata->method;
> >> >
> >> > -           bank = &gpio_bank[i];
> >> > -           spin_lock_init(&bank->lock);
> >> > +   spin_lock_init(&bank->lock);
> >> >
> >> > +   if (cpu_class_is_omap2()) {
> >> > +           bank->device_enable = pdata->device_enable;
> >> > +           bank->device_idle = pdata->device_idle;
> >> > +           bank->device_shutdown = pdata->device_shutdown;
> >> > +           pdata->device_enable(pdev);
> >> > +   } else if (cpu_class_is_omap1()) {
> >> >             /* Static mapping, never released */
> >> > -           bank->base = ioremap(bank->pbase, bank_size);
> >> > -           if (!bank->base) {
> >> > -                   printk(KERN_ERR "Could not ioremap gpio bank%i\n", i);
> >> > -                   continue;
> >> > +           res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>
> >> ... and doing it the right way here for OMAP1?
> >>
> >> platform_get_resource() should be used for both.
> >
> > Yes.
> >
> >>
> >> > +           if (unlikely(!res)) {
> >> > +                   pr_err("GPIO Bank %i Invalid mem resource\n", id);
> >> > +                   return -ENODEV;
> >> >             }
> >> >
> >> > -           omap_gpio_mod_init(bank, i);
> >> > -           omap_gpio_chip_init(bank);
> >> > +           bank->base = ioremap(res->start, resource_size(res));
> >> > +           if (!bank->base) {
> >> > +                   pr_err("Could not ioremap gpio bank%i\n", id);
> >> > +                   return -ENOMEM;
> >> > +           }
> >> >
> >> > -           if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
> >> > -                   sprintf(clk_name, "gpio%d_dbck", i + 1);
> >> > -                   bank->dbck = clk_get(NULL, clk_name);
> >> > -                   if (IS_ERR(bank->dbck))
> >> > -                           printk(KERN_ERR "Could not get %s\n", clk_name);
> >> > +           if (cpu_is_omap15xx() && (id == 0)) {
> >> > +                   static struct clk *gpio_clk;
> >> > +                   gpio_clk = clk_get(&pdev->dev, "arm_gpio_ck");
> >> > +                   if (IS_ERR(gpio_clk))
> >> > +                           pr_err("Could not get arm_gpio_ck\n");
> >> > +                   else
> >> > +                           clk_enable(gpio_clk);
> >> >             }
> >> >     }
> >> >
> >> > -   omap_gpio_show_rev();
> >> > +   omap_gpio_mod_init(bank, id);
> >> > +   omap_gpio_chip_init(bank);
> >> >
> >> > +   if (!gpio_init_done) {
> >> > +           omap_gpio_show_rev();
> >> > +           gpio_init_done = 1;
> >> > +   }
> >> > +
> >> > +   bank->initialized = 1;
> >>
> >> I think you can drop this flag, and use is_early_platform_device() if
> >> needed.
> >
> > Sure.
> >>
> >> >     return 0;
> >> >  }
> >> >
> >> > @@ -2210,16 +2074,42 @@ void omap_gpio_restore_context(void)
> >> >  }
> >> >  #endif
> >> >
> >> > -/*
> >> > - * This may get called early from board specific init
> >> > - * for boards that have interrupts routed via FPGA.
> >> > - */
> >> > +static struct platform_driver omap_gpio_driver = {
> >> > +   .probe          = omap_gpio_probe,
> >> > +   .driver         = {
> >> > +           .name   = "omap-gpio",
> >> > +   },
> >> > +};
> >> > +
> >> > +int __init omap_gpio_drv_reg(void)
> >> > +{
> >> > +   return platform_driver_register(&omap_gpio_driver);
> >> > +}
> >> > +
> >> > +early_platform_init("earlygpio", &omap_gpio_driver);
> >> > +
> >> >  int __init omap_gpio_init(void)
> >> >  {
> >> > -   if (!initialized)
> >> > -           return _omap_gpio_init();
> >> > -   else
> >> > +   int ret = 0;
> >> > +
> >> > +   if (initialized)
> >> >             return 0;
> >> > +
> >> > +#ifdef CONFIG_ARCH_OMAP1
> >> > +   if (cpu_is_omap7xx())
> >> > +           ret = omap7xx_gpio_init();
> >> > +   if (cpu_is_omap15xx())
> >> > +           ret = omap15xx_gpio_init();
> >> > +   if (cpu_is_omap16xx())
> >> > +           ret = omap16xx_gpio_init();
> >> > +#endif
> >> > +#ifdef CONFIG_ARCH_OMAP2PLUS
> >> > +   if (cpu_class_is_omap2())
> >> > +           ret = omap2_gpio_init();
> >> > +#endif
> >>
> >> No thanks.  driver init should not be calling device init.  The device
> >> init should have it's own initcall or be called by other early device
> >> init.
> >
> > Agreed. omap_gpio_init() does nothing but calling device_init().
> >
> > But having omap_gpio_init() isn't a problem for OMAP2+, whereas it
> > would break multi-omap build for OMAP1 because there are 3 files in
> > mach-omap1 for each omap.
> >
> > 1. I can club all the 3 gpio files in mach-omap1 in to one file
> > mach-omap1/gpio.c and use omap_gpio_init() in it. But the patch
> > size and file size might be much bigger as the platform_data for all
> > OMAP1 GPIO devices would be available in this file.
> >
> > 2. (or) While maintaining 3 different files for mach-omap1/gpio_xxx.c,
> > modify the board files (about 20 files) of mach-omap1 and make use
> > of SoC specific omap_gpio_init.
> >
> > 3. (or) Call gpio_init() from omap_init_common_hw() by removing the calls
> > from board files and do a cpu_is check (for mach-omap1) in it.
> >
> > Please suggest if we have any other ways to handle this and the better
> > way to handle this.
>
> I prefer 3.

Okay. New patch series would be posted in another 2 weeks.

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

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux