diff mbox

[RFC] gpio: add GPIO hogging mechanism

Message ID 1387463671-1164-2-git-send-email-b.brezillon@overkiz.com
State Superseded, archived
Headers show

Commit Message

Boris Brezillon Dec. 19, 2013, 2:34 p.m. UTC
GPIO hogging is a way to request and configure specific GPIO without
explicitly requesting it in the device driver.

The request and configuration procedure is handled in the core device
driver code before the driver probe function is called.

It allows specific GPIOs to be configured without any driver specific code.

Particularly usefull when a external device is connected to a bus and the
bus connections depends on an external switch controlled by a GPIO pin.
Or when some GPIOs have to be exported to sysfs without any userspace
intervention.

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
---
 Documentation/devicetree/bindings/gpio/gpio.txt |   47 ++++++++
 drivers/base/Makefile                           |    1 +
 drivers/base/dd.c                               |    5 +
 drivers/base/gpio.c                             |   59 ++++++++++
 drivers/gpio/devres.c                           |   39 +++++++
 drivers/gpio/gpiolib-of.c                       |  134 +++++++++++++++++++++++
 drivers/gpio/gpiolib.c                          |  103 +++++++++++++++++
 include/linux/device.h                          |    5 +
 include/linux/gpio/consumer.h                   |   25 +++++
 include/linux/gpio/devinfo.h                    |   38 +++++++
 include/linux/of_gpio.h                         |   19 ++++
 11 files changed, 475 insertions(+)
 create mode 100644 drivers/base/gpio.c
 create mode 100644 include/linux/gpio/devinfo.h

Comments

Greg Kroah-Hartman Dec. 19, 2013, 4:41 p.m. UTC | #1
On Thu, Dec 19, 2013 at 03:34:31PM +0100, Boris BREZILLON wrote:
> GPIO hogging is a way to request and configure specific GPIO without
> explicitly requesting it in the device driver.
> 
> The request and configuration procedure is handled in the core device
> driver code before the driver probe function is called.
> 
> It allows specific GPIOs to be configured without any driver specific code.
> 
> Particularly usefull when a external device is connected to a bus and the
> bus connections depends on an external switch controlled by a GPIO pin.
> Or when some GPIOs have to be exported to sysfs without any userspace
> intervention.
> 
> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
> ---
>  Documentation/devicetree/bindings/gpio/gpio.txt |   47 ++++++++
>  drivers/base/Makefile                           |    1 +
>  drivers/base/dd.c                               |    5 +
>  drivers/base/gpio.c                             |   59 ++++++++++

I don't understand what makes GPIO's "special" enough to get included in
the driver core like this, and called for each and every device that is
added to the system.

What's wrong with the generic device callbacks/notifiers we already
have?  Why does this need to be in the driver core?  And what exactly
are you doing all of this for in the first place?

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Felipe Balbi Dec. 19, 2013, 4:47 p.m. UTC | #2
On Thu, Dec 19, 2013 at 08:41:09AM -0800, Greg Kroah-Hartman wrote:
> On Thu, Dec 19, 2013 at 03:34:31PM +0100, Boris BREZILLON wrote:
> > GPIO hogging is a way to request and configure specific GPIO without
> > explicitly requesting it in the device driver.
> > 
> > The request and configuration procedure is handled in the core device
> > driver code before the driver probe function is called.
> > 
> > It allows specific GPIOs to be configured without any driver specific code.
> > 
> > Particularly usefull when a external device is connected to a bus and the
> > bus connections depends on an external switch controlled by a GPIO pin.

for external switches, you probably need a pinctrl-gpio driver.
Boris Brezillon Dec. 19, 2013, 5:13 p.m. UTC | #3
Hello Greg,

On 19/12/2013 17:41, Greg Kroah-Hartman wrote:
> On Thu, Dec 19, 2013 at 03:34:31PM +0100, Boris BREZILLON wrote:
>> GPIO hogging is a way to request and configure specific GPIO without
>> explicitly requesting it in the device driver.
>>
>> The request and configuration procedure is handled in the core device
>> driver code before the driver probe function is called.
>>
>> It allows specific GPIOs to be configured without any driver specific code.
>>
>> Particularly usefull when a external device is connected to a bus and the
>> bus connections depends on an external switch controlled by a GPIO pin.
>> Or when some GPIOs have to be exported to sysfs without any userspace
>> intervention.
>>
>> Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
>> ---
>>   Documentation/devicetree/bindings/gpio/gpio.txt |   47 ++++++++
>>   drivers/base/Makefile                           |    1 +
>>   drivers/base/dd.c                               |    5 +
>>   drivers/base/gpio.c                             |   59 ++++++++++
> I don't understand what makes GPIO's "special" enough to get included in
> the driver core like this, and called for each and every device that is
> added to the system.


> What's wrong with the generic device callbacks/notifiers we already
> have?  Why does this need to be in the driver core?  And what exactly
> are you doing all of this for in the first place?

Nothing's wrong with the generic device callbacks/notifiers, but in some
cases we don't want a generic driver to handle board specificities.

This is the case for the at91rm9200ek board (see this thread:
https://www.mail-archive.com/devicetree@vger.kernel.org/msg06838.html).

Since we are moving all boards to dt, we can't configure each board at
startup, and the rm9200ek board used to set a pin to a specific value 
(this pin
is connected to an external switch which connects MMC signals to the MMC
connector or SPI signals to an SPI device depending on the pin value) in 
order
to enable the MMC0 port or an SPI device.

I first proposed to handle this using a pinctrl pinconf definition (with 
pinctrl
output-high config). As pinctrl are requesting pinconf before calling 
driver probe
function, this was absolutely transparent to the generic driver.
But, as Linus pointed out, this pin is not really related to the SPI or 
MMC device
itself.
This is why Linus suggested the GPIO hog approach.

Anyway, I'm open to any other solution that wouldn't introduce specific
cases in arch specific code or generic drivers.

Best Regards,

Boris
> greg k-h

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Boris Brezillon Dec. 19, 2013, 5:18 p.m. UTC | #4
Hello Felipe,

On 19/12/2013 17:47, Felipe Balbi wrote:
> On Thu, Dec 19, 2013 at 08:41:09AM -0800, Greg Kroah-Hartman wrote:
>> On Thu, Dec 19, 2013 at 03:34:31PM +0100, Boris BREZILLON wrote:
>>> GPIO hogging is a way to request and configure specific GPIO without
>>> explicitly requesting it in the device driver.
>>>
>>> The request and configuration procedure is handled in the core device
>>> driver code before the driver probe function is called.
>>>
>>> It allows specific GPIOs to be configured without any driver specific code.
>>>
>>> Particularly usefull when a external device is connected to a bus and the
>>> bus connections depends on an external switch controlled by a GPIO pin.
> for external switches, you probably need a pinctrl-gpio driver.
>
Do you mean using pinctrl pinconf to configure the PIN as output-high or
output-low ?

This was my first proposal
(see https://www.mail-archive.com/devicetree@vger.kernel.org/msg05829.html).


Best Regards,

Boris
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Felipe Balbi Dec. 19, 2013, 6:22 p.m. UTC | #5
On Thu, Dec 19, 2013 at 06:18:40PM +0100, boris brezillon wrote:
> Hello Felipe,
> 
> On 19/12/2013 17:47, Felipe Balbi wrote:
> >On Thu, Dec 19, 2013 at 08:41:09AM -0800, Greg Kroah-Hartman wrote:
> >>On Thu, Dec 19, 2013 at 03:34:31PM +0100, Boris BREZILLON wrote:
> >>>GPIO hogging is a way to request and configure specific GPIO without
> >>>explicitly requesting it in the device driver.
> >>>
> >>>The request and configuration procedure is handled in the core device
> >>>driver code before the driver probe function is called.
> >>>
> >>>It allows specific GPIOs to be configured without any driver specific code.
> >>>
> >>>Particularly usefull when a external device is connected to a bus and the
> >>>bus connections depends on an external switch controlled by a GPIO pin.
> >for external switches, you probably need a pinctrl-gpio driver.
> >
> Do you mean using pinctrl pinconf to configure the PIN as output-high or
> output-low ?
> 
> This was my first proposal
> (see https://www.mail-archive.com/devicetree@vger.kernel.org/msg05829.html).

that's quite a weird argument from Linus W, considering you _do_ have a
discrete mux on the board.

We have quite a few of such "crazy" scenarios here at TI and we were
going to send a pinctrl-gpio driver. If that's not acceptable, then I
suppose there is no way to boot from NAND on a board where NAND signals
go through a discrete mux where the select signal is a GPIO pin.
Boris Brezillon Dec. 30, 2013, 9:48 a.m. UTC | #6
Hello,

On 19/12/2013 19:22, Felipe Balbi wrote:
> On Thu, Dec 19, 2013 at 06:18:40PM +0100, boris brezillon wrote:
>> Hello Felipe,
>>
>> On 19/12/2013 17:47, Felipe Balbi wrote:
>>> On Thu, Dec 19, 2013 at 08:41:09AM -0800, Greg Kroah-Hartman wrote:
>>>> On Thu, Dec 19, 2013 at 03:34:31PM +0100, Boris BREZILLON wrote:
>>>>> GPIO hogging is a way to request and configure specific GPIO without
>>>>> explicitly requesting it in the device driver.
>>>>>
>>>>> The request and configuration procedure is handled in the core device
>>>>> driver code before the driver probe function is called.
>>>>>
>>>>> It allows specific GPIOs to be configured without any driver specific code.
>>>>>
>>>>> Particularly usefull when a external device is connected to a bus and the
>>>>> bus connections depends on an external switch controlled by a GPIO pin.
>>> for external switches, you probably need a pinctrl-gpio driver.
>> Do you mean using pinctrl pinconf to configure the PIN as output-high or
>> output-low ?
>>
>> This was my first proposal
>> (see https://www.mail-archive.com/devicetree@vger.kernel.org/msg05829.html).

My mistake: this is not exactly what I proposed in my patch series.

Actually, I was directly requesting the pin connected to the external 
switch as
OUTPUT + (OUTPUT-LEVEL) according the the device needs:
- output high for MMC slot
- output low for SPI device

And, I guess this is why Linus asked me to find a better solution.

IMHO your approach is, by far, much better. You expose the external switch
as a PIN muxing device and the devices connected to through this PIN mux
block just have to request the appropriate PIN states.

In my specific case this would give the following:
- MMC conf for mmc slot 0
- SPI conf for the SPI device

With your approach the HW representation is better: the different signals
controlled by the external switch can be seen using debugfs, and device
tree definition is closer to the real HW design.

> that's quite a weird argument from Linus W, considering you _do_ have a
> discrete mux on the board.

> We have quite a few of such "crazy" scenarios here at TI and we were
> going to send a pinctrl-gpio driver. If that's not acceptable, then I
> suppose there is no way to boot from NAND on a board where NAND signals
> go through a discrete mux where the select signal is a GPIO pin.
>

Please keep going with the submission process: I'm really interested in this
driver (BTW could you add me in the CC list ?).

Linus, tell me if I'm wrong, but I think, the pinctrl-gpio is the right 
way to solve
the at91rm9200ek board use case.

This does not mean, the gpio hogs approach does not solve other issues (see
https://lkml.org/lkml/2013/8/29/333 and
https://www.mail-archive.com/linux-gpio@vger.kernel.org/msg01084.html), 
but in
my specific case, I'd rather use the pinctrl-gpio driver.

Best Regards,

Boris
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij Jan. 8, 2014, 9:37 a.m. UTC | #7
On Thu, Dec 19, 2013 at 3:34 PM, Boris BREZILLON
<b.brezillon@overkiz.com> wrote:

> GPIO hogging is a way to request and configure specific GPIO without
> explicitly requesting it in the device driver.
>
> The request and configuration procedure is handled in the core device
> driver code before the driver probe function is called.

Why?

Why can't these hogs be handled right after the gpio chip has been
added in the end of the gpiochio_add() function?

> +It might contain GPIO hog definitions. GPIO hogging is a mechanism providing
> +automatic GPIO request and configuration before the device is passed to its
> +driver probe function (the same mechanism is used for pinctrl pin config).
> +
> +Each GPIO hog definition is represented as a child node of the GPIO controller.
> +Required properties:
> +- gpio: store the gpio informations (id, flags, ...). Shall contain the
> +  number of cells specified in its parent node (GPIO controller node).

This property is alway plural "gpios".

> +- hog-as-input or hog-as-output: a boolean property specifying the GPIO
> +  direction.
> +- hog-init-high or hog-init-low: a boolean property specifying the GPIO
> +  value in case the GPIO is hogged as output.

What about just having these three:

hog-as-input
hog-as-output-high
hog-as-output-low

> +Optional properties:
> +- open-drain-line: GPIO is configured as an open drain pin.
> +- open-source-line: GPIO is configured as an open source pin.

Can you not simply us the flags in the second cell for the gpios
property for this, normally?

> +- export-line or export-line-fixed: the GPIO is exported to userspace via
> +  sysfs.

Move this feature to a separate patch. It is much more controversial
than the hog concept as such.

> +- line-name: the GPIO label name.

OK.

> @@ -66,6 +95,19 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
>                 compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
>                 reg = <0x1400 0x18>;
>                 gpio-controller;
> +               gpio-hogs = <&exported_gpio>;
> +
> +               line_a: line-a {
> +                       gpio = <5 0>;
> +                       hog-as-input;
> +                       line-name = "line-a";
> +               };
> +
> +               exported_gpio: exported-gpio {
> +                       gpio = <6 0>;
> +                       hog-as-output;
> +                       line-name = "exported-gpio";
> +               };

This looks pretty straight-forward to use, but need the DT maintainers
to provide input on this.

>         };
>
>         qe_pio_e: gpio-controller@1460 {
> @@ -75,6 +117,11 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
>                 gpio-controller;
>         };
>
> +       pio_consumer {
> +               gpio-hogs = <&line_a>;
> +               gpio-hog-names = "my-line-a";
> +       };

No. No way. That is not what hogs is about. It is not to make consumers
get their GPIOs grabbed automatically when probing. It is *only* about
making it possible for the core to set up a few GPIO lines *not* belonging
to any particular in-kernel device when probing the GPIO chip.

For providing GPIOs to consumers, use the existing OF bindings and
add code to the drivers to handle them. A device needs to keep track
of its resources.

In any case, such concepts would be a totally separate patch.

> diff --git a/drivers/base/dd.c b/drivers/base/dd.c

NAK on this, hogs shall be a GPIO-intrinsic.

> @@ -142,6 +175,9 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
>         if (!dr)
>                 return -ENOMEM;
>
> +       if (gpio_is_hogged(dev, gpio))
> +               return 0;
> +
>         rc = gpio_request(gpio, label);
>         if (rc) {
>                 devres_free(dr);
> @@ -172,6 +208,9 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
>         if (!dr)
>                 return -ENOMEM;
>
> +       if (gpio_is_hogged(dev, gpio))
> +               return 0;
> +

This just makes it impossible to release these resources. Don't do this.

Hogs should be tied to a certain GPIO chip, get hogged when the
chip is added and get removed when the chip is removed.

> + * of_gpio_hog_count() - Count a GPIO hogs on a specific device node
> + * @np:                device node to get GPIO from
> + *
> + * Returns the number of GPIO hogs requested by this device node.
> + */
> +int of_gpio_hog_count(struct device_node *np)
> +{
> +       int size;
> +
> +       if (!of_get_property(np, "gpio-hogs", &size))
> +               return 0;
> +
> +       return size / sizeof(phandle);
> +}
> +EXPORT_SYMBOL(of_gpio_hog_count);

There is no reason to export this, it should be static, gpiolib-internal.

> +EXPORT_SYMBOL(of_get_gpio_hog);

Dito.

> @@ -1214,6 +1216,17 @@ int gpiochip_add(struct gpio_chip *chip)
>
>         of_gpiochip_add(chip);
>
> +       /* Instantiate missing GPIO hogs */
> +       if (chip->dev->gpios) {
> +               for (i = 0; i < chip->dev->gpios->ngpios; i++) {
> +                       if (chip->dev->gpios->gpios[i])
> +                               continue;
> +                       desc = devm_gpiod_get_hog_index(chip->dev, i);
> +                       if (!IS_ERR(desc))
> +                               chip->dev->gpios->gpios[i] = desc;
> +               }
> +       }

This is the only thing you should be doing.

> @@ -2421,6 +2434,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
>         struct gpio_desc *desc = NULL;
>         int status;
>         enum gpio_lookup_flags flags = 0;
> +       int i;
>
>         dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
>
> @@ -2451,6 +2465,13 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
>                 return desc;
>         }
>
> +       if (dev->gpios) {
> +               for (i = 0; i < dev->gpios->ngpios; i++) {
> +                       if (dev->gpios->gpios[i] == desc)
> +                               return desc;
> +               }
> +       }

Don't do this. We already have explicit gpio resource management.
Don't attempt to make it implicit.

> +EXPORT_SYMBOL_GPL(gpiod_get_hog_index);

I don't understand this function at all.

> +bool gpio_is_hogged(struct device *dev, unsigned gpio)
> +{
> +       return gpiod_is_hogged(dev, gpio_to_desc(gpio));
> +}
> +EXPORT_SYMBOL_GPL(gpio_is_hogged);

This should not be exported.

> +/**
> + * gpio_hog_count - count number of GPIO hogs requested by a specific device
> + * @dev:       GPIO consumer
> + *
> + * Return the number of GPIO hogs.
> + */
> +int gpio_hog_count(struct device *dev)
> +{
> +       /* Using device tree? */
> +       if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
> +               return of_gpio_hog_count(dev->of_node);
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(gpio_hog_count);

Get rid of this.

> +++ b/include/linux/device.h
> @@ -22,6 +22,7 @@
>  #include <linux/types.h>
>  #include <linux/mutex.h>
>  #include <linux/pinctrl/devinfo.h>
> +#include <linux/gpio/devinfo.h>
>  #include <linux/pm.h>
>  #include <linux/atomic.h>
>  #include <linux/ratelimit.h>
> @@ -744,6 +745,10 @@ struct device {
>         struct dev_pin_info     *pins;
>  #endif
>
> +#ifdef CONFIG_GPIOLIB
> +       struct dev_gpio_info    *gpios;
> +#endif

Don't do this.

Overall it appears you try to make the device core grab all GPIOs automatically
when devices are probed, this is not what GPIO hogs are about, and we already
have a resource management model for GPIOs using the descriptors explicitly
in the drivers, I see no reason to try to push that over to the device core.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij Jan. 8, 2014, 9:45 a.m. UTC | #8
On Mon, Dec 30, 2013 at 10:48 AM, boris brezillon
<b.brezillon@overkiz.com> wrote:
> On 19/12/2013 19:22, Felipe Balbi wrote:

>> that's quite a weird argument from Linus W, considering you _do_ have a
>> discrete mux on the board.
>
>> We have quite a few of such "crazy" scenarios here at TI and we were
>> going to send a pinctrl-gpio driver.

Hm I'm all in the blue as to what a "pinctrl-gpio driver" is ... I'm
confused :-)

>> If that's not acceptable, then I
>> suppose there is no way to boot from NAND on a board where NAND signals
>> go through a discrete mux where the select signal is a GPIO pin.

One problem I have is that I still don't really understand if this is a pin
mux, i.e. changing the connection to a certain device onto some actual
*PIN* or just some other mux muxing some certain line from one silicon
block to another.

> Linus, tell me if I'm wrong, but I think, the pinctrl-gpio is the right way
> to solve
> the at91rm9200ek board use case.

I don't know, because I don't know exactly what you mean by
"pinctrl-gpio".

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Boris Brezillon Jan. 8, 2014, 10:18 a.m. UTC | #9
On 08/01/2014 10:37, Linus Walleij wrote:
> On Thu, Dec 19, 2013 at 3:34 PM, Boris BREZILLON
> <b.brezillon@overkiz.com> wrote:
>
>> GPIO hogging is a way to request and configure specific GPIO without
>> explicitly requesting it in the device driver.
>>
>> The request and configuration procedure is handled in the core device
>> driver code before the driver probe function is called.
> Why?

Because I obviously misunderstood your suggestion in our previous
discussion regarding the at91rm9200-ek board case :-)
( https://www.mail-archive.com/devicetree@vger.kernel.org/msg06838.html).

I thought you were suggesting to request GPIOs as PINCTRL configs are
requested, but apparently, you were just suggesting to directly request
the pins within the gpio controller.

Regarding the specific at91rm920-ek case, your solution should work
(as long as the gpio is configured before the SPI or MMC device is probed,
which should be the case), but the dependency between the SPI or MMC
device and the SPI/MMC switch pin is not represented in DT, and I'm not
happy with this.


Anyway, do you want me to rework the gpio hog as described below ?

Best Regards,

Boris
>
> Why can't these hogs be handled right after the gpio chip has been
> added in the end of the gpiochio_add() function?
>
>> +It might contain GPIO hog definitions. GPIO hogging is a mechanism providing
>> +automatic GPIO request and configuration before the device is passed to its
>> +driver probe function (the same mechanism is used for pinctrl pin config).
>> +
>> +Each GPIO hog definition is represented as a child node of the GPIO controller.
>> +Required properties:
>> +- gpio: store the gpio informations (id, flags, ...). Shall contain the
>> +  number of cells specified in its parent node (GPIO controller node).
> This property is alway plural "gpios".
>
>> +- hog-as-input or hog-as-output: a boolean property specifying the GPIO
>> +  direction.
>> +- hog-init-high or hog-init-low: a boolean property specifying the GPIO
>> +  value in case the GPIO is hogged as output.
> What about just having these three:
>
> hog-as-input
> hog-as-output-high
> hog-as-output-low
>
>> +Optional properties:
>> +- open-drain-line: GPIO is configured as an open drain pin.
>> +- open-source-line: GPIO is configured as an open source pin.
> Can you not simply us the flags in the second cell for the gpios
> property for this, normally?
>
>> +- export-line or export-line-fixed: the GPIO is exported to userspace via
>> +  sysfs.
> Move this feature to a separate patch. It is much more controversial
> than the hog concept as such.
>
>> +- line-name: the GPIO label name.
> OK.
>
>> @@ -66,6 +95,19 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
>>                  compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
>>                  reg = <0x1400 0x18>;
>>                  gpio-controller;
>> +               gpio-hogs = <&exported_gpio>;
>> +
>> +               line_a: line-a {
>> +                       gpio = <5 0>;
>> +                       hog-as-input;
>> +                       line-name = "line-a";
>> +               };
>> +
>> +               exported_gpio: exported-gpio {
>> +                       gpio = <6 0>;
>> +                       hog-as-output;
>> +                       line-name = "exported-gpio";
>> +               };
> This looks pretty straight-forward to use, but need the DT maintainers
> to provide input on this.
>
>>          };
>>
>>          qe_pio_e: gpio-controller@1460 {
>> @@ -75,6 +117,11 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
>>                  gpio-controller;
>>          };
>>
>> +       pio_consumer {
>> +               gpio-hogs = <&line_a>;
>> +               gpio-hog-names = "my-line-a";
>> +       };
> No. No way. That is not what hogs is about. It is not to make consumers
> get their GPIOs grabbed automatically when probing. It is *only* about
> making it possible for the core to set up a few GPIO lines *not* belonging
> to any particular in-kernel device when probing the GPIO chip.
>
> For providing GPIOs to consumers, use the existing OF bindings and
> add code to the drivers to handle them. A device needs to keep track
> of its resources.
>
> In any case, such concepts would be a totally separate patch.
>
>> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> NAK on this, hogs shall be a GPIO-intrinsic.
>
>> @@ -142,6 +175,9 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
>>          if (!dr)
>>                  return -ENOMEM;
>>
>> +       if (gpio_is_hogged(dev, gpio))
>> +               return 0;
>> +
>>          rc = gpio_request(gpio, label);
>>          if (rc) {
>>                  devres_free(dr);
>> @@ -172,6 +208,9 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
>>          if (!dr)
>>                  return -ENOMEM;
>>
>> +       if (gpio_is_hogged(dev, gpio))
>> +               return 0;
>> +
> This just makes it impossible to release these resources. Don't do this.
>
> Hogs should be tied to a certain GPIO chip, get hogged when the
> chip is added and get removed when the chip is removed.
>
>> + * of_gpio_hog_count() - Count a GPIO hogs on a specific device node
>> + * @np:                device node to get GPIO from
>> + *
>> + * Returns the number of GPIO hogs requested by this device node.
>> + */
>> +int of_gpio_hog_count(struct device_node *np)
>> +{
>> +       int size;
>> +
>> +       if (!of_get_property(np, "gpio-hogs", &size))
>> +               return 0;
>> +
>> +       return size / sizeof(phandle);
>> +}
>> +EXPORT_SYMBOL(of_gpio_hog_count);
> There is no reason to export this, it should be static, gpiolib-internal.
>
>> +EXPORT_SYMBOL(of_get_gpio_hog);
> Dito.
>
>> @@ -1214,6 +1216,17 @@ int gpiochip_add(struct gpio_chip *chip)
>>
>>          of_gpiochip_add(chip);
>>
>> +       /* Instantiate missing GPIO hogs */
>> +       if (chip->dev->gpios) {
>> +               for (i = 0; i < chip->dev->gpios->ngpios; i++) {
>> +                       if (chip->dev->gpios->gpios[i])
>> +                               continue;
>> +                       desc = devm_gpiod_get_hog_index(chip->dev, i);
>> +                       if (!IS_ERR(desc))
>> +                               chip->dev->gpios->gpios[i] = desc;
>> +               }
>> +       }
> This is the only thing you should be doing.
>
>> @@ -2421,6 +2434,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
>>          struct gpio_desc *desc = NULL;
>>          int status;
>>          enum gpio_lookup_flags flags = 0;
>> +       int i;
>>
>>          dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
>>
>> @@ -2451,6 +2465,13 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
>>                  return desc;
>>          }
>>
>> +       if (dev->gpios) {
>> +               for (i = 0; i < dev->gpios->ngpios; i++) {
>> +                       if (dev->gpios->gpios[i] == desc)
>> +                               return desc;
>> +               }
>> +       }
> Don't do this. We already have explicit gpio resource management.
> Don't attempt to make it implicit.
>
>> +EXPORT_SYMBOL_GPL(gpiod_get_hog_index);
> I don't understand this function at all.
>
>> +bool gpio_is_hogged(struct device *dev, unsigned gpio)
>> +{
>> +       return gpiod_is_hogged(dev, gpio_to_desc(gpio));
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_is_hogged);
> This should not be exported.
>
>> +/**
>> + * gpio_hog_count - count number of GPIO hogs requested by a specific device
>> + * @dev:       GPIO consumer
>> + *
>> + * Return the number of GPIO hogs.
>> + */
>> +int gpio_hog_count(struct device *dev)
>> +{
>> +       /* Using device tree? */
>> +       if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
>> +               return of_gpio_hog_count(dev->of_node);
>> +       return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(gpio_hog_count);
> Get rid of this.
>
>> +++ b/include/linux/device.h
>> @@ -22,6 +22,7 @@
>>   #include <linux/types.h>
>>   #include <linux/mutex.h>
>>   #include <linux/pinctrl/devinfo.h>
>> +#include <linux/gpio/devinfo.h>
>>   #include <linux/pm.h>
>>   #include <linux/atomic.h>
>>   #include <linux/ratelimit.h>
>> @@ -744,6 +745,10 @@ struct device {
>>          struct dev_pin_info     *pins;
>>   #endif
>>
>> +#ifdef CONFIG_GPIOLIB
>> +       struct dev_gpio_info    *gpios;
>> +#endif
> Don't do this.
>
> Overall it appears you try to make the device core grab all GPIOs automatically
> when devices are probed, this is not what GPIO hogs are about, and we already
> have a resource management model for GPIOs using the descriptors explicitly
> in the drivers, I see no reason to try to push that over to the device core.
>
> Yours,
> Linus Walleij

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij Jan. 14, 2014, 10:27 a.m. UTC | #10
On Wed, Jan 8, 2014 at 11:18 AM, boris brezillon
<b.brezillon@overkiz.com> wrote:

> Anyway, do you want me to rework the gpio hog as described below ?

If you feel you have time, drive and a proper usecase for testing it,
sure. I just want it to be driven my someone who *really* needs
that feature.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ben Gamari Sept. 20, 2014, 9:37 p.m. UTC | #11
Hi Boris,

I'm just returning to this now.


Greg Kroah-Hartman <gregkh@linuxfoundation.org> writes:

> I don't understand what makes GPIO's "special" enough to get included in
> the driver core like this, and called for each and every device that is
> added to the system.
>
I'm also a bit confused why GPIOs ended up in the driver core but
perhaps I'm missing something. What was your motivation here?

Cheers,

- Ben
Ben Gamari Sept. 20, 2014, 10:26 p.m. UTC | #12
Ben Gamari <bgamari.foss@gmail.com> writes:

> Hi Boris,
>
> I'm just returning to this now.
>
>
> Greg Kroah-Hartman <gregkh@linuxfoundation.org> writes:
>
>> I don't understand what makes GPIO's "special" enough to get included in
>> the driver core like this, and called for each and every device that is
>> added to the system.
>>
> I'm also a bit confused why GPIOs ended up in the driver core but
> perhaps I'm missing something. What was your motivation here?
>
Somehow I overlooked the message in which you responded to this. Ignore
the above.

Cheers,

- Ben
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index 0c85bb6..e2295e3 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -59,6 +59,35 @@  and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
 Every GPIO controller node must both an empty "gpio-controller"
 property, and have #gpio-cells contain the size of the gpio-specifier.
 
+It might contain GPIO hog definitions. GPIO hogging is a mechanism providing
+automatic GPIO request and configuration before the device is passed to its
+driver probe function (the same mechanism is used for pinctrl pin config).
+
+Each GPIO hog definition is represented as a child node of the GPIO controller.
+Required properties:
+- gpio: store the gpio informations (id, flags, ...). Shall contain the
+  number of cells specified in its parent node (GPIO controller node).
+- hog-as-input or hog-as-output: a boolean property specifying the GPIO
+  direction.
+- hog-init-high or hog-init-low: a boolean property specifying the GPIO
+  value in case the GPIO is hogged as output.
+
+Optional properties:
+- open-drain-line: GPIO is configured as an open drain pin.
+- open-source-line: GPIO is configured as an open source pin.
+- export-line or export-line-fixed: the GPIO is exported to userspace via
+  sysfs.
+- line-name: the GPIO label name.
+
+A GPIO consumer can request GPIO hogs using the "gpio-hogs" property, which
+encodes a list of requested GPIO hogs.
+If the "gpio-hog-names" property is specified and the GPIO hog export the GPIO
+to sysfs, links to the GPIO directory are created in the consumer sysfs device
+directory.
+
+If you just want to export a GPIO to sysfs without assigning it to a specific
+device, you can specify a "gpio-hogs" property in the GPIO controller node.
+
 Example of two SOC GPIO banks defined as gpio-controller nodes:
 
 	qe_pio_a: gpio-controller@1400 {
@@ -66,6 +95,19 @@  Example of two SOC GPIO banks defined as gpio-controller nodes:
 		compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
 		reg = <0x1400 0x18>;
 		gpio-controller;
+		gpio-hogs = <&exported_gpio>;
+
+		line_a: line-a {
+			gpio = <5 0>;
+			hog-as-input;
+			line-name = "line-a";
+		};
+
+		exported_gpio: exported-gpio {
+			gpio = <6 0>;
+			hog-as-output;
+			line-name = "exported-gpio";
+		};
 	};
 
 	qe_pio_e: gpio-controller@1460 {
@@ -75,6 +117,11 @@  Example of two SOC GPIO banks defined as gpio-controller nodes:
 		gpio-controller;
 	};
 
+	pio_consumer {
+		gpio-hogs = <&line_a>;
+		gpio-hog-names = "my-line-a";
+	};
+
 2.1) gpio- and pin-controller interaction
 -----------------------------------------
 
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 94e8a80..17940c3 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -22,6 +22,7 @@  obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)	+= regmap/
 obj-$(CONFIG_SOC_BUS) += soc.o
 obj-$(CONFIG_PINCTRL) += pinctrl.o
+obj-$(CONFIG_GPIOLIB) += gpio.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 0605176..cfeceea 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -25,6 +25,7 @@ 
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
 #include <linux/pinctrl/devinfo.h>
+#include <linux/gpio/devinfo.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -278,6 +279,10 @@  static int really_probe(struct device *dev, struct device_driver *drv)
 	if (ret)
 		goto probe_failed;
 
+	ret = gpio_get_hogs(dev);
+	if (ret)
+		goto probe_failed;
+
 	if (driver_sysfs_add(dev)) {
 		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
 			__func__, dev_name(dev));
diff --git a/drivers/base/gpio.c b/drivers/base/gpio.c
new file mode 100644
index 0000000..565c31c
--- /dev/null
+++ b/drivers/base/gpio.c
@@ -0,0 +1,59 @@ 
+/*
+ * Driver core interface to the GPIO subsystem.
+ *
+ * Copyright (C) Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * Author: Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/devinfo.h>
+#include <linux/gpio/consumer.h>
+#include <linux/slab.h>
+
+/**
+ * gpio_get_hogs() - called by the device core before probe
+ * @dev: the device that is just about to probe
+ */
+int gpio_get_hogs(struct device *dev)
+{
+	struct gpio_desc *desc;
+	int ret;
+	int count;
+	int i = 0;
+
+	count = gpio_hog_count(dev);
+	if (!count)
+		return 0;
+
+	dev->gpios = devm_kzalloc(dev,
+				  sizeof(*(dev->gpios)) +
+				  (count * sizeof(struct gpio_desc *)),
+				  GFP_KERNEL);
+	if (!dev->gpios)
+		return -ENOMEM;
+
+	dev->gpios->ngpios = count;
+	for (i = 0; i < count; i++) {
+		desc = devm_gpiod_get_hog_index(dev, i);
+		if (IS_ERR(desc)) {
+			ret = PTR_ERR(desc);
+			if (ret == -EPROBE_DEFER)
+				goto cleanup;
+			desc = NULL;
+		}
+		dev->gpios->gpios[i] = desc;
+	}
+
+	return 0;
+
+cleanup:
+	for (; i > 0; i--)
+		devm_gpiod_put(dev, dev->gpios->gpios[i - 1]);
+	devm_kfree(dev, dev->gpios);
+	dev->gpios = NULL;
+
+	return ret;
+}
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 307464f..ad0ebc5 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -87,6 +87,39 @@  struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
 EXPORT_SYMBOL(devm_gpiod_get_index);
 
 /**
+ * devm_gpiod_get_hog_index - Resource-managed gpiod_get_hog_index()
+ * @dev:	GPIO consumer
+ * @idx:	index of the GPIO to obtain in the consumer
+ *
+ * Managed gpiod_get_hog_index(). GPIO descriptors returned from this function
+ * are automatically disposed on driver detach. See gpiod_get_index() for
+ * detailed information about behavior and return values.
+ */
+struct gpio_desc *__must_check devm_gpiod_get_hog_index(struct device *dev,
+							unsigned int idx)
+{
+	struct gpio_desc **dr;
+	struct gpio_desc *desc;
+
+	dr = devres_alloc(devm_gpiod_release, sizeof(struct gpiod_desc *),
+			  GFP_KERNEL);
+	if (!dr)
+		return ERR_PTR(-ENOMEM);
+
+	desc = gpiod_get_hog_index(dev, idx);
+	if (IS_ERR(desc)) {
+		devres_free(dr);
+		return desc;
+	}
+
+	*dr = desc;
+	devres_add(dev, dr);
+
+	return desc;
+}
+EXPORT_SYMBOL(devm_gpiod_get_hog_index);
+
+/**
  * devm_gpiod_put - Resource-managed gpiod_put()
  * @desc:	GPIO descriptor to dispose of
  *
@@ -142,6 +175,9 @@  int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
 	if (!dr)
 		return -ENOMEM;
 
+	if (gpio_is_hogged(dev, gpio))
+		return 0;
+
 	rc = gpio_request(gpio, label);
 	if (rc) {
 		devres_free(dr);
@@ -172,6 +208,9 @@  int devm_gpio_request_one(struct device *dev, unsigned gpio,
 	if (!dr)
 		return -ENOMEM;
 
+	if (gpio_is_hogged(dev, gpio))
+		return 0;
+
 	rc = gpio_request_one(gpio, flags, label);
 	if (rc) {
 		devres_free(dr);
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index e0a98f5..8e9fbef 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -96,6 +96,140 @@  struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
 EXPORT_SYMBOL(of_get_named_gpiod_flags);
 
 /**
+ * of_gpio_hog_count() - Count a GPIO hogs on a specific device node
+ * @np:		device node to get GPIO from
+ *
+ * Returns the number of GPIO hogs requested by this device node.
+ */
+int of_gpio_hog_count(struct device_node *np)
+{
+	int size;
+
+	if (!of_get_property(np, "gpio-hogs", &size))
+		return 0;
+
+	return size / sizeof(phandle);
+}
+EXPORT_SYMBOL(of_gpio_hog_count);
+
+/**
+ * of_get_gpio_hog() - Get a GPIO hog descriptor, names and flags for GPIO API
+ * @np:		device node to get GPIO from
+ * @index:	index of the GPIO
+ * @name:	GPIO line name
+ * @lnk_name	GPIO link name (for sysfs link)
+ * @flags:	a flags pointer to fill in
+ *
+ * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
+ * value on the error condition.
+ */
+struct gpio_desc *of_get_gpio_hog(struct device_node *np, int index,
+				  const char **name, const char **lnk_name,
+				  unsigned long *flags)
+{
+	struct device_node *hog_np, *chip_np;
+	enum of_gpio_flags xlate_flags;
+	unsigned long req_flags = 0;
+	struct gpio_desc *desc;
+	struct gg_data gg_data = {
+		.flags = &xlate_flags,
+		.out_gpio = NULL,
+	};
+	u32 tmp;
+	int i;
+	int ret;
+
+	hog_np = of_parse_phandle(np, "gpio-hogs", index);
+	if (!hog_np)
+		return ERR_PTR(-EINVAL);
+
+	chip_np = hog_np->parent;
+	if (!chip_np) {
+		desc = ERR_PTR(-EINVAL);
+		goto out;
+	}
+
+	ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
+	if (ret) {
+		desc = ERR_PTR(ret);
+		goto out;
+	}
+
+	if (tmp > MAX_PHANDLE_ARGS) {
+		desc = ERR_PTR(-EINVAL);
+		goto out;
+	}
+
+	gg_data.gpiospec.args_count = tmp;
+	gg_data.gpiospec.np = chip_np;
+	for (i = 0; i < tmp; i++) {
+		ret = of_property_read_u32(hog_np, "gpio",
+					   &gg_data.gpiospec.args[i]);
+		if (ret) {
+			desc = ERR_PTR(ret);
+			goto out;
+		}
+	}
+
+	gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
+	if (!gg_data.out_gpio) {
+		if (hog_np->parent == np)
+			desc = ERR_PTR(-ENXIO);
+		else
+			desc = ERR_PTR(-EPROBE_DEFER);
+
+		goto out;
+	}
+
+	if (xlate_flags & OF_GPIO_ACTIVE_LOW)
+		req_flags |= GPIOF_ACTIVE_LOW;
+
+	if (of_property_read_bool(hog_np, "hog-as-input")) {
+		req_flags |= GPIOF_DIR_IN;
+	} else if (of_property_read_bool(hog_np, "hog-as-output")) {
+		if (of_property_read_bool(hog_np, "hog-init-high")) {
+			req_flags |= GPIOF_INIT_HIGH;
+		} else if (!of_property_read_bool(hog_np, "hog-init-low")) {
+			desc = ERR_PTR(-EINVAL);
+			goto out;
+		}
+	} else {
+		desc = ERR_PTR(-EINVAL);
+		goto out;
+	}
+
+	if (of_property_read_bool(hog_np, "open-drain-line"))
+		req_flags |= GPIOF_OPEN_DRAIN;
+
+	if (of_property_read_bool(hog_np, "open-source-line"))
+		req_flags |= GPIOF_OPEN_DRAIN;
+
+	if (of_property_read_bool(hog_np, "export-line"))
+		req_flags |= GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE;
+	else if (of_property_read_bool(hog_np, "export-line-fixed"))
+		req_flags |= GPIOF_EXPORT;
+
+	if (name && of_property_read_string(hog_np, "line-name", name))
+		*name = hog_np->name;
+
+	if (lnk_name) {
+		*lnk_name = NULL;
+		of_property_read_string_index(np, "gpio-hog-names", index, lnk_name);
+	}
+
+	if (flags)
+		*flags = req_flags;
+
+	desc = gg_data.out_gpio;
+
+out:
+	of_node_put(hog_np);
+
+	return desc;
+}
+EXPORT_SYMBOL(of_get_gpio_hog);
+
+/**
  * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
  * @gc:		pointer to the gpio_chip structure
  * @np:		device node of the GPIO chip
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 85f772c..147b503 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1166,6 +1166,8 @@  int gpiochip_add(struct gpio_chip *chip)
 	int		status = 0;
 	unsigned	id;
 	int		base = chip->base;
+	struct gpio_desc	*desc;
+	int 		i;
 
 	if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
 			&& base >= 0) {
@@ -1214,6 +1216,17 @@  int gpiochip_add(struct gpio_chip *chip)
 
 	of_gpiochip_add(chip);
 
+	/* Instantiate missing GPIO hogs */
+	if (chip->dev->gpios) {
+		for (i = 0; i < chip->dev->gpios->ngpios; i++) {
+			if (chip->dev->gpios->gpios[i])
+				continue;
+			desc = devm_gpiod_get_hog_index(chip->dev, i);
+			if (!IS_ERR(desc))
+				chip->dev->gpios->gpios[i] = desc;
+		}
+	}
+
 	if (status)
 		goto fail;
 
@@ -2421,6 +2434,7 @@  struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
 	struct gpio_desc *desc = NULL;
 	int status;
 	enum gpio_lookup_flags flags = 0;
+	int i;
 
 	dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
 
@@ -2451,6 +2465,13 @@  struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
 		return desc;
 	}
 
+	if (dev->gpios) {
+		for (i = 0; i < dev->gpios->ngpios; i++) {
+			if (dev->gpios->gpios[i] == desc)
+				return desc;
+		}
+	}
+
 	status = gpiod_request(desc, con_id);
 
 	if (status < 0)
@@ -2468,6 +2489,88 @@  struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
 EXPORT_SYMBOL_GPL(gpiod_get_index);
 
 /**
+ * gpiod_get_hog_index - obtain a GPIO from a multi-index GPIO hog function
+ * @dev:	GPIO consumer
+ * @idx:	index of the GPIO to obtain in the consumer
+ *
+ * This should only be used by core device driver code to request GPIO hogs
+ * before probing a device.
+ *
+ * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error.
+ */
+struct gpio_desc *__must_check gpiod_get_hog_index(struct device *dev,
+						   unsigned int idx)
+{
+	struct gpio_desc *desc = NULL;
+	int status;
+	unsigned long flags;
+	const char *name, *lnk_name;
+
+	/* Using device tree? */
+	if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) {
+		dev_dbg(dev, "using device tree for GPIO hog retrieval\n");
+		desc = of_get_gpio_hog(dev->of_node, idx, &name, &lnk_name,
+				       &flags);
+	}
+
+	if (!desc)
+		return ERR_PTR(-ENOTSUPP);
+	else if (IS_ERR(desc))
+		return desc;
+
+	status = gpio_request_one(desc_to_gpio(desc), flags, name);
+	if (status)
+		return ERR_PTR(status);
+
+	if (!lnk_name || !(flags & GPIOF_EXPORT))
+		return desc;
+
+	status = gpiod_export_link(dev, lnk_name, desc);
+	if (status) {
+		gpiod_free(desc);
+		return ERR_PTR(status);
+	}
+
+	return desc;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_hog_index);
+
+static bool gpiod_is_hogged(struct device *dev, struct gpio_desc *desc)
+{
+	int i;
+
+	if (dev->gpios) {
+		for (i = 0; i < dev->gpios->ngpios; i++) {
+			if (dev->gpios->gpios[i] == desc)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+bool gpio_is_hogged(struct device *dev, unsigned gpio)
+{
+	return gpiod_is_hogged(dev, gpio_to_desc(gpio));
+}
+EXPORT_SYMBOL_GPL(gpio_is_hogged);
+
+/**
+ * gpio_hog_count - count number of GPIO hogs requested by a specific device
+ * @dev:	GPIO consumer
+ *
+ * Return the number of GPIO hogs.
+ */
+int gpio_hog_count(struct device *dev)
+{
+	/* Using device tree? */
+	if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
+		return of_gpio_hog_count(dev->of_node);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_hog_count);
+
+/**
  * gpiod_put - dispose of a GPIO descriptor
  * @desc:	GPIO descriptor to dispose of
  *
diff --git a/include/linux/device.h b/include/linux/device.h
index 952b010..df9ea62 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -22,6 +22,7 @@ 
 #include <linux/types.h>
 #include <linux/mutex.h>
 #include <linux/pinctrl/devinfo.h>
+#include <linux/gpio/devinfo.h>
 #include <linux/pm.h>
 #include <linux/atomic.h>
 #include <linux/ratelimit.h>
@@ -744,6 +745,10 @@  struct device {
 	struct dev_pin_info	*pins;
 #endif
 
+#ifdef CONFIG_GPIOLIB
+	struct dev_gpio_info	*gpios;
+#endif
+
 #ifdef CONFIG_NUMA
 	int		numa_node;	/* NUMA node this device is close to */
 #endif
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 4d34dbb..69d1e99 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -24,6 +24,10 @@  struct gpio_desc *__must_check gpiod_get(struct device *dev,
 struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
 					       const char *con_id,
 					       unsigned int idx);
+struct gpio_desc *__must_check gpiod_get_hog_index(struct device *dev,
+						   unsigned int idx);
+int gpio_hog_count(struct device *dev);
+bool gpio_is_hogged(struct device *dev, unsigned gpio);
 void gpiod_put(struct gpio_desc *desc);
 
 struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
@@ -31,6 +35,8 @@  struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
 struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
 						    const char *con_id,
 						    unsigned int idx);
+struct gpio_desc *__must_check devm_gpiod_get_hog_index(struct device *dev,
+							unsigned int idx);
 void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
 
 int gpiod_get_direction(const struct gpio_desc *desc);
@@ -74,6 +80,19 @@  static inline struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
 {
 	return ERR_PTR(-ENOSYS);
 }
+static inline struct gpio_desc *__must_check
+gpiod_get_hog_index(struct device *dev, unsigned int idx)
+{
+	return ERR_PTR(-ENOSYS);
+}
+static inline int gpio_hog_count(struct device *dev)
+{
+	return 0;
+}
+static inline bool gpio_is_hogged(struct device *dev, unsigned gpio)
+{
+	return false;
+}
 static inline void gpiod_put(struct gpio_desc *desc)
 {
 	might_sleep();
@@ -94,6 +113,12 @@  struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
 {
 	return ERR_PTR(-ENOSYS);
 }
+static inline
+struct gpio_desc *__must_check devm_gpiod_get_hog_index(struct device *dev,
+							unsigned int idx)
+{
+	return ERR_PTR(-ENOSYS);
+}
 static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
 {
 	might_sleep();
diff --git a/include/linux/gpio/devinfo.h b/include/linux/gpio/devinfo.h
new file mode 100644
index 0000000..010c59b
--- /dev/null
+++ b/include/linux/gpio/devinfo.h
@@ -0,0 +1,38 @@ 
+/*
+ * Per-device information from the GPIO system.
+ * This is the stuff that get included into the device
+ * core.
+ *
+ * Copyright (C) Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * Author: Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef GPIO_DEVINFO_H
+#define GPIO_DEVINFO_H
+
+#ifdef CONFIG_GPIOLIB
+
+/* The device core acts as a consumer toward GPIO */
+#include <linux/gpio/consumer.h>
+
+struct dev_gpio_info {
+	int ngpios;
+	struct gpio_desc *gpios[0];
+};
+
+extern int gpio_get_hogs(struct device *dev);
+
+#else
+
+/* Stubs if we're not using GPIO hogs */
+
+static inline int gpio_get_hogs(struct device *dev)
+{
+	return 0;
+}
+
+#endif /* CONFIG_GPIOLIB */
+#endif /* GPIO_DEVINFO_H */
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index f14123a..43f7f86 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -60,6 +60,11 @@  extern int of_gpio_simple_xlate(struct gpio_chip *gc,
 				const struct of_phandle_args *gpiospec,
 				u32 *flags);
 
+extern int of_gpio_hog_count(struct device_node *np);
+extern struct gpio_desc *of_get_gpio_hog(struct device_node *np, int index,
+					 const char **name,
+					 const char **lnk_name,
+					 unsigned long *flags);
 #else /* CONFIG_OF_GPIO */
 
 /* Drivers may not strictly depend on the GPIO support, so let them link. */
@@ -79,6 +84,20 @@  static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
 static inline void of_gpiochip_add(struct gpio_chip *gc) { }
 static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
 
+static inline int of_gpio_hog_count(struct device_node *np)
+{
+	return 0;
+}
+
+static inline struct gpio_desc *of_get_gpio_hog(struct device_node *np,
+						int index,
+						const char **name,
+						const char **lnk_name,
+						unsigned long *flags)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
 #endif /* CONFIG_OF_GPIO */
 
 static inline int of_get_named_gpio_flags(struct device_node *np,