Documentation: Update the recommended pattern for GPIO irqchips

Update the documentation to get rid of the per-gpio_irq_chip
irq_chip structure, and give examples of the new pattern.

Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Bartosz Golaszewski <brgl@bgdev.pl>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220419141846.598305-11-maz@kernel.org
This commit is contained in:
Marc Zyngier 2022-04-19 15:18:46 +01:00
Родитель afefc32662
Коммит 5644b66a9c
1 изменённых файлов: 142 добавлений и 33 удалений

Просмотреть файл

@ -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