devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFD] Sharing GPIOs for input (buttons) and output (LEDs)
@ 2016-02-22 12:14 Geert Uytterhoeven
  2016-03-17 10:18 ` Linus Walleij
  0 siblings, 1 reply; 4+ messages in thread
From: Geert Uytterhoeven @ 2016-02-22 12:14 UTC (permalink / raw)
  To: linux-gpio, linux-leds, devicetree; +Cc: linux-renesas-soc, linux-kernel

TL;DR: If a GPIO is connected to both a push button and an LED, can we
(1) still use both, or can we (2) chose which one to use?
This affects both the hardware description in DT and user policies.


Introduction
------------

On the Renesas Salvator-X development board, 3 GPIO pins are connected to both
push buttons and LEDs.
  - If the GPIO is configured for output, it can control the LED,
  - If the GPIO is configured for input, the push button status can be
    read. Note that the LED is on if the push button is not pressed; it is
    turned off while holding the button.


DT Hardware Description
-----------------------

There exist device tree bindings for push buttons connected to GPIOs,
and the following works:

        keyboard {
                compatible = "gpio-keys";

                key-a {
                        gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
                        label = "SW20";
                        wakeup-source;
                        linux,code = <KEY_A>;
                };
                key-b {
                        gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
                        label = "SW21";
                        wakeup-source;
                        linux,code = <KEY_B>;
                };
                key-c {
                        gpios = <&gpio6 13 GPIO_ACTIVE_LOW>;
                        label = "SW22";
                        wakeup-source;
                        linux,code = <KEY_C>;
                };
        };


There exist device tree bindings for LEDs connected to GPIOs, and the
following also works:

        leds {
                compatible = "gpio-leds";

                led4 {
                        gpios = <&gpio6 11 GPIO_ACTIVE_HIGH>;
                        label = "LED4";
                };
                led5 {
                        gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
                        label = "LED5";
                };
                led6 {
                        gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>;
                        label = "LED6";
                };
        };


However, having both in the DTS doesn't mean you'll have working buttons
and LEDs. The first driver initialized will bind to the GPIOs. The
second driver will fail to initialize as the GPIOs are already busy.

One option to solve this is to introduce new bindings for GPIOs shared
by push buttons and LEDs. But that isn't without its own set of
problems. E.g. in my case the buttons use GPIO_ACTIVE_LOW, while the
LEDs use GPIO_ACTIVE_HIGH (I'm sure other combinations are possible),
which is supposed to be encoded in the GPIO descriptor.

Hence I'm inclined to keep the existing bindings, as they do describe
the hardware.


Device Driver
-------------

As a proof-of-concept, I hacked up a new driver that binds to both
"gpio-keys" and "gpio-leds", by combining the existing gpio-keys-polled
and gpio-leds drivers.

If a GPIO is found busy during initialization, and if it's already in
use by the other half of the driver, the driver switches to a special
"polled-key-and-LED" mode. I.e. during polling, it does:
  - Save the GPIO output state,
  - Switch the GPIO to input mode,
  - Wait 5 ms (else it will read the old output state, depending on
    e.g. hardware capacitance),
  - Read the GPIO input state,
  - Switch the GPIO to output mode,
  - Restore the GPIO output state.

And it works, the LEDs can be controlled, and the push button states can
be read!

However, due to the 5 ms delay, there's a visible flickering of LEDs
that are supposed to be turned off (remember, when the GPIO is
configured for input and the button is not pressed, the LED is lit).

If we go this route, adding support for non-polled GPIOs (if the GPIO is
not shared with an LED) and wake-up should be doable.


User Policies
-------------

Hence we can have support for GPIOs connected to both push buttons and
LEDs. But perhaps the user doesn't want to use both at the same time,
or not for all GPIOs. On a final product this is probably not the case,
but it is on a development board like Salvator-X.

If it wasn't for the visible flickering when both are enabled, this
wouldn't matter. But the flickering may be considered annoying, so it
would be good if the user could disable either the push button or LED by
software.

One option is to disable the keyboard node using a DT overlay. But
that's cheating, as it modifies the hardware description, while this is
clearly a user policy.

Another use case would be to use the LEDs, and not the buttons, except
for system wake-up. Then there wouldn't be a need to poll during normal
system operation.


Thanks for your comments!

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFD] Sharing GPIOs for input (buttons) and output (LEDs)
  2016-02-22 12:14 [RFD] Sharing GPIOs for input (buttons) and output (LEDs) Geert Uytterhoeven
@ 2016-03-17 10:18 ` Linus Walleij
  2016-03-22 13:59   ` Vaibhav Hiremath
  0 siblings, 1 reply; 4+ messages in thread
From: Linus Walleij @ 2016-03-17 10:18 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: linux-gpio, linux-leds, devicetree, linux-renesas-soc, linux-kernel

On Mon, Feb 22, 2016 at 1:14 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:

> On the Renesas Salvator-X development board, 3 GPIO pins are connected to both
> push buttons and LEDs.
>   - If the GPIO is configured for output, it can control the LED,
>   - If the GPIO is configured for input, the push button status can be
>     read. Note that the LED is on if the push button is not pressed; it is
>     turned off while holding the button.

Have you asked the hardware engineer who did this construction
what s/he was thinking? And I mean seriously: what was the
usecase? Did they really design the LEDs to be used to flicker
with or just as an indication as to whether the button was being
pushed or not?

Your approach seems dedicated to use it for both usecases (also
as a stand-alone heartbeat or whatever) but was that really
intended?

>         keyboard {
>                 compatible = "gpio-keys";
>
>                 key-a {
>                         gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
>                         label = "SW20";
>                         wakeup-source;
>                         linux,code = <KEY_A>;
>                 };
>                 key-b {
>                         gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
>                         label = "SW21";
>                         wakeup-source;
>                         linux,code = <KEY_B>;
>                 };
>                 key-c {
>                         gpios = <&gpio6 13 GPIO_ACTIVE_LOW>;
>                         label = "SW22";
>                         wakeup-source;
>                         linux,code = <KEY_C>;
>                 };
>         };

I suspect that in this usecase, the GPIO should be flagged
GPIO_OPEN_DRAIN rather than GPIO_ACTIVE_LOW,
as the construction with the LED draws current fron the line.

> There exist device tree bindings for LEDs connected to GPIOs, and the
> following also works:
>
>         leds {
>                 compatible = "gpio-leds";
>
>                 led4 {
>                         gpios = <&gpio6 11 GPIO_ACTIVE_HIGH>;
>                         label = "LED4";
>                 };
>                 led5 {
>                         gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
>                         label = "LED5";
>                 };
>                 led6 {
>                         gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>;
>                         label = "LED6";
>                 };
>         };

OK

> If a GPIO is found busy during initialization, and if it's already in
> use by the other half of the driver, the driver switches to a special
> "polled-key-and-LED" mode. I.e. during polling, it does:
>   - Save the GPIO output state,
>   - Switch the GPIO to input mode,
>   - Wait 5 ms (else it will read the old output state, depending on
>     e.g. hardware capacitance),
>   - Read the GPIO input state,
>   - Switch the GPIO to output mode,
>   - Restore the GPIO output state.
>
> And it works, the LEDs can be controlled, and the push button states can
> be read!

Why go to such troubles of switching the line from output to
input to read it?

Especially when a line is OPEN_DRAIN it should be perfectly legal
to read it's value even if it is set as output, but AFAICT that is
always working no matter whether the line is set as output.

> However, due to the 5 ms delay, there's a visible flickering of LEDs
> that are supposed to be turned off (remember, when the GPIO is
> configured for input and the button is not pressed, the LED is lit).
>
> If we go this route, adding support for non-polled GPIOs (if the GPIO is
> not shared with an LED) and wake-up should be doable.

I think this actually implies OPEN_DRAIN and if you flag it as such
the core should be happy using it as input and output at the same
time.

If the hardware has a problem with reading the value from a line
that is set to output, it needs a workaround hack in the driver to
support reading and output line, *NOT* changes to gpiolib,
because the lib assumes this is always possible, i.e. it will
call the driver .get() callback no matter what.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFD] Sharing GPIOs for input (buttons) and output (LEDs)
  2016-03-17 10:18 ` Linus Walleij
@ 2016-03-22 13:59   ` Vaibhav Hiremath
  2016-03-22 14:18     ` Linus Walleij
  0 siblings, 1 reply; 4+ messages in thread
From: Vaibhav Hiremath @ 2016-03-22 13:59 UTC (permalink / raw)
  To: Linus Walleij, Geert Uytterhoeven
  Cc: linux-gpio, linux-leds, devicetree, linux-renesas-soc, linux-kernel



On Thursday 17 March 2016 03:48 PM, Linus Walleij wrote:
> On Mon, Feb 22, 2016 at 1:14 PM, Geert Uytterhoeven
> <geert@linux-m68k.org> wrote:
>
>> On the Renesas Salvator-X development board, 3 GPIO pins are connected to both
>> push buttons and LEDs.

Not exactly related to buttons and leds,
but recently I came across another usecase of shared gpio,

Say, for example, we have multiple external I2C peripheral which share
interrupt line over gpio (ofcourse irq line is muxed onto single gpio).

Now in kernel I would have multiple instances of driver supporting each
peripheral but gpio can not be shared for registering irq.

Do you suggest MFD driver for such simple usecases ? Should gpiolib
support SHARED gpios, and gpiolib can define all the policies over
configuration (input only, what about conflicts, bidirectional mode?)

Thanks,
Vaibhav


>>    - If the GPIO is configured for output, it can control the LED,
>>    - If the GPIO is configured for input, the push button status can be
>>      read. Note that the LED is on if the push button is not pressed; it is
>>      turned off while holding the button.
>
> Have you asked the hardware engineer who did this construction
> what s/he was thinking? And I mean seriously: what was the
> usecase? Did they really design the LEDs to be used to flicker
> with or just as an indication as to whether the button was being
> pushed or not?
>
> Your approach seems dedicated to use it for both usecases (also
> as a stand-alone heartbeat or whatever) but was that really
> intended?
>
>>          keyboard {
>>                  compatible = "gpio-keys";
>>
>>                  key-a {
>>                          gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
>>                          label = "SW20";
>>                          wakeup-source;
>>                          linux,code = <KEY_A>;
>>                  };
>>                  key-b {
>>                          gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
>>                          label = "SW21";
>>                          wakeup-source;
>>                          linux,code = <KEY_B>;
>>                  };
>>                  key-c {
>>                          gpios = <&gpio6 13 GPIO_ACTIVE_LOW>;
>>                          label = "SW22";
>>                          wakeup-source;
>>                          linux,code = <KEY_C>;
>>                  };
>>          };
>
> I suspect that in this usecase, the GPIO should be flagged
> GPIO_OPEN_DRAIN rather than GPIO_ACTIVE_LOW,
> as the construction with the LED draws current fron the line.
>
>> There exist device tree bindings for LEDs connected to GPIOs, and the
>> following also works:
>>
>>          leds {
>>                  compatible = "gpio-leds";
>>
>>                  led4 {
>>                          gpios = <&gpio6 11 GPIO_ACTIVE_HIGH>;
>>                          label = "LED4";
>>                  };
>>                  led5 {
>>                          gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
>>                          label = "LED5";
>>                  };
>>                  led6 {
>>                          gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>;
>>                          label = "LED6";
>>                  };
>>          };
>
> OK
>
>> If a GPIO is found busy during initialization, and if it's already in
>> use by the other half of the driver, the driver switches to a special
>> "polled-key-and-LED" mode. I.e. during polling, it does:
>>    - Save the GPIO output state,
>>    - Switch the GPIO to input mode,
>>    - Wait 5 ms (else it will read the old output state, depending on
>>      e.g. hardware capacitance),
>>    - Read the GPIO input state,
>>    - Switch the GPIO to output mode,
>>    - Restore the GPIO output state.
>>
>> And it works, the LEDs can be controlled, and the push button states can
>> be read!
>
> Why go to such troubles of switching the line from output to
> input to read it?
>
> Especially when a line is OPEN_DRAIN it should be perfectly legal
> to read it's value even if it is set as output, but AFAICT that is
> always working no matter whether the line is set as output.
>
>> However, due to the 5 ms delay, there's a visible flickering of LEDs
>> that are supposed to be turned off (remember, when the GPIO is
>> configured for input and the button is not pressed, the LED is lit).
>>
>> If we go this route, adding support for non-polled GPIOs (if the GPIO is
>> not shared with an LED) and wake-up should be doable.
>
> I think this actually implies OPEN_DRAIN and if you flag it as such
> the core should be happy using it as input and output at the same
> time.
>
> If the hardware has a problem with reading the value from a line
> that is set to output, it needs a workaround hack in the driver to
> support reading and output line, *NOT* changes to gpiolib,
> because the lib assumes this is always possible, i.e. it will
> call the driver .get() callback no matter what.
>
> 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
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RFD] Sharing GPIOs for input (buttons) and output (LEDs)
  2016-03-22 13:59   ` Vaibhav Hiremath
@ 2016-03-22 14:18     ` Linus Walleij
  0 siblings, 0 replies; 4+ messages in thread
From: Linus Walleij @ 2016-03-22 14:18 UTC (permalink / raw)
  To: Vaibhav Hiremath
  Cc: Geert Uytterhoeven, linux-gpio, linux-leds, devicetree,
	linux-renesas-soc, linux-kernel

On Tue, Mar 22, 2016 at 2:59 PM, Vaibhav Hiremath
<vaibhav.hiremath@linaro.org> wrote:
> On Thursday 17 March 2016 03:48 PM, Linus Walleij wrote:

> but recently I came across another usecase of shared gpio,
>
> Say, for example, we have multiple external I2C peripheral which share
> interrupt line over gpio (ofcourse irq line is muxed onto single gpio).
>
> Now in kernel I would have multiple instances of driver supporting each
> peripheral but gpio can not be shared for registering irq.
>
> Do you suggest MFD driver for such simple usecases ? Should gpiolib
> support SHARED gpios, and gpiolib can define all the policies over
> configuration

I don't see why you would want to use MFD at all.

Not shared GPIOs but shared interrupt lines.

If you're using device tree is is pretty straight forward:

- Make sure the GPIOlib and irqchip portions of the driver
  are totally orthogonal. (See Documentation/gpio/driver.txt
  section "GPIO drivers providing IRQs")

- Just use the irqchip side of the GPIO

- Make sure your consumers check if the IRQ is theirs
  and return IRQ_HANDLED vs NO_IRQ depending on
  whether it's theirs or not.

It is quite obvious from context that in this case all consumers
are using an open drain (if active low) scheme. However
since the GPIO is then used as input it has no effect, it is
more a question for the consumers to assure their IRQ
logic is not using push-pull but rather open drain or you will
get a disaster in the totempole...

> (input only, what about conflicts, bidirectional mode?)

We thought about this, see Documentation/gpio/driver.txt section
Locking IRQ usage".

When the line is locked for IRQ usage, it cannot be switched to
output.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2016-03-22 14:18 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-22 12:14 [RFD] Sharing GPIOs for input (buttons) and output (LEDs) Geert Uytterhoeven
2016-03-17 10:18 ` Linus Walleij
2016-03-22 13:59   ` Vaibhav Hiremath
2016-03-22 14:18     ` Linus Walleij

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).