Loading Documentation/driver-api/gpio/driver.rst +44 −23 Original line number Diff line number Diff line Loading @@ -416,7 +416,8 @@ The preferred way to set up the helpers is to fill in the 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 same time as setting up the rest of the GPIO functionality. The following is a typical example of a cascaded interrupt handler using gpio_irq_chip: is a typical example of a chained cascaded interrupt handler using the gpio_irq_chip: .. code-block:: c Loading Loading @@ -452,7 +453,46 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip: return devm_gpiochip_add_data(dev, &g->gc, g); The helper support using hierarchical interrupt controllers as well. The helper supports using threaded interrupts as well. Then you just request the interrupt separately and go with it: .. code-block:: c /* Typical state container with dynamic irqchip */ struct my_gpio { struct gpio_chip gc; struct irq_chip irq; }; int irq; /* from platform etc */ struct my_gpio *g; 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, irq_thread_fn, IRQF_ONESHOT, "my-chip", g); if (ret < 0) return ret; /* Get a pointer to the gpio_irq_chip */ girq = &g->gc.irq; girq->chip = &g->irq; /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; girq->parents = NULL; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; return devm_gpiochip_add_data(dev, &g->gc, g); The helper supports using hierarchical interrupt controllers as well. In this case the typical set-up will look like this: .. code-block:: c Loading Loading @@ -493,32 +533,13 @@ the parent hardware irq from a child (i.e. this gpio chip) hardware irq. As always it is good to look at examples in the kernel tree for advice on how to find the required pieces. The old way of adding irqchips to gpiochips after registration is also still available but we try to move away from this: - DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks need to embed the gpio_chip in its state container and obtain a pointer to the container using container_of(). (See Documentation/driver-api/driver-model/design-patterns.rst) - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip, as discussed above regarding different types of cascaded irqchips. The cascaded irq has to be handled by a threaded interrupt handler. Apart from that it works exactly like the chained irqchip. - gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a gpio_chip from a parent IRQ. As the parent IRQ has usually been explicitly requested by the driver, this does very little more than mark all the child IRQs as having the other IRQ as parent. If there is a need to exclude certain GPIO lines from the IRQ domain handled by these helpers, we can set .irq.need_valid_mask of the gpiochip before devm_gpiochip_add_data() or gpiochip_add_data() is called. This allocates an .irq.valid_mask with as many bits set as there are GPIO lines in the chip, each bit representing line 0..n-1. Drivers can exclude GPIO lines by clearing bits from this mask. The mask must be filled in before gpiochip_irqchip_add() or gpiochip_irqchip_add_nested() is called. from this mask. The mask can be filled in the init_valid_mask() callback that is part of the struct gpio_irq_chip. To use the helpers please keep the following in mind: Loading drivers/gpio/TODO +0 −49 Original line number Diff line number Diff line Loading @@ -129,58 +129,9 @@ GPIOLIB irqchip The GPIOLIB irqchip is a helper irqchip for "simple cases" that should try to cover any generic kind of irqchip cascaded from a GPIO. - Convert all the GPIOLIB_IRQCHIP users to pass an irqchip template, parent and flags before calling [devm_]gpiochip_add[_data](). Currently we set up the irqchip after setting up the gpiochip using gpiochip_irqchip_add() and gpiochip_set_[chained|nested]_irqchip(). This is too complex, so convert all users over to just set up the irqchip before registering the gpio_chip, typical example: /* Typical state container with dynamic irqchip */ struct my_gpio { struct gpio_chip gc; struct irq_chip irq; }; int irq; /* from platform etc */ struct my_gpio *g; 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 */ girq = &g->gc.irq; girq->chip = &g->irq; girq->parent_handler = ftgpio_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), GFP_KERNEL); if (!girq->parents) return -ENOMEM; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; girq->parents[0] = irq; When this is done, we will delete the old APIs for instatiating GPIOLIB_IRQCHIP and simplify the code. - Look over and identify any remaining easily converted drivers and dry-code conversions to gpiolib irqchip for maintainers to test - Drop gpiochip_set_chained_irqchip() when all the chained irqchips have been converted to the above infrastructure. - Add more infrastructure to make it possible to also pass a threaded irqchip in struct gpio_irq_chip. - Drop gpiochip_irqchip_add_nested() when all the chained irqchips have been converted to the above infrastructure. Increase integration with pin control Loading drivers/gpio/gpio-104-idi-48.c +2 −4 Original line number Diff line number Diff line Loading @@ -132,8 +132,7 @@ static void idi_48_irq_mask(struct irq_data *data) outb(idi48gpio->cos_enb, idi48gpio->base + 7); raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); } return; Loading Loading @@ -166,8 +165,7 @@ static void idi_48_irq_unmask(struct irq_data *data) outb(idi48gpio->cos_enb, idi48gpio->base + 7); raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); } return; Loading drivers/gpio/gpio-stmpe.c +1 −9 Original line number Diff line number Diff line Loading @@ -474,15 +474,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip.parent = &pdev->dev; stmpe_gpio->chip.of_node = np; stmpe_gpio->chip.base = -1; /* * REVISIT: this makes sure the valid mask gets allocated and * filled in when adding the gpio_chip, but the rest of the * gpio_irqchip is still filled in using the old method * in gpiochip_irqchip_add_nested() so clean this up once we * get the gpio_irqchip to initialize while adding the * gpio_chip also for threaded irqchips. */ stmpe_gpio->chip.irq.init_valid_mask = stmpe_init_irq_valid_mask; if (IS_ENABLED(CONFIG_DEBUG_FS)) stmpe_gpio->chip.dbg_show = stmpe_dbg_show; Loading Loading @@ -520,6 +511,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_simple_irq; girq->threaded = true; girq->init_valid_mask = stmpe_init_irq_valid_mask; } ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio); Loading drivers/gpio/gpiolib-cdev.c +8 −16 Original line number Diff line number Diff line Loading @@ -1479,22 +1479,11 @@ static __poll_t lineevent_poll(struct file *file, return events; } static ssize_t lineevent_get_size(void) { #if defined(CONFIG_X86_64) && !defined(CONFIG_UML) /* i386 has no padding after 'id' */ if (in_ia32_syscall()) { struct compat_gpioeevent_data { compat_u64 timestamp; u32 id; }; return sizeof(struct compat_gpioeevent_data); } #endif return sizeof(struct gpioevent_data); } static ssize_t lineevent_read(struct file *file, char __user *buf, size_t count, Loading @@ -1515,7 +1504,10 @@ static ssize_t lineevent_read(struct file *file, * actual sizeof() and pass this as an argument to copy_to_user() to * drop unneeded bytes from the output. */ ge_size = lineevent_get_size(); if (compat_need_64bit_alignment_fixup()) ge_size = sizeof(struct compat_gpioeevent_data); else ge_size = sizeof(struct gpioevent_data); if (count < ge_size) return -EINVAL; Loading Loading
Documentation/driver-api/gpio/driver.rst +44 −23 Original line number Diff line number Diff line Loading @@ -416,7 +416,8 @@ The preferred way to set up the helpers is to fill in the 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 same time as setting up the rest of the GPIO functionality. The following is a typical example of a cascaded interrupt handler using gpio_irq_chip: is a typical example of a chained cascaded interrupt handler using the gpio_irq_chip: .. code-block:: c Loading Loading @@ -452,7 +453,46 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip: return devm_gpiochip_add_data(dev, &g->gc, g); The helper support using hierarchical interrupt controllers as well. The helper supports using threaded interrupts as well. Then you just request the interrupt separately and go with it: .. code-block:: c /* Typical state container with dynamic irqchip */ struct my_gpio { struct gpio_chip gc; struct irq_chip irq; }; int irq; /* from platform etc */ struct my_gpio *g; 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, irq_thread_fn, IRQF_ONESHOT, "my-chip", g); if (ret < 0) return ret; /* Get a pointer to the gpio_irq_chip */ girq = &g->gc.irq; girq->chip = &g->irq; /* This will let us handle the parent IRQ in the driver */ girq->parent_handler = NULL; girq->num_parents = 0; girq->parents = NULL; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; return devm_gpiochip_add_data(dev, &g->gc, g); The helper supports using hierarchical interrupt controllers as well. In this case the typical set-up will look like this: .. code-block:: c Loading Loading @@ -493,32 +533,13 @@ the parent hardware irq from a child (i.e. this gpio chip) hardware irq. As always it is good to look at examples in the kernel tree for advice on how to find the required pieces. The old way of adding irqchips to gpiochips after registration is also still available but we try to move away from this: - DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks need to embed the gpio_chip in its state container and obtain a pointer to the container using container_of(). (See Documentation/driver-api/driver-model/design-patterns.rst) - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip, as discussed above regarding different types of cascaded irqchips. The cascaded irq has to be handled by a threaded interrupt handler. Apart from that it works exactly like the chained irqchip. - gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a gpio_chip from a parent IRQ. As the parent IRQ has usually been explicitly requested by the driver, this does very little more than mark all the child IRQs as having the other IRQ as parent. If there is a need to exclude certain GPIO lines from the IRQ domain handled by these helpers, we can set .irq.need_valid_mask of the gpiochip before devm_gpiochip_add_data() or gpiochip_add_data() is called. This allocates an .irq.valid_mask with as many bits set as there are GPIO lines in the chip, each bit representing line 0..n-1. Drivers can exclude GPIO lines by clearing bits from this mask. The mask must be filled in before gpiochip_irqchip_add() or gpiochip_irqchip_add_nested() is called. from this mask. The mask can be filled in the init_valid_mask() callback that is part of the struct gpio_irq_chip. To use the helpers please keep the following in mind: Loading
drivers/gpio/TODO +0 −49 Original line number Diff line number Diff line Loading @@ -129,58 +129,9 @@ GPIOLIB irqchip The GPIOLIB irqchip is a helper irqchip for "simple cases" that should try to cover any generic kind of irqchip cascaded from a GPIO. - Convert all the GPIOLIB_IRQCHIP users to pass an irqchip template, parent and flags before calling [devm_]gpiochip_add[_data](). Currently we set up the irqchip after setting up the gpiochip using gpiochip_irqchip_add() and gpiochip_set_[chained|nested]_irqchip(). This is too complex, so convert all users over to just set up the irqchip before registering the gpio_chip, typical example: /* Typical state container with dynamic irqchip */ struct my_gpio { struct gpio_chip gc; struct irq_chip irq; }; int irq; /* from platform etc */ struct my_gpio *g; 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 */ girq = &g->gc.irq; girq->chip = &g->irq; girq->parent_handler = ftgpio_gpio_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), GFP_KERNEL); if (!girq->parents) return -ENOMEM; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; girq->parents[0] = irq; When this is done, we will delete the old APIs for instatiating GPIOLIB_IRQCHIP and simplify the code. - Look over and identify any remaining easily converted drivers and dry-code conversions to gpiolib irqchip for maintainers to test - Drop gpiochip_set_chained_irqchip() when all the chained irqchips have been converted to the above infrastructure. - Add more infrastructure to make it possible to also pass a threaded irqchip in struct gpio_irq_chip. - Drop gpiochip_irqchip_add_nested() when all the chained irqchips have been converted to the above infrastructure. Increase integration with pin control Loading
drivers/gpio/gpio-104-idi-48.c +2 −4 Original line number Diff line number Diff line Loading @@ -132,8 +132,7 @@ static void idi_48_irq_mask(struct irq_data *data) outb(idi48gpio->cos_enb, idi48gpio->base + 7); raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); } return; Loading Loading @@ -166,8 +165,7 @@ static void idi_48_irq_unmask(struct irq_data *data) outb(idi48gpio->cos_enb, idi48gpio->base + 7); raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); } return; Loading
drivers/gpio/gpio-stmpe.c +1 −9 Original line number Diff line number Diff line Loading @@ -474,15 +474,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip.parent = &pdev->dev; stmpe_gpio->chip.of_node = np; stmpe_gpio->chip.base = -1; /* * REVISIT: this makes sure the valid mask gets allocated and * filled in when adding the gpio_chip, but the rest of the * gpio_irqchip is still filled in using the old method * in gpiochip_irqchip_add_nested() so clean this up once we * get the gpio_irqchip to initialize while adding the * gpio_chip also for threaded irqchips. */ stmpe_gpio->chip.irq.init_valid_mask = stmpe_init_irq_valid_mask; if (IS_ENABLED(CONFIG_DEBUG_FS)) stmpe_gpio->chip.dbg_show = stmpe_dbg_show; Loading Loading @@ -520,6 +511,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_simple_irq; girq->threaded = true; girq->init_valid_mask = stmpe_init_irq_valid_mask; } ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio); Loading
drivers/gpio/gpiolib-cdev.c +8 −16 Original line number Diff line number Diff line Loading @@ -1479,22 +1479,11 @@ static __poll_t lineevent_poll(struct file *file, return events; } static ssize_t lineevent_get_size(void) { #if defined(CONFIG_X86_64) && !defined(CONFIG_UML) /* i386 has no padding after 'id' */ if (in_ia32_syscall()) { struct compat_gpioeevent_data { compat_u64 timestamp; u32 id; }; return sizeof(struct compat_gpioeevent_data); } #endif return sizeof(struct gpioevent_data); } static ssize_t lineevent_read(struct file *file, char __user *buf, size_t count, Loading @@ -1515,7 +1504,10 @@ static ssize_t lineevent_read(struct file *file, * actual sizeof() and pass this as an argument to copy_to_user() to * drop unneeded bytes from the output. */ ge_size = lineevent_get_size(); if (compat_need_64bit_alignment_fixup()) ge_size = sizeof(struct compat_gpioeevent_data); else ge_size = sizeof(struct gpioevent_data); if (count < ge_size) return -EINVAL; Loading