forked from mirrors/linux
		
	Merge branch irq/gpio-immutable into irq/irqchip-next
* irq/gpio-immutable: : . : First try at preventing the GPIO subsystem from abusing irq_chip : data structures. The general idea is to have an irq_chip flag : to tell the GPIO subsystem that these structures are immutable, : and to convert drivers one by one. : . Documentation: Update the recommended pattern for GPIO irqchips gpio: Update TODO to mention immutable irq_chip structures pinctrl: amd: Make the irqchip immutable pinctrl: msmgpio: Make the irqchip immutable pinctrl: apple-gpio: Make the irqchip immutable gpio: pl061: Make the irqchip immutable gpio: tegra186: Make the irqchip immutable gpio: Add helpers to ease the transition towards immutable irq_chip gpio: Expose the gpiochip_irq_re[ql]res helpers gpio: Don't fiddle with irqchips marked as immutable Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
		
						commit
						4bde53ab33
					
				
					 11 changed files with 293 additions and 90 deletions
				
			
		| 
						 | 
					@ -417,30 +417,66 @@ struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
 | 
				
			||||||
If you do this, the additional irq_chip will be set up by gpiolib at the
 | 
					If you do this, the additional irq_chip will be set up by gpiolib at the
 | 
				
			||||||
same time as setting up the rest of the GPIO functionality. The following
 | 
					same time as setting up the rest of the GPIO functionality. The following
 | 
				
			||||||
is a typical example of a chained cascaded interrupt handler using
 | 
					is a typical example of a chained cascaded interrupt handler using
 | 
				
			||||||
the gpio_irq_chip:
 | 
					the gpio_irq_chip. Note how the mask/unmask (or disable/enable) functions
 | 
				
			||||||
 | 
					call into the core gpiolib code:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: c
 | 
					.. code-block:: c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Typical state container with dynamic irqchip */
 | 
					  /* Typical state container */
 | 
				
			||||||
  struct my_gpio {
 | 
					  struct my_gpio {
 | 
				
			||||||
      struct gpio_chip gc;
 | 
					      struct gpio_chip gc;
 | 
				
			||||||
      struct irq_chip irq;
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static void my_gpio_mask_irq(struct irq_data *d)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					      struct gpio_chip *gc = irq_desc_get_handler_data(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /*
 | 
				
			||||||
 | 
					       * Perform any necessary action to mask the interrupt,
 | 
				
			||||||
 | 
					       * and then call into the core code to synchronise the
 | 
				
			||||||
 | 
					       * state.
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      gpiochip_disable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static void my_gpio_unmask_irq(struct irq_data *d)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					      struct gpio_chip *gc = irq_desc_get_handler_data(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      gpiochip_enable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /*
 | 
				
			||||||
 | 
					       * Perform any necessary action to unmask the interrupt,
 | 
				
			||||||
 | 
					       * after having called into the core code to synchronise
 | 
				
			||||||
 | 
					       * the state.
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					   * Statically populate the irqchip. Note that it is made const
 | 
				
			||||||
 | 
					   * (further indicated by the IRQCHIP_IMMUTABLE flag), and that
 | 
				
			||||||
 | 
					   * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra
 | 
				
			||||||
 | 
					   * callbacks to the structure.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static const struct irq_chip my_gpio_irq_chip = {
 | 
				
			||||||
 | 
					      .name		= "my_gpio_irq",
 | 
				
			||||||
 | 
					      .irq_ack		= my_gpio_ack_irq,
 | 
				
			||||||
 | 
					      .irq_mask		= my_gpio_mask_irq,
 | 
				
			||||||
 | 
					      .irq_unmask	= my_gpio_unmask_irq,
 | 
				
			||||||
 | 
					      .irq_set_type	= my_gpio_set_irq_type,
 | 
				
			||||||
 | 
					      .flags		= IRQCHIP_IMMUTABLE,
 | 
				
			||||||
 | 
					      /* Provide the gpio resource callbacks */
 | 
				
			||||||
 | 
					      GPIOCHIP_IRQ_RESOURCE_HELPERS,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int irq; /* from platform etc */
 | 
					  int irq; /* from platform etc */
 | 
				
			||||||
  struct my_gpio *g;
 | 
					  struct my_gpio *g;
 | 
				
			||||||
  struct gpio_irq_chip *girq;
 | 
					  struct gpio_irq_chip *girq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Set up the irqchip dynamically */
 | 
					 | 
				
			||||||
  g->irq.name = "my_gpio_irq";
 | 
					 | 
				
			||||||
  g->irq.irq_ack = my_gpio_ack_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_mask = my_gpio_mask_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_unmask = my_gpio_unmask_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_set_type = my_gpio_set_irq_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Get a pointer to the gpio_irq_chip */
 | 
					  /* Get a pointer to the gpio_irq_chip */
 | 
				
			||||||
  girq = &g->gc.irq;
 | 
					  girq = &g->gc.irq;
 | 
				
			||||||
  girq->chip = &g->irq;
 | 
					  gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip);
 | 
				
			||||||
  girq->parent_handler = ftgpio_gpio_irq_handler;
 | 
					  girq->parent_handler = ftgpio_gpio_irq_handler;
 | 
				
			||||||
  girq->num_parents = 1;
 | 
					  girq->num_parents = 1;
 | 
				
			||||||
  girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
 | 
					  girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
 | 
				
			||||||
| 
						 | 
					@ -458,23 +494,58 @@ the interrupt separately and go with it:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: c
 | 
					.. code-block:: c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Typical state container with dynamic irqchip */
 | 
					  /* Typical state container */
 | 
				
			||||||
  struct my_gpio {
 | 
					  struct my_gpio {
 | 
				
			||||||
      struct gpio_chip gc;
 | 
					      struct gpio_chip gc;
 | 
				
			||||||
      struct irq_chip irq;
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static void my_gpio_mask_irq(struct irq_data *d)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					      struct gpio_chip *gc = irq_desc_get_handler_data(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /*
 | 
				
			||||||
 | 
					       * Perform any necessary action to mask the interrupt,
 | 
				
			||||||
 | 
					       * and then call into the core code to synchronise the
 | 
				
			||||||
 | 
					       * state.
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      gpiochip_disable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static void my_gpio_unmask_irq(struct irq_data *d)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					      struct gpio_chip *gc = irq_desc_get_handler_data(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      gpiochip_enable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /*
 | 
				
			||||||
 | 
					       * Perform any necessary action to unmask the interrupt,
 | 
				
			||||||
 | 
					       * after having called into the core code to synchronise
 | 
				
			||||||
 | 
					       * the state.
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					   * Statically populate the irqchip. Note that it is made const
 | 
				
			||||||
 | 
					   * (further indicated by the IRQCHIP_IMMUTABLE flag), and that
 | 
				
			||||||
 | 
					   * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra
 | 
				
			||||||
 | 
					   * callbacks to the structure.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static const struct irq_chip my_gpio_irq_chip = {
 | 
				
			||||||
 | 
					      .name		= "my_gpio_irq",
 | 
				
			||||||
 | 
					      .irq_ack		= my_gpio_ack_irq,
 | 
				
			||||||
 | 
					      .irq_mask		= my_gpio_mask_irq,
 | 
				
			||||||
 | 
					      .irq_unmask	= my_gpio_unmask_irq,
 | 
				
			||||||
 | 
					      .irq_set_type	= my_gpio_set_irq_type,
 | 
				
			||||||
 | 
					      .flags		= IRQCHIP_IMMUTABLE,
 | 
				
			||||||
 | 
					      /* Provide the gpio resource callbacks */
 | 
				
			||||||
 | 
					      GPIOCHIP_IRQ_RESOURCE_HELPERS,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int irq; /* from platform etc */
 | 
					  int irq; /* from platform etc */
 | 
				
			||||||
  struct my_gpio *g;
 | 
					  struct my_gpio *g;
 | 
				
			||||||
  struct gpio_irq_chip *girq;
 | 
					  struct gpio_irq_chip *girq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Set up the irqchip dynamically */
 | 
					 | 
				
			||||||
  g->irq.name = "my_gpio_irq";
 | 
					 | 
				
			||||||
  g->irq.irq_ack = my_gpio_ack_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_mask = my_gpio_mask_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_unmask = my_gpio_unmask_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_set_type = my_gpio_set_irq_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ret = devm_request_threaded_irq(dev, irq, NULL,
 | 
					  ret = devm_request_threaded_irq(dev, irq, NULL,
 | 
				
			||||||
		irq_thread_fn, IRQF_ONESHOT, "my-chip", g);
 | 
							irq_thread_fn, IRQF_ONESHOT, "my-chip", g);
 | 
				
			||||||
  if (ret < 0)
 | 
					  if (ret < 0)
 | 
				
			||||||
| 
						 | 
					@ -482,7 +553,7 @@ the interrupt separately and go with it:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Get a pointer to the gpio_irq_chip */
 | 
					  /* Get a pointer to the gpio_irq_chip */
 | 
				
			||||||
  girq = &g->gc.irq;
 | 
					  girq = &g->gc.irq;
 | 
				
			||||||
  girq->chip = &g->irq;
 | 
					  gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip);
 | 
				
			||||||
  /* This will let us handle the parent IRQ in the driver */
 | 
					  /* This will let us handle the parent IRQ in the driver */
 | 
				
			||||||
  girq->parent_handler = NULL;
 | 
					  girq->parent_handler = NULL;
 | 
				
			||||||
  girq->num_parents = 0;
 | 
					  girq->num_parents = 0;
 | 
				
			||||||
| 
						 | 
					@ -500,24 +571,61 @@ In this case the typical set-up will look like this:
 | 
				
			||||||
  /* Typical state container with dynamic irqchip */
 | 
					  /* Typical state container with dynamic irqchip */
 | 
				
			||||||
  struct my_gpio {
 | 
					  struct my_gpio {
 | 
				
			||||||
      struct gpio_chip gc;
 | 
					      struct gpio_chip gc;
 | 
				
			||||||
      struct irq_chip irq;
 | 
					 | 
				
			||||||
      struct fwnode_handle *fwnode;
 | 
					      struct fwnode_handle *fwnode;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int irq; /* from platform etc */
 | 
					  static void my_gpio_mask_irq(struct irq_data *d)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					      struct gpio_chip *gc = irq_desc_get_handler_data(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /*
 | 
				
			||||||
 | 
					       * Perform any necessary action to mask the interrupt,
 | 
				
			||||||
 | 
					       * and then call into the core code to synchronise the
 | 
				
			||||||
 | 
					       * state.
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      gpiochip_disable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					      irq_mask_mask_parent(d);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static void my_gpio_unmask_irq(struct irq_data *d)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					      struct gpio_chip *gc = irq_desc_get_handler_data(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      gpiochip_enable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /*
 | 
				
			||||||
 | 
					       * Perform any necessary action to unmask the interrupt,
 | 
				
			||||||
 | 
					       * after having called into the core code to synchronise
 | 
				
			||||||
 | 
					       * the state.
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      irq_mask_unmask_parent(d);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					   * Statically populate the irqchip. Note that it is made const
 | 
				
			||||||
 | 
					   * (further indicated by the IRQCHIP_IMMUTABLE flag), and that
 | 
				
			||||||
 | 
					   * the GPIOCHIP_IRQ_RESOURCE_HELPER macro adds some extra
 | 
				
			||||||
 | 
					   * callbacks to the structure.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static const struct irq_chip my_gpio_irq_chip = {
 | 
				
			||||||
 | 
					      .name		= "my_gpio_irq",
 | 
				
			||||||
 | 
					      .irq_ack		= my_gpio_ack_irq,
 | 
				
			||||||
 | 
					      .irq_mask		= my_gpio_mask_irq,
 | 
				
			||||||
 | 
					      .irq_unmask	= my_gpio_unmask_irq,
 | 
				
			||||||
 | 
					      .irq_set_type	= my_gpio_set_irq_type,
 | 
				
			||||||
 | 
					      .flags		= IRQCHIP_IMMUTABLE,
 | 
				
			||||||
 | 
					      /* Provide the gpio resource callbacks */
 | 
				
			||||||
 | 
					      GPIOCHIP_IRQ_RESOURCE_HELPERS,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct my_gpio *g;
 | 
					  struct my_gpio *g;
 | 
				
			||||||
  struct gpio_irq_chip *girq;
 | 
					  struct gpio_irq_chip *girq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Set up the irqchip dynamically */
 | 
					 | 
				
			||||||
  g->irq.name = "my_gpio_irq";
 | 
					 | 
				
			||||||
  g->irq.irq_ack = my_gpio_ack_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_mask = my_gpio_mask_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_unmask = my_gpio_unmask_irq;
 | 
					 | 
				
			||||||
  g->irq.irq_set_type = my_gpio_set_irq_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Get a pointer to the gpio_irq_chip */
 | 
					  /* Get a pointer to the gpio_irq_chip */
 | 
				
			||||||
  girq = &g->gc.irq;
 | 
					  girq = &g->gc.irq;
 | 
				
			||||||
  girq->chip = &g->irq;
 | 
					  gpio_irq_chip_set_chip(girq, &my_gpio_irq_chip);
 | 
				
			||||||
  girq->default_type = IRQ_TYPE_NONE;
 | 
					  girq->default_type = IRQ_TYPE_NONE;
 | 
				
			||||||
  girq->handler = handle_bad_irq;
 | 
					  girq->handler = handle_bad_irq;
 | 
				
			||||||
  girq->fwnode = g->fwnode;
 | 
					  girq->fwnode = g->fwnode;
 | 
				
			||||||
| 
						 | 
					@ -605,8 +713,9 @@ When implementing an irqchip inside a GPIO driver, these two functions should
 | 
				
			||||||
typically be called in the .irq_disable() and .irq_enable() callbacks from the
 | 
					typically be called in the .irq_disable() and .irq_enable() callbacks from the
 | 
				
			||||||
irqchip.
 | 
					irqchip.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When using the gpiolib irqchip helpers, these callbacks are automatically
 | 
					When IRQCHIP_IMMUTABLE is not advertised by the irqchip, these callbacks
 | 
				
			||||||
assigned.
 | 
					are automatically assigned. This behaviour is deprecated and on its way
 | 
				
			||||||
 | 
					to be removed from the kernel.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Real-Time compliance for GPIO IRQ chips
 | 
					Real-Time compliance for GPIO IRQ chips
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -178,3 +178,22 @@ discussed but the idea is to provide a low-level access point
 | 
				
			||||||
for debugging and hacking and to expose all lines without the
 | 
					for debugging and hacking and to expose all lines without the
 | 
				
			||||||
need of any exporting. Also provide ample ammunition to shoot
 | 
					need of any exporting. Also provide ample ammunition to shoot
 | 
				
			||||||
oneself in the foot, because this is debugfs after all.
 | 
					oneself in the foot, because this is debugfs after all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Moving over to immutable irq_chip structures
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Most of the gpio chips implementing interrupt support rely on gpiolib
 | 
				
			||||||
 | 
					intercepting some of the irq_chip callbacks, preventing the structures
 | 
				
			||||||
 | 
					from being made read-only and forcing duplication of structures that
 | 
				
			||||||
 | 
					should otherwise be unique.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The solution is to call into the gpiolib code when needed (resource
 | 
				
			||||||
 | 
					management, enable/disable or unmask/mask callbacks), and to let the
 | 
				
			||||||
 | 
					core code know about that by exposing a flag (IRQCHIP_IMMUTABLE) in
 | 
				
			||||||
 | 
					the irq_chip structure. The irq_chip structure can then be made unique
 | 
				
			||||||
 | 
					and const.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A small number of drivers have been converted (pl061, tegra186, msm,
 | 
				
			||||||
 | 
					amd, apple), and can be used as examples of how to proceed with this
 | 
				
			||||||
 | 
					conversion. Note that drivers using the generic irqchip framework
 | 
				
			||||||
 | 
					cannot be converted yet, but watch this space!
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,6 @@ struct pl061 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void __iomem		*base;
 | 
						void __iomem		*base;
 | 
				
			||||||
	struct gpio_chip	gc;
 | 
						struct gpio_chip	gc;
 | 
				
			||||||
	struct irq_chip		irq_chip;
 | 
					 | 
				
			||||||
	int			parent_irq;
 | 
						int			parent_irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PM
 | 
					#ifdef CONFIG_PM
 | 
				
			||||||
| 
						 | 
					@ -241,6 +240,8 @@ static void pl061_irq_mask(struct irq_data *d)
 | 
				
			||||||
	gpioie = readb(pl061->base + GPIOIE) & ~mask;
 | 
						gpioie = readb(pl061->base + GPIOIE) & ~mask;
 | 
				
			||||||
	writeb(gpioie, pl061->base + GPIOIE);
 | 
						writeb(gpioie, pl061->base + GPIOIE);
 | 
				
			||||||
	raw_spin_unlock(&pl061->lock);
 | 
						raw_spin_unlock(&pl061->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_disable_irq(gc, d->hwirq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pl061_irq_unmask(struct irq_data *d)
 | 
					static void pl061_irq_unmask(struct irq_data *d)
 | 
				
			||||||
| 
						 | 
					@ -250,6 +251,8 @@ static void pl061_irq_unmask(struct irq_data *d)
 | 
				
			||||||
	u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
 | 
						u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
 | 
				
			||||||
	u8 gpioie;
 | 
						u8 gpioie;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_enable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	raw_spin_lock(&pl061->lock);
 | 
						raw_spin_lock(&pl061->lock);
 | 
				
			||||||
	gpioie = readb(pl061->base + GPIOIE) | mask;
 | 
						gpioie = readb(pl061->base + GPIOIE) | mask;
 | 
				
			||||||
	writeb(gpioie, pl061->base + GPIOIE);
 | 
						writeb(gpioie, pl061->base + GPIOIE);
 | 
				
			||||||
| 
						 | 
					@ -283,6 +286,24 @@ static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
 | 
				
			||||||
	return irq_set_irq_wake(pl061->parent_irq, state);
 | 
						return irq_set_irq_wake(pl061->parent_irq, state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void pl061_irq_print_chip(struct irq_data *data, struct seq_file *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seq_printf(p, dev_name(gc->parent));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct irq_chip pl061_irq_chip = {
 | 
				
			||||||
 | 
						.irq_ack		= pl061_irq_ack,
 | 
				
			||||||
 | 
						.irq_mask		= pl061_irq_mask,
 | 
				
			||||||
 | 
						.irq_unmask		= pl061_irq_unmask,
 | 
				
			||||||
 | 
						.irq_set_type		= pl061_irq_type,
 | 
				
			||||||
 | 
						.irq_set_wake		= pl061_irq_set_wake,
 | 
				
			||||||
 | 
						.irq_print_chip		= pl061_irq_print_chip,
 | 
				
			||||||
 | 
						.flags			= IRQCHIP_IMMUTABLE,
 | 
				
			||||||
 | 
						GPIOCHIP_IRQ_RESOURCE_HELPERS,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 | 
					static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct device *dev = &adev->dev;
 | 
						struct device *dev = &adev->dev;
 | 
				
			||||||
| 
						 | 
					@ -315,13 +336,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * irq_chip support
 | 
						 * irq_chip support
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	pl061->irq_chip.name = dev_name(dev);
 | 
					 | 
				
			||||||
	pl061->irq_chip.irq_ack	= pl061_irq_ack;
 | 
					 | 
				
			||||||
	pl061->irq_chip.irq_mask = pl061_irq_mask;
 | 
					 | 
				
			||||||
	pl061->irq_chip.irq_unmask = pl061_irq_unmask;
 | 
					 | 
				
			||||||
	pl061->irq_chip.irq_set_type = pl061_irq_type;
 | 
					 | 
				
			||||||
	pl061->irq_chip.irq_set_wake = pl061_irq_set_wake;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	writeb(0, pl061->base + GPIOIE); /* disable irqs */
 | 
						writeb(0, pl061->base + GPIOIE); /* disable irqs */
 | 
				
			||||||
	irq = adev->irq[0];
 | 
						irq = adev->irq[0];
 | 
				
			||||||
	if (!irq)
 | 
						if (!irq)
 | 
				
			||||||
| 
						 | 
					@ -329,7 +343,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 | 
				
			||||||
	pl061->parent_irq = irq;
 | 
						pl061->parent_irq = irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	girq = &pl061->gc.irq;
 | 
						girq = &pl061->gc.irq;
 | 
				
			||||||
	girq->chip = &pl061->irq_chip;
 | 
						gpio_irq_chip_set_chip(girq, &pl061_irq_chip);
 | 
				
			||||||
	girq->parent_handler = pl061_irq_handler;
 | 
						girq->parent_handler = pl061_irq_handler;
 | 
				
			||||||
	girq->num_parents = 1;
 | 
						girq->num_parents = 1;
 | 
				
			||||||
	girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
 | 
						girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,7 +80,6 @@ struct tegra_gpio_soc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tegra_gpio {
 | 
					struct tegra_gpio {
 | 
				
			||||||
	struct gpio_chip gpio;
 | 
						struct gpio_chip gpio;
 | 
				
			||||||
	struct irq_chip intc;
 | 
					 | 
				
			||||||
	unsigned int num_irq;
 | 
						unsigned int num_irq;
 | 
				
			||||||
	unsigned int *irq;
 | 
						unsigned int *irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -372,6 +371,8 @@ static void tegra186_irq_mask(struct irq_data *data)
 | 
				
			||||||
	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
 | 
						value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
 | 
				
			||||||
	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
 | 
						value &= ~TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
 | 
				
			||||||
	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
 | 
						writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_disable_irq(&gpio->gpio, data->hwirq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tegra186_irq_unmask(struct irq_data *data)
 | 
					static void tegra186_irq_unmask(struct irq_data *data)
 | 
				
			||||||
| 
						 | 
					@ -385,6 +386,8 @@ static void tegra186_irq_unmask(struct irq_data *data)
 | 
				
			||||||
	if (WARN_ON(base == NULL))
 | 
						if (WARN_ON(base == NULL))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_enable_irq(&gpio->gpio, data->hwirq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
 | 
						value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
 | 
				
			||||||
	value |= TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
 | 
						value |= TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
 | 
				
			||||||
	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
 | 
						writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
 | 
				
			||||||
| 
						 | 
					@ -456,6 +459,24 @@ static int tegra186_irq_set_wake(struct irq_data *data, unsigned int on)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tegra186_irq_print_chip(struct irq_data *data, struct seq_file *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seq_printf(p, dev_name(gc->parent));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct irq_chip tegra186_gpio_irq_chip = {
 | 
				
			||||||
 | 
						.irq_ack		= tegra186_irq_ack,
 | 
				
			||||||
 | 
						.irq_mask		= tegra186_irq_mask,
 | 
				
			||||||
 | 
						.irq_unmask		= tegra186_irq_unmask,
 | 
				
			||||||
 | 
						.irq_set_type		= tegra186_irq_set_type,
 | 
				
			||||||
 | 
						.irq_set_wake		= tegra186_irq_set_wake,
 | 
				
			||||||
 | 
						.irq_print_chip		= tegra186_irq_print_chip,
 | 
				
			||||||
 | 
						.flags			= IRQCHIP_IMMUTABLE,
 | 
				
			||||||
 | 
						GPIOCHIP_IRQ_RESOURCE_HELPERS,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tegra186_gpio_irq(struct irq_desc *desc)
 | 
					static void tegra186_gpio_irq(struct irq_desc *desc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
 | 
						struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
 | 
				
			||||||
| 
						 | 
					@ -760,15 +781,8 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
 | 
				
			||||||
	gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
 | 
						gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
 | 
				
			||||||
#endif /* CONFIG_OF_GPIO */
 | 
					#endif /* CONFIG_OF_GPIO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gpio->intc.name = dev_name(&pdev->dev);
 | 
					 | 
				
			||||||
	gpio->intc.irq_ack = tegra186_irq_ack;
 | 
					 | 
				
			||||||
	gpio->intc.irq_mask = tegra186_irq_mask;
 | 
					 | 
				
			||||||
	gpio->intc.irq_unmask = tegra186_irq_unmask;
 | 
					 | 
				
			||||||
	gpio->intc.irq_set_type = tegra186_irq_set_type;
 | 
					 | 
				
			||||||
	gpio->intc.irq_set_wake = tegra186_irq_set_wake;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	irq = &gpio->gpio.irq;
 | 
						irq = &gpio->gpio.irq;
 | 
				
			||||||
	irq->chip = &gpio->intc;
 | 
						gpio_irq_chip_set_chip(irq, &tegra186_gpio_irq_chip);
 | 
				
			||||||
	irq->fwnode = of_node_to_fwnode(pdev->dev.of_node);
 | 
						irq->fwnode = of_node_to_fwnode(pdev->dev.of_node);
 | 
				
			||||||
	irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq;
 | 
						irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq;
 | 
				
			||||||
	irq->populate_parent_alloc_arg = tegra186_gpio_populate_parent_fwspec;
 | 
						irq->populate_parent_alloc_arg = tegra186_gpio_populate_parent_fwspec;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1433,19 +1433,21 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)
 | 
				
			||||||
	return irq_create_mapping(domain, offset);
 | 
						return irq_create_mapping(domain, offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int gpiochip_irq_reqres(struct irq_data *d)
 | 
					int gpiochip_irq_reqres(struct irq_data *d)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
						struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return gpiochip_reqres_irq(gc, d->hwirq);
 | 
						return gpiochip_reqres_irq(gc, d->hwirq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(gpiochip_irq_reqres);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gpiochip_irq_relres(struct irq_data *d)
 | 
					void gpiochip_irq_relres(struct irq_data *d)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
						struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gpiochip_relres_irq(gc, d->hwirq);
 | 
						gpiochip_relres_irq(gc, d->hwirq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(gpiochip_irq_relres);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gpiochip_irq_mask(struct irq_data *d)
 | 
					static void gpiochip_irq_mask(struct irq_data *d)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1485,6 +1487,11 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct irq_chip *irqchip = gc->irq.chip;
 | 
						struct irq_chip *irqchip = gc->irq.chip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (irqchip->flags & IRQCHIP_IMMUTABLE)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chip_warn(gc, "not an immutable chip, please consider fixing it!\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!irqchip->irq_request_resources &&
 | 
						if (!irqchip->irq_request_resources &&
 | 
				
			||||||
	    !irqchip->irq_release_resources) {
 | 
						    !irqchip->irq_release_resources) {
 | 
				
			||||||
		irqchip->irq_request_resources = gpiochip_irq_reqres;
 | 
							irqchip->irq_request_resources = gpiochip_irq_reqres;
 | 
				
			||||||
| 
						 | 
					@ -1652,7 +1659,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)
 | 
				
			||||||
		irq_domain_remove(gc->irq.domain);
 | 
							irq_domain_remove(gc->irq.domain);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (irqchip) {
 | 
						if (irqchip && !(irqchip->flags & IRQCHIP_IMMUTABLE)) {
 | 
				
			||||||
		if (irqchip->irq_request_resources == gpiochip_irq_reqres) {
 | 
							if (irqchip->irq_request_resources == gpiochip_irq_reqres) {
 | 
				
			||||||
			irqchip->irq_request_resources = NULL;
 | 
								irqchip->irq_request_resources = NULL;
 | 
				
			||||||
			irqchip->irq_release_resources = NULL;
 | 
								irqchip->irq_release_resources = NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -387,6 +387,8 @@ static void amd_gpio_irq_enable(struct irq_data *d)
 | 
				
			||||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
						struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
				
			||||||
	struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 | 
						struct amd_gpio *gpio_dev = gpiochip_get_data(gc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_enable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	raw_spin_lock_irqsave(&gpio_dev->lock, flags);
 | 
						raw_spin_lock_irqsave(&gpio_dev->lock, flags);
 | 
				
			||||||
	pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
 | 
						pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
 | 
				
			||||||
	pin_reg |= BIT(INTERRUPT_ENABLE_OFF);
 | 
						pin_reg |= BIT(INTERRUPT_ENABLE_OFF);
 | 
				
			||||||
| 
						 | 
					@ -408,6 +410,8 @@ static void amd_gpio_irq_disable(struct irq_data *d)
 | 
				
			||||||
	pin_reg &= ~BIT(INTERRUPT_MASK_OFF);
 | 
						pin_reg &= ~BIT(INTERRUPT_MASK_OFF);
 | 
				
			||||||
	writel(pin_reg, gpio_dev->base + (d->hwirq)*4);
 | 
						writel(pin_reg, gpio_dev->base + (d->hwirq)*4);
 | 
				
			||||||
	raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
 | 
						raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_disable_irq(gc, d->hwirq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void amd_gpio_irq_mask(struct irq_data *d)
 | 
					static void amd_gpio_irq_mask(struct irq_data *d)
 | 
				
			||||||
| 
						 | 
					@ -577,7 +581,7 @@ static void amd_irq_ack(struct irq_data *d)
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct irq_chip amd_gpio_irqchip = {
 | 
					static const struct irq_chip amd_gpio_irqchip = {
 | 
				
			||||||
	.name         = "amd_gpio",
 | 
						.name         = "amd_gpio",
 | 
				
			||||||
	.irq_ack      = amd_irq_ack,
 | 
						.irq_ack      = amd_irq_ack,
 | 
				
			||||||
	.irq_enable   = amd_gpio_irq_enable,
 | 
						.irq_enable   = amd_gpio_irq_enable,
 | 
				
			||||||
| 
						 | 
					@ -593,7 +597,8 @@ static struct irq_chip amd_gpio_irqchip = {
 | 
				
			||||||
	 * the wake event. Otherwise the wake event will never clear and
 | 
						 * the wake event. Otherwise the wake event will never clear and
 | 
				
			||||||
	 * prevent the system from suspending.
 | 
						 * prevent the system from suspending.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	.flags        = IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,
 | 
						.flags        = IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND | IRQCHIP_IMMUTABLE,
 | 
				
			||||||
 | 
						GPIOCHIP_IRQ_RESOURCE_HELPERS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PIN_IRQ_PENDING	(BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF))
 | 
					#define PIN_IRQ_PENDING	(BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF))
 | 
				
			||||||
| 
						 | 
					@ -1026,7 +1031,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
 | 
				
			||||||
	amd_gpio_irq_init(gpio_dev);
 | 
						amd_gpio_irq_init(gpio_dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	girq = &gpio_dev->gc.irq;
 | 
						girq = &gpio_dev->gc.irq;
 | 
				
			||||||
	girq->chip = &amd_gpio_irqchip;
 | 
						gpio_irq_chip_set_chip(girq, &amd_gpio_irqchip);
 | 
				
			||||||
	/* This will let us handle the parent IRQ in the driver */
 | 
						/* This will let us handle the parent IRQ in the driver */
 | 
				
			||||||
	girq->parent_handler = NULL;
 | 
						girq->parent_handler = NULL;
 | 
				
			||||||
	girq->num_parents = 0;
 | 
						girq->num_parents = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,6 @@ struct apple_gpio_pinctrl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pinctrl_desc pinctrl_desc;
 | 
						struct pinctrl_desc pinctrl_desc;
 | 
				
			||||||
	struct gpio_chip gpio_chip;
 | 
						struct gpio_chip gpio_chip;
 | 
				
			||||||
	struct irq_chip irq_chip;
 | 
					 | 
				
			||||||
	u8 irqgrps[];
 | 
						u8 irqgrps[];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,17 +274,21 @@ static unsigned int apple_gpio_irq_type(unsigned int type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void apple_gpio_irq_mask(struct irq_data *data)
 | 
					static void apple_gpio_irq_mask(struct irq_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
 | 
						struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
 | 
				
			||||||
 | 
						struct apple_gpio_pinctrl *pctl = gpiochip_get_data(gc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apple_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_MODE,
 | 
						apple_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_MODE,
 | 
				
			||||||
	                   FIELD_PREP(REG_GPIOx_MODE, REG_GPIOx_IN_IRQ_OFF));
 | 
						                   FIELD_PREP(REG_GPIOx_MODE, REG_GPIOx_IN_IRQ_OFF));
 | 
				
			||||||
 | 
						gpiochip_disable_irq(gc, data->hwirq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void apple_gpio_irq_unmask(struct irq_data *data)
 | 
					static void apple_gpio_irq_unmask(struct irq_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct apple_gpio_pinctrl *pctl = gpiochip_get_data(irq_data_get_irq_chip_data(data));
 | 
						struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
 | 
				
			||||||
 | 
						struct apple_gpio_pinctrl *pctl = gpiochip_get_data(gc);
 | 
				
			||||||
	unsigned int irqtype = apple_gpio_irq_type(irqd_get_trigger_type(data));
 | 
						unsigned int irqtype = apple_gpio_irq_type(irqd_get_trigger_type(data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_enable_irq(gc, data->hwirq);
 | 
				
			||||||
	apple_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_MODE,
 | 
						apple_gpio_set_reg(pctl, data->hwirq, REG_GPIOx_MODE,
 | 
				
			||||||
	                   FIELD_PREP(REG_GPIOx_MODE, irqtype));
 | 
						                   FIELD_PREP(REG_GPIOx_MODE, irqtype));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -343,13 +346,15 @@ static void apple_gpio_irq_handler(struct irq_desc *desc)
 | 
				
			||||||
	chained_irq_exit(chip, desc);
 | 
						chained_irq_exit(chip, desc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct irq_chip apple_gpio_irqchip = {
 | 
					static const struct irq_chip apple_gpio_irqchip = {
 | 
				
			||||||
	.name		= "Apple-GPIO",
 | 
						.name			= "Apple-GPIO",
 | 
				
			||||||
	.irq_startup	= apple_gpio_irq_startup,
 | 
						.irq_startup		= apple_gpio_irq_startup,
 | 
				
			||||||
	.irq_ack	= apple_gpio_irq_ack,
 | 
						.irq_ack		= apple_gpio_irq_ack,
 | 
				
			||||||
	.irq_mask	= apple_gpio_irq_mask,
 | 
						.irq_mask		= apple_gpio_irq_mask,
 | 
				
			||||||
	.irq_unmask	= apple_gpio_irq_unmask,
 | 
						.irq_unmask		= apple_gpio_irq_unmask,
 | 
				
			||||||
	.irq_set_type	= apple_gpio_irq_set_type,
 | 
						.irq_set_type		= apple_gpio_irq_set_type,
 | 
				
			||||||
 | 
						.flags			= IRQCHIP_IMMUTABLE,
 | 
				
			||||||
 | 
						GPIOCHIP_IRQ_RESOURCE_HELPERS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Probe & register */
 | 
					/* Probe & register */
 | 
				
			||||||
| 
						 | 
					@ -360,8 +365,6 @@ static int apple_gpio_register(struct apple_gpio_pinctrl *pctl)
 | 
				
			||||||
	void **irq_data = NULL;
 | 
						void **irq_data = NULL;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pctl->irq_chip = apple_gpio_irqchip;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pctl->gpio_chip.label = dev_name(pctl->dev);
 | 
						pctl->gpio_chip.label = dev_name(pctl->dev);
 | 
				
			||||||
	pctl->gpio_chip.request = gpiochip_generic_request;
 | 
						pctl->gpio_chip.request = gpiochip_generic_request;
 | 
				
			||||||
	pctl->gpio_chip.free = gpiochip_generic_free;
 | 
						pctl->gpio_chip.free = gpiochip_generic_free;
 | 
				
			||||||
| 
						 | 
					@ -377,7 +380,7 @@ static int apple_gpio_register(struct apple_gpio_pinctrl *pctl)
 | 
				
			||||||
	if (girq->num_parents) {
 | 
						if (girq->num_parents) {
 | 
				
			||||||
		int i;
 | 
							int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		girq->chip = &pctl->irq_chip;
 | 
							gpio_irq_chip_set_chip(girq, &apple_gpio_irqchip);
 | 
				
			||||||
		girq->parent_handler = apple_gpio_irq_handler;
 | 
							girq->parent_handler = apple_gpio_irq_handler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		girq->parents = kmalloc_array(girq->num_parents,
 | 
							girq->parents = kmalloc_array(girq->num_parents,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,6 @@
 | 
				
			||||||
 * @chip:           gpiochip handle.
 | 
					 * @chip:           gpiochip handle.
 | 
				
			||||||
 * @desc:           pin controller descriptor
 | 
					 * @desc:           pin controller descriptor
 | 
				
			||||||
 * @restart_nb:     restart notifier block.
 | 
					 * @restart_nb:     restart notifier block.
 | 
				
			||||||
 * @irq_chip:       irq chip information
 | 
					 | 
				
			||||||
 * @irq:            parent irq for the TLMM irq_chip.
 | 
					 * @irq:            parent irq for the TLMM irq_chip.
 | 
				
			||||||
 * @intr_target_use_scm: route irq to application cpu using scm calls
 | 
					 * @intr_target_use_scm: route irq to application cpu using scm calls
 | 
				
			||||||
 * @lock:           Spinlock to protect register resources as well
 | 
					 * @lock:           Spinlock to protect register resources as well
 | 
				
			||||||
| 
						 | 
					@ -63,7 +62,6 @@ struct msm_pinctrl {
 | 
				
			||||||
	struct pinctrl_desc desc;
 | 
						struct pinctrl_desc desc;
 | 
				
			||||||
	struct notifier_block restart_nb;
 | 
						struct notifier_block restart_nb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct irq_chip irq_chip;
 | 
					 | 
				
			||||||
	int irq;
 | 
						int irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool intr_target_use_scm;
 | 
						bool intr_target_use_scm;
 | 
				
			||||||
| 
						 | 
					@ -868,6 +866,8 @@ static void msm_gpio_irq_enable(struct irq_data *d)
 | 
				
			||||||
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
						struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 | 
				
			||||||
	struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
 | 
						struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_enable_irq(gc, d->hwirq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (d->parent_data)
 | 
						if (d->parent_data)
 | 
				
			||||||
		irq_chip_enable_parent(d);
 | 
							irq_chip_enable_parent(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -885,6 +885,8 @@ static void msm_gpio_irq_disable(struct irq_data *d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!test_bit(d->hwirq, pctrl->skip_wake_irqs))
 | 
						if (!test_bit(d->hwirq, pctrl->skip_wake_irqs))
 | 
				
			||||||
		msm_gpio_irq_mask(d);
 | 
							msm_gpio_irq_mask(d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gpiochip_disable_irq(gc, d->hwirq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -958,6 +960,14 @@ static void msm_gpio_irq_ack(struct irq_data *d)
 | 
				
			||||||
	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 | 
						raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void msm_gpio_irq_eoi(struct irq_data *d)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						d = d->parent_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (d)
 | 
				
			||||||
 | 
							d->chip->irq_eoi(d);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool msm_gpio_needs_dual_edge_parent_workaround(struct irq_data *d,
 | 
					static bool msm_gpio_needs_dual_edge_parent_workaround(struct irq_data *d,
 | 
				
			||||||
						       unsigned int type)
 | 
											       unsigned int type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1255,6 +1265,26 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
 | 
				
			||||||
	return device_property_count_u16(pctrl->dev, "gpios") > 0;
 | 
						return device_property_count_u16(pctrl->dev, "gpios") > 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct irq_chip msm_gpio_irq_chip = {
 | 
				
			||||||
 | 
						.name			= "msmgpio",
 | 
				
			||||||
 | 
						.irq_enable		= msm_gpio_irq_enable,
 | 
				
			||||||
 | 
						.irq_disable		= msm_gpio_irq_disable,
 | 
				
			||||||
 | 
						.irq_mask		= msm_gpio_irq_mask,
 | 
				
			||||||
 | 
						.irq_unmask		= msm_gpio_irq_unmask,
 | 
				
			||||||
 | 
						.irq_ack		= msm_gpio_irq_ack,
 | 
				
			||||||
 | 
						.irq_eoi		= msm_gpio_irq_eoi,
 | 
				
			||||||
 | 
						.irq_set_type		= msm_gpio_irq_set_type,
 | 
				
			||||||
 | 
						.irq_set_wake		= msm_gpio_irq_set_wake,
 | 
				
			||||||
 | 
						.irq_request_resources	= msm_gpio_irq_reqres,
 | 
				
			||||||
 | 
						.irq_release_resources	= msm_gpio_irq_relres,
 | 
				
			||||||
 | 
						.irq_set_affinity	= msm_gpio_irq_set_affinity,
 | 
				
			||||||
 | 
						.irq_set_vcpu_affinity	= msm_gpio_irq_set_vcpu_affinity,
 | 
				
			||||||
 | 
						.flags			= (IRQCHIP_MASK_ON_SUSPEND |
 | 
				
			||||||
 | 
									   IRQCHIP_SET_TYPE_MASKED |
 | 
				
			||||||
 | 
									   IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND |
 | 
				
			||||||
 | 
									   IRQCHIP_IMMUTABLE),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int msm_gpio_init(struct msm_pinctrl *pctrl)
 | 
					static int msm_gpio_init(struct msm_pinctrl *pctrl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gpio_chip *chip;
 | 
						struct gpio_chip *chip;
 | 
				
			||||||
| 
						 | 
					@ -1276,22 +1306,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 | 
				
			||||||
	if (msm_gpio_needs_valid_mask(pctrl))
 | 
						if (msm_gpio_needs_valid_mask(pctrl))
 | 
				
			||||||
		chip->init_valid_mask = msm_gpio_init_valid_mask;
 | 
							chip->init_valid_mask = msm_gpio_init_valid_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pctrl->irq_chip.name = "msmgpio";
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_enable = msm_gpio_irq_enable;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_disable = msm_gpio_irq_disable;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_mask = msm_gpio_irq_mask;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_ack = msm_gpio_irq_ack;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_set_affinity = msm_gpio_irq_set_affinity;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.irq_set_vcpu_affinity = msm_gpio_irq_set_vcpu_affinity;
 | 
					 | 
				
			||||||
	pctrl->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND |
 | 
					 | 
				
			||||||
				IRQCHIP_SET_TYPE_MASKED |
 | 
					 | 
				
			||||||
				IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	np = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0);
 | 
						np = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0);
 | 
				
			||||||
	if (np) {
 | 
						if (np) {
 | 
				
			||||||
		chip->irq.parent_domain = irq_find_matching_host(np,
 | 
							chip->irq.parent_domain = irq_find_matching_host(np,
 | 
				
			||||||
| 
						 | 
					@ -1300,7 +1314,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 | 
				
			||||||
		if (!chip->irq.parent_domain)
 | 
							if (!chip->irq.parent_domain)
 | 
				
			||||||
			return -EPROBE_DEFER;
 | 
								return -EPROBE_DEFER;
 | 
				
			||||||
		chip->irq.child_to_parent_hwirq = msm_gpio_wakeirq;
 | 
							chip->irq.child_to_parent_hwirq = msm_gpio_wakeirq;
 | 
				
			||||||
		pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent;
 | 
					 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Let's skip handling the GPIOs, if the parent irqchip
 | 
							 * Let's skip handling the GPIOs, if the parent irqchip
 | 
				
			||||||
		 * is handling the direct connect IRQ of the GPIO.
 | 
							 * is handling the direct connect IRQ of the GPIO.
 | 
				
			||||||
| 
						 | 
					@ -1313,7 +1326,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	girq = &chip->irq;
 | 
						girq = &chip->irq;
 | 
				
			||||||
	girq->chip = &pctrl->irq_chip;
 | 
						gpio_irq_chip_set_chip(girq, &msm_gpio_irq_chip);
 | 
				
			||||||
	girq->parent_handler = msm_gpio_irq_handler;
 | 
						girq->parent_handler = msm_gpio_irq_handler;
 | 
				
			||||||
	girq->fwnode = pctrl->dev->fwnode;
 | 
						girq->fwnode = pctrl->dev->fwnode;
 | 
				
			||||||
	girq->num_parents = 1;
 | 
						girq->num_parents = 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -588,6 +588,22 @@ void gpiochip_relres_irq(struct gpio_chip *gc, unsigned int offset);
 | 
				
			||||||
void gpiochip_disable_irq(struct gpio_chip *gc, unsigned int offset);
 | 
					void gpiochip_disable_irq(struct gpio_chip *gc, unsigned int offset);
 | 
				
			||||||
void gpiochip_enable_irq(struct gpio_chip *gc, unsigned int offset);
 | 
					void gpiochip_enable_irq(struct gpio_chip *gc, unsigned int offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* irq_data versions of the above */
 | 
				
			||||||
 | 
					int gpiochip_irq_reqres(struct irq_data *data);
 | 
				
			||||||
 | 
					void gpiochip_irq_relres(struct irq_data *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Paste this in your irq_chip structure  */
 | 
				
			||||||
 | 
					#define	GPIOCHIP_IRQ_RESOURCE_HELPERS					\
 | 
				
			||||||
 | 
							.irq_request_resources  = gpiochip_irq_reqres,		\
 | 
				
			||||||
 | 
							.irq_release_resources  = gpiochip_irq_relres
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void gpio_irq_chip_set_chip(struct gpio_irq_chip *girq,
 | 
				
			||||||
 | 
										  const struct irq_chip *chip)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Yes, dropping const is ugly, but it isn't like we have a choice */
 | 
				
			||||||
 | 
						girq->chip = (struct irq_chip *)chip;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Line status inquiry for drivers */
 | 
					/* Line status inquiry for drivers */
 | 
				
			||||||
bool gpiochip_line_is_open_drain(struct gpio_chip *gc, unsigned int offset);
 | 
					bool gpiochip_line_is_open_drain(struct gpio_chip *gc, unsigned int offset);
 | 
				
			||||||
bool gpiochip_line_is_open_source(struct gpio_chip *gc, unsigned int offset);
 | 
					bool gpiochip_line_is_open_source(struct gpio_chip *gc, unsigned int offset);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -569,6 +569,7 @@ struct irq_chip {
 | 
				
			||||||
 * IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND:  Invokes __enable_irq()/__disable_irq() for wake irqs
 | 
					 * IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND:  Invokes __enable_irq()/__disable_irq() for wake irqs
 | 
				
			||||||
 *                                    in the suspend path if they are in disabled state
 | 
					 *                                    in the suspend path if they are in disabled state
 | 
				
			||||||
 * IRQCHIP_AFFINITY_PRE_STARTUP:      Default affinity update before startup
 | 
					 * IRQCHIP_AFFINITY_PRE_STARTUP:      Default affinity update before startup
 | 
				
			||||||
 | 
					 * IRQCHIP_IMMUTABLE:		      Don't ever change anything in this chip
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	IRQCHIP_SET_TYPE_MASKED			= (1 <<  0),
 | 
						IRQCHIP_SET_TYPE_MASKED			= (1 <<  0),
 | 
				
			||||||
| 
						 | 
					@ -582,6 +583,7 @@ enum {
 | 
				
			||||||
	IRQCHIP_SUPPORTS_NMI			= (1 <<  8),
 | 
						IRQCHIP_SUPPORTS_NMI			= (1 <<  8),
 | 
				
			||||||
	IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND	= (1 <<  9),
 | 
						IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND	= (1 <<  9),
 | 
				
			||||||
	IRQCHIP_AFFINITY_PRE_STARTUP		= (1 << 10),
 | 
						IRQCHIP_AFFINITY_PRE_STARTUP		= (1 << 10),
 | 
				
			||||||
 | 
						IRQCHIP_IMMUTABLE			= (1 << 11),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/irqdesc.h>
 | 
					#include <linux/irqdesc.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,6 +58,7 @@ static const struct irq_bit_descr irqchip_flags[] = {
 | 
				
			||||||
	BIT_MASK_DESCR(IRQCHIP_SUPPORTS_LEVEL_MSI),
 | 
						BIT_MASK_DESCR(IRQCHIP_SUPPORTS_LEVEL_MSI),
 | 
				
			||||||
	BIT_MASK_DESCR(IRQCHIP_SUPPORTS_NMI),
 | 
						BIT_MASK_DESCR(IRQCHIP_SUPPORTS_NMI),
 | 
				
			||||||
	BIT_MASK_DESCR(IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND),
 | 
						BIT_MASK_DESCR(IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND),
 | 
				
			||||||
 | 
						BIT_MASK_DESCR(IRQCHIP_IMMUTABLE),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue