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:
Родитель
afefc32662
Коммит
5644b66a9c
|
@ -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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче