Re: [PATCH] gpio: xilinx: Add interrupt support

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

 



sob., 6 cze 2020 o 01:57 Robert Hancock <hancock@xxxxxxxxxxxxx> napisał(a):
>
> Adds interrupt support to the Xilinx GPIO driver so that rising and
> falling edge line events can be supported. Since interrupt support is
> an optional feature in the Xilinx IP, the driver continues to support
> devices which have no interrupt provided.
>
> These changes are based on a patch in the Xilinx Linux Git tree,
> "gpio: xilinx: Add irq support to the driver" from Srinivas Neeli, but
> include a number of fixes and improvements such as supporting both
> rising and falling edge events.
>
> Signed-off-by: Robert Hancock <hancock@xxxxxxxxxxxxx>
> ---
>  drivers/gpio/Kconfig       |   1 +
>  drivers/gpio/gpio-xilinx.c | 247 ++++++++++++++++++++++++++++++++++---
>  2 files changed, 233 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index bcacd9c74aa80..5f91e7829fb7d 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -652,6 +652,7 @@ config GPIO_XGENE_SB
>
>  config GPIO_XILINX
>         tristate "Xilinx GPIO support"
> +       select GPIOLIB_IRQCHIP
>         help
>           Say yes here to support the Xilinx FPGA GPIO device
>
> diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
> index 67f9f82e0db0e..42ae12801d0bf 100644
> --- a/drivers/gpio/gpio-xilinx.c
> +++ b/drivers/gpio/gpio-xilinx.c
> @@ -14,6 +14,9 @@
>  #include <linux/io.h>
>  #include <linux/gpio/driver.h>
>  #include <linux/slab.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip/chained_irq.h>
>
>  /* Register Offset Definitions */
>  #define XGPIO_DATA_OFFSET   (0x0)      /* Data register  */
> @@ -21,6 +24,11 @@
>
>  #define XGPIO_CHANNEL_OFFSET   0x8
>
> +#define XGPIO_GIER_OFFSET      0x11c /* Global Interrupt Enable */
> +#define XGPIO_GIER_IE          BIT(31)
> +#define XGPIO_IPISR_OFFSET     0x120 /* IP Interrupt Status */
> +#define XGPIO_IPIER_OFFSET     0x128 /* IP Interrupt Enable */
> +
>  /* Read/Write access to the GPIO registers */
>  #if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86)
>  # define xgpio_readreg(offset)         readl(offset)
> @@ -35,17 +43,27 @@
>   * @gc: GPIO chip
>   * @regs: register block
>   * @gpio_width: GPIO width for every channel
> - * @gpio_state: GPIO state shadow register
> + * @gpio_state: GPIO write state shadow register
> + * @gpio_last_irq_read: GPIO read state register from last interrupt
>   * @gpio_dir: GPIO direction shadow register
>   * @gpio_lock: Lock used for synchronization
> + * @irq: IRQ used by GPIO device
> + * @irq_enable: GPIO irq enable/disable bitfield
> + * @irq_rising_edge: GPIO irq rising edge enable/disable bitfield
> + * @irq_falling_edge: GPIO irq rising edge enable/disable bitfield
>   */
>  struct xgpio_instance {
>         struct gpio_chip gc;
>         void __iomem *regs;
>         unsigned int gpio_width[2];
>         u32 gpio_state[2];
> +       u32 gpio_last_irq_read[2];
>         u32 gpio_dir[2];
> -       spinlock_t gpio_lock[2];
> +       spinlock_t gpio_lock;
> +       int irq;
> +       u32 irq_enable[2];
> +       u32 irq_rising_edge[2];
> +       u32 irq_falling_edge[2];

I don't know this driver very well. Could you explain why the two
instances of these fields and why are you removing the second lock?

[snip!]

>         chip->gc.base = -1;
> @@ -336,6 +530,29 @@ static int xgpio_probe(struct platform_device *pdev)
>
>         xgpio_save_regs(chip);
>
> +       chip->irq = platform_get_irq(pdev, 0);

Why not simply: platform_get_irq_optional()?

> +       if (chip->irq <= 0) {
> +               dev_info(&pdev->dev, "GPIO IRQ not set\n");
> +       } else {
> +               u32 temp;
> +
> +               /* Disable per-channel interrupts */
> +               xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, 0);
> +               /* Clear any existing per-channel interrupts */
> +               temp = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET);
> +               xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, temp);
> +               /* Enable global interrupts */
> +               xgpio_writereg(chip->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE);
> +
> +               chip->gc.irq.chip = &xgpio_irqchip;
> +               chip->gc.irq.handler = handle_bad_irq;
> +               chip->gc.irq.default_type = IRQ_TYPE_NONE;
> +               chip->gc.irq.parent_handler = xgpio_irqhandler;
> +               chip->gc.irq.parent_handler_data = chip;
> +               chip->gc.irq.parents = &chip->irq;
> +               chip->gc.irq.num_parents = 1;
> +       }
> +
>         status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
>         if (status) {
>                 dev_err(&pdev->dev, "failed to add GPIO chip\n");
> --
> 2.26.2
>

Bart




[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