diff mbox

[03/11] gpio: davinci: Modify to platform driver

Message ID 1369206634-6778-4-git-send-email-avinashphilip@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

avinash philip May 22, 2013, 7:10 a.m. UTC
From: KV Sujith <sujithkv@ti.com>

Modify GPIO Davinci driver to be compliant to standard platform drivers.
The driver did not have platform driver structure or a probe. Instead,
had a davinci_gpio_setup() function which is called in the pure_init
sequence. The function also had dependency on davinci_soc_info structure
of the corresponding platform. For Device Tree(DT) implementation, we
need to get rid of the dependency on the davinci_soc_info structure.
Hence as a first stage of DT conversion, we implement a probe. Future
commits shall modify the probe to read platform related data from DT.

- Add platform_driver structure and driver register function for davinci
  GPIO driver. The driver registration is made to happen in
  postcore_initcall. This is required since machine init functions like
  da850_lcd_hw_init() make use of GPIO.
- Convert the davinci_gpio_setup() to davinci_gpio_probe().
- Remove access of members in soc_info structure. Instead, relevant data
  are taken from davinci_gpio_platform_data structure pointed by
  pdev->dev.platform_data.
- Change clk_get() to devm_clk_get() as devm_clk_get() is a device
  managed function and makes error handling simpler.
- Change pr_err to dev_err for ngpio error reporting.
- Arrange include files and variables in alphabetical order

Signed-off-by: KV Sujith <sujithkv@ti.com>
[avinashphilip@ti.com: Move global definition for "struct
davinci_gpio_controller" variable to local in probe and set it as driver
data.]
Signed-off-by: Philip Avinash <avinashphilip@ti.com>
---
 arch/arm/mach-davinci/include/mach/gpio-davinci.h |    2 +
 drivers/gpio/gpio-davinci.c                       |  121 +++++++++++++++------
 2 files changed, 87 insertions(+), 36 deletions(-)

Comments

Linus Walleij May 30, 2013, 6:12 p.m. UTC | #1
On Wed, May 22, 2013 at 9:10 AM, Philip Avinash <avinashphilip@ti.com> wrote:

Why not squash patch 1 into this patch?

Anyway, this bring us closer to the model of other drivers so:
Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij
Sekhar Nori June 11, 2013, 11:56 a.m. UTC | #2
On 5/22/2013 12:40 PM, Philip Avinash wrote:
> From: KV Sujith <sujithkv@ti.com>
> 
> Modify GPIO Davinci driver to be compliant to standard platform drivers.
> The driver did not have platform driver structure or a probe. Instead,
> had a davinci_gpio_setup() function which is called in the pure_init
> sequence. The function also had dependency on davinci_soc_info structure
> of the corresponding platform. For Device Tree(DT) implementation, we
> need to get rid of the dependency on the davinci_soc_info structure.
> Hence as a first stage of DT conversion, we implement a probe. Future
> commits shall modify the probe to read platform related data from DT.
> 
> - Add platform_driver structure and driver register function for davinci
>   GPIO driver. The driver registration is made to happen in
>   postcore_initcall. This is required since machine init functions like
>   da850_lcd_hw_init() make use of GPIO.
> - Convert the davinci_gpio_setup() to davinci_gpio_probe().
> - Remove access of members in soc_info structure. Instead, relevant data
>   are taken from davinci_gpio_platform_data structure pointed by
>   pdev->dev.platform_data.
> - Change clk_get() to devm_clk_get() as devm_clk_get() is a device
>   managed function and makes error handling simpler.
> - Change pr_err to dev_err for ngpio error reporting.
> - Arrange include files and variables in alphabetical order
> 
> Signed-off-by: KV Sujith <sujithkv@ti.com>
> [avinashphilip@ti.com: Move global definition for "struct
> davinci_gpio_controller" variable to local in probe and set it as driver
> data.]
> Signed-off-by: Philip Avinash <avinashphilip@ti.com>
> ---
>  arch/arm/mach-davinci/include/mach/gpio-davinci.h |    2 +
>  drivers/gpio/gpio-davinci.c                       |  121 +++++++++++++++------
>  2 files changed, 87 insertions(+), 36 deletions(-)
> 
> diff --git a/arch/arm/mach-davinci/include/mach/gpio-davinci.h b/arch/arm/mach-davinci/include/mach/gpio-davinci.h
> index 1fdd1fd..b325a1d 100644
> --- a/arch/arm/mach-davinci/include/mach/gpio-davinci.h
> +++ b/arch/arm/mach-davinci/include/mach/gpio-davinci.h
> @@ -60,6 +60,8 @@ struct davinci_gpio_controller {
>  	void __iomem		*set_data;
>  	void __iomem		*clr_data;
>  	void __iomem		*in_data;
> +	int			gpio_unbanked;
> +	unsigned		gpio_irq;
>  };
>  
>  /* The __gpio_to_controller() and __gpio_mask() functions inline to constants
> diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
> index d308955..08830aa 100644
> --- a/drivers/gpio/gpio-davinci.c
> +++ b/drivers/gpio/gpio-davinci.c
> @@ -11,10 +11,17 @@
>   */
>  
>  #include <linux/clk.h>
> +#include <linux/device.h>
>  #include <linux/errno.h>
>  #include <linux/gpio.h>
>  #include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/irqdomain.h>
>  #include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/platform_data/gpio-davinci.h>

> +#include <mach/gpio-davinci.h>

This include seems unnecessary.

>  
>  #include <asm/mach/irq.h>

While at it, you can get rid of this include and use <linux/irq.h> instead?

>  
> @@ -35,10 +42,9 @@ struct davinci_gpio_regs {
>  #define chip2controller(chip)	\
>  	container_of(chip, struct davinci_gpio_controller, chip)
>  
> -static struct davinci_gpio_controller ctlrs[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
>  static void __iomem *gpio_base;
>  
> -static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
> +static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio)
>  {
>  	void __iomem *ptr;
>  
> @@ -64,7 +70,7 @@ static inline struct davinci_gpio_regs __iomem *irq2regs(int irq)
>  		irq_get_chip_data(irq);
>  }
>  
> -static int __init davinci_gpio_irq_setup(void);
> +static int davinci_gpio_irq_setup(struct platform_device *pdev);
>  
>  static inline int __davinci_direction(struct gpio_chip *chip,
>  			unsigned offset, bool out, int value)
> @@ -127,33 +133,52 @@ static void davinci_gpio_set(struct gpio_chip *chip, unsigned offset,
>  	__raw_writel((1 << offset), value ? &regs->set_data : &regs->clr_data);
>  }
>  
> -static int __init davinci_gpio_setup(void)
> +static int davinci_gpio_probe(struct platform_device *pdev)
>  {
>  	int i, base;
>  	unsigned ngpio;
> -	struct davinci_soc_info *soc_info = &davinci_soc_info;
> +	struct davinci_gpio_controller *ctlrs;
> +	struct davinci_gpio_platform_data *pdata;
>  	struct davinci_gpio_regs *regs;
> +	struct device *dev = &pdev->dev;
> +	struct resource *res;
>  
> -	if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)
> -		return 0;
> +	pdata = dev->platform_data;
> +	if (!pdata) {
> +		dev_err(dev, "GPIO: No Platform Data Supplied\n");

dev_err should already tell that the error is coming from davinci-gpio
so no need to prefix GPIO: again.

> +		return -EINVAL;
> +	}
>  
>  	/*
>  	 * The gpio banks conceptually expose a segmented bitmap,
>  	 * and "ngpio" is one more than the largest zero-based
>  	 * bit index that's valid.
>  	 */
> -	ngpio = soc_info->gpio_num;
> +	ngpio = pdata->ngpio;
>  	if (ngpio == 0) {
> -		pr_err("GPIO setup:  how many GPIOs?\n");
> +		dev_err(dev, "GPIO Probe: how many GPIOs?\n");
>  		return -EINVAL;
>  	}
>  
>  	if (WARN_ON(DAVINCI_N_GPIO < ngpio))
>  		ngpio = DAVINCI_N_GPIO;
>  
> -	gpio_base = ioremap(soc_info->gpio_base, SZ_4K);
> -	if (WARN_ON(!gpio_base))
> +	ctlrs = devm_kzalloc(dev,
> +		ngpio * sizeof(struct davinci_gpio_controller), GFP_KERNEL);

Line break alignment needs fixing.

> +	if (!ctlrs) {
> +		dev_err(dev, "Memory alloc failed\n");
>  		return -ENOMEM;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (unlikely(!res)) {
> +		dev_err(dev, "Invalid mem resource\n");
> +		return -ENODEV;

-EBUSY is better if you cannot get the resource.

> +	}
> +
> +	gpio_base = devm_ioremap_resource(dev, res);
> +	if (!gpio_base)
> +		return -EADDRNOTAVAIL;

devm_ioremap_resource gives an error encoder pointer if it fails so
please use that instead of masking it.

>  
>  	for (i = 0, base = 0; base < ngpio; i++, base += 32) {
>  		ctlrs[i].chip.label = "DaVinci";
> @@ -179,13 +204,10 @@ static int __init davinci_gpio_setup(void)
>  		gpiochip_add(&ctlrs[i].chip);
>  	}
>  
> -	soc_info->gpio_ctlrs = ctlrs;

> -	soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);

You drop setting gpio_ctlrs_num here and don't introduce it anywhere
else in the patchset so in effect you render the inline gpio get/set API
useless. Looks like this initialization should be moved to platform code?

> -
> -	davinci_gpio_irq_setup();
> +	platform_set_drvdata(pdev, ctlrs);
> +	davinci_gpio_irq_setup(pdev);
>  	return 0;
>  }
> -pure_initcall(davinci_gpio_setup);
>  
>  /*
>   * We expect irqs will normally be set up as input pins, but they can also be
> @@ -297,14 +319,14 @@ static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
>  
>  static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
>  {
> -	struct davinci_soc_info *soc_info = &davinci_soc_info;
> +	struct davinci_gpio_controller *ctlr = chip2controller(chip);
>  
>  	/*
>  	 * NOTE:  we assume for now that only irqs in the first gpio_chip
>  	 * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
>  	 */
> -	if (offset < soc_info->gpio_unbanked)
> -		return soc_info->gpio_irq + offset;
> +	if (offset < ctlr->irq_base)
> +		return ctlr->gpio_irq + offset;
>  	else
>  		return -ENODEV;
>  }
> @@ -313,12 +335,11 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
>  {
>  	struct davinci_gpio_controller *ctlr;
>  	struct davinci_gpio_regs __iomem *regs;
> -	struct davinci_soc_info *soc_info = &davinci_soc_info;
>  	u32 mask;
>  
>  	ctlr = (struct davinci_gpio_controller *)data->handler_data;
>  	regs = (struct davinci_gpio_regs __iomem *)ctlr->regs;
> -	mask = __gpio_mask(data->irq - soc_info->gpio_irq);
> +	mask = __gpio_mask(data->irq - ctlr->gpio_irq);
>  
>  	if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
>  		return -EINVAL;
> @@ -339,23 +360,33 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
>   * (dm6446) can be set appropriately for GPIOV33 pins.
>   */
>  
> -static int __init davinci_gpio_irq_setup(void)
> +static int davinci_gpio_irq_setup(struct platform_device *pdev)
>  {
> -	u32		binten = 0;
> -	unsigned	gpio, irq, bank, ngpio, bank_irq;
> -	struct clk	*clk;
> +	u32 binten = 0;
> +	unsigned gpio, irq, bank, ngpio, bank_irq;
> +	struct clk *clk;
> +	struct davinci_gpio_controller *ctlrs = platform_get_drvdata(pdev);
> +	struct davinci_gpio_platform_data *pdata;
>  	struct davinci_gpio_regs __iomem *regs;
> -	struct davinci_soc_info *soc_info = &davinci_soc_info;
> +	struct device *dev = &pdev->dev;
> +	struct resource *res;
> +
> +	pdata = dev->platform_data;
> +	ngpio = pdata->ngpio;
> +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	if (unlikely(!res)) {
> +		dev_err(dev, "Invalid IRQ resource\n");
> +		return -ENODEV;

-EBUSY again?

Thanks,
Sekhar
avinash philip June 11, 2013, 12:55 p.m. UTC | #3
On Tue, Jun 11, 2013 at 17:26:06, Nori, Sekhar wrote:
> 
> 
> On 5/22/2013 12:40 PM, Philip Avinash wrote:
> > From: KV Sujith <sujithkv@ti.com>
> > 
> > Modify GPIO Davinci driver to be compliant to standard platform drivers.
> > The driver did not have platform driver structure or a probe. Instead,
> > had a davinci_gpio_setup() function which is called in the pure_init
> > sequence. The function also had dependency on davinci_soc_info structure
> > of the corresponding platform. For Device Tree(DT) implementation, we
> > need to get rid of the dependency on the davinci_soc_info structure.
> > Hence as a first stage of DT conversion, we implement a probe. Future
> > commits shall modify the probe to read platform related data from DT.
> > 
> > - Add platform_driver structure and driver register function for davinci
> >   GPIO driver. The driver registration is made to happen in
> >   postcore_initcall. This is required since machine init functions like
> >   da850_lcd_hw_init() make use of GPIO.
> > - Convert the davinci_gpio_setup() to davinci_gpio_probe().
> > - Remove access of members in soc_info structure. Instead, relevant data
> >   are taken from davinci_gpio_platform_data structure pointed by
> >   pdev->dev.platform_data.
> > - Change clk_get() to devm_clk_get() as devm_clk_get() is a device
> >   managed function and makes error handling simpler.
> > - Change pr_err to dev_err for ngpio error reporting.
> > - Arrange include files and variables in alphabetical order
> > 
> > Signed-off-by: KV Sujith <sujithkv@ti.com>
> > [avinashphilip@ti.com: Move global definition for "struct
> > davinci_gpio_controller" variable to local in probe and set it as driver
> > data.]
> > Signed-off-by: Philip Avinash <avinashphilip@ti.com>
> > ---
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/platform_data/gpio-davinci.h>
> 
> > +#include <mach/gpio-davinci.h>
> 
> This include seems unnecessary.

This include is not required.

> 
> >  
> >  #include <asm/mach/irq.h>
> 
> While at it, you can get rid of this include and use <linux/irq.h> instead?

Ok

> 
> >  
> > +	pdata = dev->platform_data;
> > +	if (!pdata) {
> > +		dev_err(dev, "GPIO: No Platform Data Supplied\n");
> 
> dev_err should already tell that the error is coming from davinci-gpio
> so no need to prefix GPIO: again.

Ok

> 
> > +		return -EINVAL;
> > +	}
> > -	if (WARN_ON(!gpio_base))
> > +	ctlrs = devm_kzalloc(dev,
> > +		ngpio * sizeof(struct davinci_gpio_controller), GFP_KERNEL);
> 
> Line break alignment needs fixing.

Ok

> 
> > +	if (!ctlrs) {
> > +		dev_err(dev, "Memory alloc failed\n");
> >  		return -ENOMEM;
> > +	}
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (unlikely(!res)) {
> > +		dev_err(dev, "Invalid mem resource\n");
> > +		return -ENODEV;
> 
> -EBUSY is better if you cannot get the resource.

Ok

> 
> > +	}
> > +
> > +	gpio_base = devm_ioremap_resource(dev, res);
> > +	if (!gpio_base)
> > +		return -EADDRNOTAVAIL;
> 
> devm_ioremap_resource gives an error encoder pointer if it fails so
> please use that instead of masking it.

Ok

> 
> >  
> >  	for (i = 0, base = 0; base < ngpio; i++, base += 32) {
> >  		ctlrs[i].chip.label = "DaVinci";
> > @@ -179,13 +204,10 @@ static int __init davinci_gpio_setup(void)
> >  		gpiochip_add(&ctlrs[i].chip);
> >  	}
> >  
> > -	soc_info->gpio_ctlrs = ctlrs;
> 
> > -	soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
> 
> You drop setting gpio_ctlrs_num here and don't introduce it anywhere
> else in the patchset so in effect you render the inline gpio get/set API
> useless. Looks like this initialization should be moved to platform code?

With [PATCH 08/11] ARM: davinci: start using gpiolib support gpio get/set API
Has no more dependency on soc_info->gpio_ctlrs_num.

I can merge [PATCH 08/11] ARM: davinci: start using gpiolib support to
[PATCH 03/11] gpio: davinci: Modify to platform driver

> 
> > -

> > +	pdata = dev->platform_data;
> > +	ngpio = pdata->ngpio;
> > +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> > +	if (unlikely(!res)) {
> > +		dev_err(dev, "Invalid IRQ resource\n");
> > +		return -ENODEV;
> 
> -EBUSY again?

Ok

Thanks
Avinash

> 
> Thanks,
> Sekhar
>
Sekhar Nori June 12, 2013, 7:43 a.m. UTC | #4
On 6/11/2013 6:25 PM, Philip, Avinash wrote:

> On Tue, Jun 11, 2013 at 17:26:06, Nori, Sekhar wrote:

>> On 5/22/2013 12:40 PM, Philip Avinash wrote:

>>> @@ -179,13 +204,10 @@ static int __init davinci_gpio_setup(void)
>>>  		gpiochip_add(&ctlrs[i].chip);
>>>  	}
>>>  
>>> -	soc_info->gpio_ctlrs = ctlrs;
>>
>>> -	soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
>>
>> You drop setting gpio_ctlrs_num here and don't introduce it anywhere
>> else in the patchset so in effect you render the inline gpio get/set API
>> useless. Looks like this initialization should be moved to platform code?
> 
> With [PATCH 08/11] ARM: davinci: start using gpiolib support gpio get/set API
> Has no more dependency on soc_info->gpio_ctlrs_num.

With this series, you have removed support for inline gpio get/set API.
I see that the inline functions are still available for use on
tnetv107x. I wonder why it is important to keep these for tnetv107x when
not necessary for other DaVinci devices?

When you are removing this feature, please note it prominently in your
cover letter and patch description. Also, please provide some data on
how the latency now compares to that of inline access earlier. This is
important especially for the read. For the writes, gpio clock will
mostly determine how soon the value changes on the pin.

I am okay with removing the inline access feature. It helps simplify
code and most arm machines don't use them. I would just like to see some
data for justification as this can be seen as feature regression. Also,
if we are removing it, its better to also remove it completely and get
the LOC savings instead of just stopping its usage.

Thanks,
Sekhar
avinash philip June 12, 2013, 12:10 p.m. UTC | #5
On Wed, Jun 12, 2013 at 13:13:59, Nori, Sekhar wrote:
> On 6/11/2013 6:25 PM, Philip, Avinash wrote:
> 
> > On Tue, Jun 11, 2013 at 17:26:06, Nori, Sekhar wrote:
> 
> >> On 5/22/2013 12:40 PM, Philip Avinash wrote:
> 
> >>> @@ -179,13 +204,10 @@ static int __init davinci_gpio_setup(void)
> >>>  		gpiochip_add(&ctlrs[i].chip);
> >>>  	}
> >>>  
> >>> -	soc_info->gpio_ctlrs = ctlrs;
> >>
> >>> -	soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
> >>
> >> You drop setting gpio_ctlrs_num here and don't introduce it anywhere
> >> else in the patchset so in effect you render the inline gpio get/set API
> >> useless. Looks like this initialization should be moved to platform code?
> > 
> > With [PATCH 08/11] ARM: davinci: start using gpiolib support gpio get/set API
> > Has no more dependency on soc_info->gpio_ctlrs_num.
> 
> With this series, you have removed support for inline gpio get/set API.
> I see that the inline functions are still available for use on
> tnetv107x. I wonder why it is important to keep these for tnetv107x when
> not necessary for other DaVinci devices?

To support DT boot in da850, gpio davinci has to be converted to a driver and
remove references to davinci_soc_info from driver. But tnetv107x has 
separate GPIO driver and reference to davinci_soc_info can also be removed.
But I didn't found defconfig support for tnetv107x platforms and left untouched.
As I will not be able to build and test on tnetv107x, I prefer to not touch it.

> 
> When you are removing this feature, please note it prominently in your
> cover letter and patch description.

Ok

> Also, please provide some data on 
> how the latency now compares to that of inline access earlier. This is
> important especially for the read.

I am not sure whether I understood correctly or not? Meanwhile I had done
an experiment by reading printk timing before and after gpio_get_value from
a test module. I think this will help in software latency for inline access over
gpiolib specific access.

gpio_get_value latency testing code

+
+       local_irq_disable();
+       pr_emerg("%d %x\n", __LINE__, jiffies);
+       gpio_get_value(gpio_num);
+       pr_emerg("%d %x\n", __LINE__, jiffies);
+       local_irq_enable();

inline gpio functions with interrupt disabled
[   29.734337] 81 ffff966c
[   29.736847] 83 ffff966c

Time diff = 	0.00251

gpio library with interrupt disabled

[  272.876763] 81 fffff567
[  272.879291] 83 fffff567

Time diff =	0.002528

Inline function takes less time as expected.

> For the writes, gpio clock will
> mostly determine how soon the value changes on the pin.
> 
> I am okay with removing the inline access feature. It helps simplify
> code and most arm machines don't use them. I would just like to see some
> data for justification as this can be seen as feature regression. Also,
> if we are removing it, its better to also remove it completely and get
> the LOC savings instead of just stopping its usage.

I see build failure with below patch for tnetv107x
[v6,6/6] Davinci: tnetv107x default configuration 

So I prefer to leave tnetv107x platform for now.

Thanks
Avinash

>
Sekhar Nori June 13, 2013, 6:17 a.m. UTC | #6
On 6/12/2013 5:40 PM, Philip, Avinash wrote:
> On Wed, Jun 12, 2013 at 13:13:59, Nori, Sekhar wrote:
>> On 6/11/2013 6:25 PM, Philip, Avinash wrote:
>>
>>> On Tue, Jun 11, 2013 at 17:26:06, Nori, Sekhar wrote:
>>
>>>> On 5/22/2013 12:40 PM, Philip Avinash wrote:
>>
>>>>> @@ -179,13 +204,10 @@ static int __init davinci_gpio_setup(void)
>>>>>  		gpiochip_add(&ctlrs[i].chip);
>>>>>  	}
>>>>>  
>>>>> -	soc_info->gpio_ctlrs = ctlrs;
>>>>
>>>>> -	soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
>>>>
>>>> You drop setting gpio_ctlrs_num here and don't introduce it anywhere
>>>> else in the patchset so in effect you render the inline gpio get/set API
>>>> useless. Looks like this initialization should be moved to platform code?
>>>
>>> With [PATCH 08/11] ARM: davinci: start using gpiolib support gpio get/set API
>>> Has no more dependency on soc_info->gpio_ctlrs_num.
>>
>> With this series, you have removed support for inline gpio get/set API.
>> I see that the inline functions are still available for use on
>> tnetv107x. I wonder why it is important to keep these for tnetv107x when
>> not necessary for other DaVinci devices?
> 
> To support DT boot in da850, gpio davinci has to be converted to a driver and
> remove references to davinci_soc_info from driver. But tnetv107x has 
> separate GPIO driver and reference to davinci_soc_info can also be removed.
> But I didn't found defconfig support for tnetv107x platforms and left untouched.
> As I will not be able to build and test on tnetv107x, I prefer to not touch it.

You can always build it by enabling it in menuconfig. Its an ARMv6
platform so you will have to disable other ARMv5 based platforms from
while enabling it. ARMv5 and ARMv6 cannot co-exist in the same image.

> 
>>
>> When you are removing this feature, please note it prominently in your
>> cover letter and patch description.
> 
> Ok
> 
>> Also, please provide some data on 
>> how the latency now compares to that of inline access earlier. This is
>> important especially for the read.
> 
> I am not sure whether I understood correctly or not? Meanwhile I had done
> an experiment by reading printk timing before and after gpio_get_value from
> a test module. I think this will help in software latency for inline access over
> gpiolib specific access.
> 
> gpio_get_value latency testing code
> 
> +
> +       local_irq_disable();
> +       pr_emerg("%d %x\n", __LINE__, jiffies);
> +       gpio_get_value(gpio_num);
> +       pr_emerg("%d %x\n", __LINE__, jiffies);
> +       local_irq_enable();
> 
> inline gpio functions with interrupt disabled
> [   29.734337] 81 ffff966c
> [   29.736847] 83 ffff966c
> 
> Time diff = 	0.00251
> 
> gpio library with interrupt disabled
> 
> [  272.876763] 81 fffff567
> [  272.879291] 83 fffff567
> 
> Time diff =	0.002528
> 
> Inline function takes less time as expected.

Okay, please note these experiments in your cover letter. Its an 18usec
difference. I have no reference to say if that will affect any
application, but it will at least serve as information for someone who
may get affected by it.

> 
>> For the writes, gpio clock will
>> mostly determine how soon the value changes on the pin.
>>
>> I am okay with removing the inline access feature. It helps simplify
>> code and most arm machines don't use them. I would just like to see some
>> data for justification as this can be seen as feature regression. Also,
>> if we are removing it, its better to also remove it completely and get
>> the LOC savings instead of just stopping its usage.
> 
> I see build failure with below patch for tnetv107x
> [v6,6/6] Davinci: tnetv107x default configuration 

Where is this patch? What is the commit-id if it is in mainline? Where
is the failure log?

> 
> So I prefer to leave tnetv107x platform for now.

I don't think that's acceptable. At least by me.

Thanks,
Sekhar
diff mbox

Patch

diff --git a/arch/arm/mach-davinci/include/mach/gpio-davinci.h b/arch/arm/mach-davinci/include/mach/gpio-davinci.h
index 1fdd1fd..b325a1d 100644
--- a/arch/arm/mach-davinci/include/mach/gpio-davinci.h
+++ b/arch/arm/mach-davinci/include/mach/gpio-davinci.h
@@ -60,6 +60,8 @@  struct davinci_gpio_controller {
 	void __iomem		*set_data;
 	void __iomem		*clr_data;
 	void __iomem		*in_data;
+	int			gpio_unbanked;
+	unsigned		gpio_irq;
 };
 
 /* The __gpio_to_controller() and __gpio_mask() functions inline to constants
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index d308955..08830aa 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -11,10 +11,17 @@ 
  */
 
 #include <linux/clk.h>
+#include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/gpio-davinci.h>
+#include <mach/gpio-davinci.h>
 
 #include <asm/mach/irq.h>
 
@@ -35,10 +42,9 @@  struct davinci_gpio_regs {
 #define chip2controller(chip)	\
 	container_of(chip, struct davinci_gpio_controller, chip)
 
-static struct davinci_gpio_controller ctlrs[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
 static void __iomem *gpio_base;
 
-static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
+static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio)
 {
 	void __iomem *ptr;
 
@@ -64,7 +70,7 @@  static inline struct davinci_gpio_regs __iomem *irq2regs(int irq)
 		irq_get_chip_data(irq);
 }
 
-static int __init davinci_gpio_irq_setup(void);
+static int davinci_gpio_irq_setup(struct platform_device *pdev);
 
 static inline int __davinci_direction(struct gpio_chip *chip,
 			unsigned offset, bool out, int value)
@@ -127,33 +133,52 @@  static void davinci_gpio_set(struct gpio_chip *chip, unsigned offset,
 	__raw_writel((1 << offset), value ? &regs->set_data : &regs->clr_data);
 }
 
-static int __init davinci_gpio_setup(void)
+static int davinci_gpio_probe(struct platform_device *pdev)
 {
 	int i, base;
 	unsigned ngpio;
-	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	struct davinci_gpio_controller *ctlrs;
+	struct davinci_gpio_platform_data *pdata;
 	struct davinci_gpio_regs *regs;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
 
-	if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)
-		return 0;
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_err(dev, "GPIO: No Platform Data Supplied\n");
+		return -EINVAL;
+	}
 
 	/*
 	 * The gpio banks conceptually expose a segmented bitmap,
 	 * and "ngpio" is one more than the largest zero-based
 	 * bit index that's valid.
 	 */
-	ngpio = soc_info->gpio_num;
+	ngpio = pdata->ngpio;
 	if (ngpio == 0) {
-		pr_err("GPIO setup:  how many GPIOs?\n");
+		dev_err(dev, "GPIO Probe: how many GPIOs?\n");
 		return -EINVAL;
 	}
 
 	if (WARN_ON(DAVINCI_N_GPIO < ngpio))
 		ngpio = DAVINCI_N_GPIO;
 
-	gpio_base = ioremap(soc_info->gpio_base, SZ_4K);
-	if (WARN_ON(!gpio_base))
+	ctlrs = devm_kzalloc(dev,
+		ngpio * sizeof(struct davinci_gpio_controller), GFP_KERNEL);
+	if (!ctlrs) {
+		dev_err(dev, "Memory alloc failed\n");
 		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res)) {
+		dev_err(dev, "Invalid mem resource\n");
+		return -ENODEV;
+	}
+
+	gpio_base = devm_ioremap_resource(dev, res);
+	if (!gpio_base)
+		return -EADDRNOTAVAIL;
 
 	for (i = 0, base = 0; base < ngpio; i++, base += 32) {
 		ctlrs[i].chip.label = "DaVinci";
@@ -179,13 +204,10 @@  static int __init davinci_gpio_setup(void)
 		gpiochip_add(&ctlrs[i].chip);
 	}
 
-	soc_info->gpio_ctlrs = ctlrs;
-	soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
-
-	davinci_gpio_irq_setup();
+	platform_set_drvdata(pdev, ctlrs);
+	davinci_gpio_irq_setup(pdev);
 	return 0;
 }
-pure_initcall(davinci_gpio_setup);
 
 /*
  * We expect irqs will normally be set up as input pins, but they can also be
@@ -297,14 +319,14 @@  static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
 
 static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
 {
-	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	struct davinci_gpio_controller *ctlr = chip2controller(chip);
 
 	/*
 	 * NOTE:  we assume for now that only irqs in the first gpio_chip
 	 * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
 	 */
-	if (offset < soc_info->gpio_unbanked)
-		return soc_info->gpio_irq + offset;
+	if (offset < ctlr->irq_base)
+		return ctlr->gpio_irq + offset;
 	else
 		return -ENODEV;
 }
@@ -313,12 +335,11 @@  static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
 {
 	struct davinci_gpio_controller *ctlr;
 	struct davinci_gpio_regs __iomem *regs;
-	struct davinci_soc_info *soc_info = &davinci_soc_info;
 	u32 mask;
 
 	ctlr = (struct davinci_gpio_controller *)data->handler_data;
 	regs = (struct davinci_gpio_regs __iomem *)ctlr->regs;
-	mask = __gpio_mask(data->irq - soc_info->gpio_irq);
+	mask = __gpio_mask(data->irq - ctlr->gpio_irq);
 
 	if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
 		return -EINVAL;
@@ -339,23 +360,33 @@  static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
  * (dm6446) can be set appropriately for GPIOV33 pins.
  */
 
-static int __init davinci_gpio_irq_setup(void)
+static int davinci_gpio_irq_setup(struct platform_device *pdev)
 {
-	u32		binten = 0;
-	unsigned	gpio, irq, bank, ngpio, bank_irq;
-	struct clk	*clk;
+	u32 binten = 0;
+	unsigned gpio, irq, bank, ngpio, bank_irq;
+	struct clk *clk;
+	struct davinci_gpio_controller *ctlrs = platform_get_drvdata(pdev);
+	struct davinci_gpio_platform_data *pdata;
 	struct davinci_gpio_regs __iomem *regs;
-	struct davinci_soc_info *soc_info = &davinci_soc_info;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+
+	pdata = dev->platform_data;
+	ngpio = pdata->ngpio;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (unlikely(!res)) {
+		dev_err(dev, "Invalid IRQ resource\n");
+		return -ENODEV;
+	}
 
-	ngpio = soc_info->gpio_num;
+	bank_irq = res->start;
 
-	bank_irq = soc_info->gpio_irq;
-	if (bank_irq == 0) {
-		printk(KERN_ERR "Don't know first GPIO bank IRQ.\n");
-		return -EINVAL;
+	if (unlikely(!bank_irq)) {
+		dev_err(dev, "Invalid IRQ resource\n");
+		return -ENODEV;
 	}
 
-	clk = clk_get(NULL, "gpio");
+	clk = devm_clk_get(dev, "gpio");
 	if (IS_ERR(clk)) {
 		printk(KERN_ERR "Error %ld getting gpio clock?\n",
 		       PTR_ERR(clk));
@@ -371,8 +402,8 @@  static int __init davinci_gpio_irq_setup(void)
 	 */
 	for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) {
 		ctlrs[bank].chip.to_irq = gpio_to_irq_banked;
-		ctlrs[bank].irq_base = soc_info->gpio_unbanked ?
-			-EINVAL : (soc_info->intc_irq_num + gpio);
+		ctlrs[bank].irq_base = pdata->gpio_unbanked ?
+			-EINVAL : (pdata->intc_irq_num + gpio);
 	}
 
 	/*
@@ -380,7 +411,7 @@  static int __init davinci_gpio_irq_setup(void)
 	 * controller only handling trigger modes.  We currently assume no
 	 * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
 	 */
-	if (soc_info->gpio_unbanked) {
+	if (pdata->gpio_unbanked) {
 		static struct irq_chip_type gpio_unbanked;
 
 		/* pass "bank 0" GPIO IRQs to AINTC */
@@ -400,7 +431,7 @@  static int __init davinci_gpio_irq_setup(void)
 		__raw_writel(~0, &regs->set_rising);
 
 		/* set the direct IRQs up to use that irqchip */
-		for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
+		for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) {
 			irq_set_chip(irq, &gpio_unbanked.chip);
 			irq_set_handler_data(irq, &ctlrs[gpio / 32]);
 			irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
@@ -455,3 +486,21 @@  done:
 
 	return 0;
 }
+
+static struct platform_driver davinci_gpio_driver = {
+	.probe		= davinci_gpio_probe,
+	.driver		= {
+		.name	= "davinci_gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/**
+ * gpio driver register needs to be done before machine_init functions
+ * access gpio APIs. Hence davinci_gpio_drv_reg() is a postcore_initcall.
+ */
+static int __init davinci_gpio_drv_reg(void)
+{
+	return platform_driver_register(&davinci_gpio_driver);
+}
+postcore_initcall(davinci_gpio_drv_reg);