Re: [RFC PATCH] gpiolib: call gpiochip_(un)lock_as_irq for dis/enable_irq()

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

 



Hi Hans,

On Sat, 21 Jul 2018 09:46:19 +0100,
Hans Verkuil <hverkuil@xxxxxxxxx> wrote:
> 
> Hi Linus,
> 
> On 20/07/18 10:06, Linus Walleij wrote:
> 
> <snip>
> 
> > You would probably think it's fine if you didn't have to do this
> > heavy lifting and could just request them on probe and
> > call enable_irq() and disable_irq() when needed, and have these
> > call down into the irq_chip .irq_enable() and .irq_disable() and
> > lock the GPIO line as input *there* instead, and then change
> > this everywhere (yes patch all gpio_chips with an irqchip
> > driver in that case).
> > 
> > As drivers have likely sometimes already assigned function
> > pointers to .irq_enable() and .irq_disable() these have to
> > be copied and stored in struct gpio_irq_chip() by
> > gpiochip_set_cascaded_irqchip() and called in sequence.
> > But it can be done.
> > 
> > What about changing the GPIOLIB_IRQCHIP code to just
> > do the module_get()/put() part on .irq_request_resources()
> > and move the locking to the .irq_enable()/.irq_disable()
> > callbacks so that we can enable and disable irqs on the fly
> > in a better way? (BIG WIN!)
> > 
> > What about going and reinvestigating this instead?
> > 
> > I'm sorry that I can't present any simple solution, but hey,
> > I presented a really complicated solution instead, isn't it
> > great! :D
> 
> I did do some investigation into this, but it made me very unhappy:
> it's a lot of low-level changes in a lot of drivers for a lot of
> different boards, some of which are probably hard to test. Scary.
> 
> But I've come up with a much simpler alternative: add two new
> gpiolib functions: gpiod_enable_irq and gpiod_disable_irq.
> 
> An RFC patch is below (documentation is missing, but it works fine).
> 
> Basically if you have a gpio which has an interrupt, then you can use
> these functions to disable and enable it. It enables/disables the interrupt
> and calls gpiochip_(un)lock_as_irq() as well.
> 
> It is even possible to call gpiod_direction_input in gpiod_enable_irq to ensure
> that the direction is set correctly. I have not done so, but if you think it is
> useful, then it's trivial to do. Right now it will return an error if the
> direction is still set to output.
> 
> If there is no associated interrupt, then gpiod_enable_irq just returns 0. Not
> sure if that's a bug or a feature. It's easy enough to change.
> 
> Let me know what you think. IMHO this avoids a huge amount of churn in code you
> really do no want to touch and it does exactly what you want it to do. And it
> looks pretty clean as well, both in gpiolib and in the drivers.
> 
> Regards,
> 
> 	Hans
> 
> Signed-off-by: Hans Verkuil <hansverk@xxxxxxxxx>
> ---
>  drivers/gpio/gpiolib.c        | 83 ++++++++++++++++++++++++++---------
>  include/linux/gpio/consumer.h |  3 ++
>  2 files changed, 66 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index e11a3bb03820..75ad6177fa95 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -3228,28 +3228,16 @@ int gpiod_to_irq(const struct gpio_desc *desc)
>  }
>  EXPORT_SYMBOL_GPL(gpiod_to_irq);
> 
> -/**
> - * gpiochip_lock_as_irq() - lock a GPIO to be used as IRQ
> - * @chip: the chip the GPIO to lock belongs to
> - * @offset: the offset of the GPIO to lock as IRQ
> - *
> - * This is used directly by GPIO drivers that want to lock down
> - * a certain GPIO line to be used for IRQs.
> - */
> -int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
> +static int gpiodesc_lock_as_irq(struct gpio_desc *desc)
>  {
> -	struct gpio_desc *desc;
> -
> -	desc = gpiochip_get_desc(chip, offset);
> -	if (IS_ERR(desc))
> -		return PTR_ERR(desc);
> +	struct gpio_chip *chip = gpiod_to_chip(desc);
> 
>  	/*
>  	 * If it's fast: flush the direction setting if something changed
>  	 * behind our back
>  	 */
>  	if (!chip->can_sleep && chip->get_direction) {
> -		int dir = chip->get_direction(chip, offset);
> +		int dir = chip->get_direction(chip, gpio_chip_hwgpio(desc));
> 
>  		if (dir)
>  			clear_bit(FLAG_IS_OUT, &desc->flags);
> @@ -3276,8 +3264,53 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
> 
>  	return 0;
>  }
> +
> +/**
> + * gpiochip_lock_as_irq() - lock a GPIO to be used as IRQ
> + * @chip: the chip the GPIO to lock belongs to
> + * @offset: the offset of the GPIO to lock as IRQ
> + *
> + * This is used directly by GPIO drivers that want to lock down
> + * a certain GPIO line to be used for IRQs.
> + */
> +int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
> +{
> +	struct gpio_desc *desc;
> +
> +	desc = gpiochip_get_desc(chip, offset);
> +	if (IS_ERR(desc))
> +		return PTR_ERR(desc);
> +	return gpiodesc_lock_as_irq(desc);
> +}
>  EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
> 
> +int gpiod_enable_irq(struct gpio_desc *desc)
> +{
> +	int irq;
> +	int ret;
> +
> +	VALIDATE_DESC(desc);
> +
> +	irq = gpiod_to_irq(desc);
> +	if (irq < 0)
> +		return 0;
> +
> +	ret = gpiodesc_lock_as_irq(desc);
> +	if (!ret)
> +		enable_irq(irq);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(gpiod_enable_irq);

{enable,disable}_irq() are supposed to allow nesting. Do you intent to
preserve the same semantics? This is specially important if you allow
sharing of the interrupt line between devices.

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux