Loading Documentation/gpio/driver.txt +6 −0 Original line number Diff line number Diff line Loading @@ -262,6 +262,12 @@ symbol: to the container using container_of(). (See Documentation/driver-model/design-patterns.txt) If there is a need to exclude certain GPIOs from the IRQ domain, one can set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is called. This allocates .irq_valid_mask with as many bits set as there are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this mask. The mask must be filled in before gpiochip_irqchip_add() is called. * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler data. (Notice handler data, since the irqchip data is likely used by the Loading drivers/gpio/gpiolib.c +63 −3 Original line number Diff line number Diff line Loading @@ -71,6 +71,8 @@ LIST_HEAD(gpio_devices); static void gpiochip_free_hogs(struct gpio_chip *chip); static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip); static bool gpiolib_initialized; Loading Loading @@ -1167,6 +1169,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) if (status) goto err_remove_from_list; status = gpiochip_irqchip_init_valid_mask(chip); if (status) goto err_remove_from_list; status = of_gpiochip_add(chip); if (status) goto err_remove_chip; Loading @@ -1192,6 +1198,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) acpi_gpiochip_remove(chip); gpiochip_free_hogs(chip); of_gpiochip_remove(chip); gpiochip_irqchip_free_valid_mask(chip); err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); list_del(&gdev->list); Loading Loading @@ -1401,6 +1408,40 @@ static struct gpio_chip *find_chip_by_name(const char *name) * The following is irqchip helper code for gpiochips. */ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) { int i; if (!gpiochip->irq_need_valid_mask) return 0; gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio), sizeof(long), GFP_KERNEL); if (!gpiochip->irq_valid_mask) return -ENOMEM; /* Assume by default all GPIOs are valid */ for (i = 0; i < gpiochip->ngpio; i++) set_bit(i, gpiochip->irq_valid_mask); return 0; } static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) { kfree(gpiochip->irq_valid_mask); gpiochip->irq_valid_mask = NULL; } static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, unsigned int offset) { /* No mask means all valid */ if (likely(!gpiochip->irq_valid_mask)) return true; return test_bit(offset, gpiochip->irq_valid_mask); } /** * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip * @gpiochip: the gpiochip to set the irqchip chain to Loading Loading @@ -1442,10 +1483,13 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, } /* Set the parent IRQ for all affected IRQs */ for (offset = 0; offset < gpiochip->ngpio; offset++) for (offset = 0; offset < gpiochip->ngpio; offset++) { if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) continue; irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset), parent_irq); } } EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); /** Loading Loading @@ -1551,9 +1595,12 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) /* Remove all IRQ mappings and delete the domain */ if (gpiochip->irqdomain) { for (offset = 0; offset < gpiochip->ngpio; offset++) for (offset = 0; offset < gpiochip->ngpio; offset++) { if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) continue; irq_dispose_mapping( irq_find_mapping(gpiochip->irqdomain, offset)); } irq_domain_remove(gpiochip->irqdomain); } Loading @@ -1562,6 +1609,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) gpiochip->irqchip->irq_release_resources = NULL; gpiochip->irqchip = NULL; } gpiochip_irqchip_free_valid_mask(gpiochip); } /** Loading Loading @@ -1597,6 +1646,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, struct lock_class_key *lock_key) { struct device_node *of_node; bool irq_base_set = false; unsigned int offset; unsigned irq_base = 0; Loading Loading @@ -1646,13 +1696,17 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, * necessary to allocate descriptors for all IRQs. */ for (offset = 0; offset < gpiochip->ngpio; offset++) { if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) continue; irq_base = irq_create_mapping(gpiochip->irqdomain, offset); if (offset == 0) if (!irq_base_set) { /* * Store the base into the gpiochip to be used when * unmapping the irqs. */ gpiochip->irq_base = irq_base; irq_base_set = true; } } acpi_gpiochip_request_interrupts(gpiochip); Loading @@ -1664,6 +1718,12 @@ EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add); #else /* CONFIG_GPIOLIB_IRQCHIP */ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) { return 0; } static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) { } #endif /* CONFIG_GPIOLIB_IRQCHIP */ Loading include/linux/gpio/driver.h +6 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,10 @@ enum single_ended_mode { * initialization, provided by GPIO driver * @irq_parent: GPIO IRQ chip parent/bank linux irq number, * provided by GPIO driver * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all * bits set to one * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to * be included in IRQ domain of the chip * @lock_key: per GPIO IRQ chip lockdep class * * A gpio_chip can help platforms abstract various sources of GPIOs so Loading Loading @@ -190,6 +194,8 @@ struct gpio_chip { irq_flow_handler_t irq_handler; unsigned int irq_default_type; int irq_parent; bool irq_need_valid_mask; unsigned long *irq_valid_mask; struct lock_class_key *lock_key; #endif Loading Loading
Documentation/gpio/driver.txt +6 −0 Original line number Diff line number Diff line Loading @@ -262,6 +262,12 @@ symbol: to the container using container_of(). (See Documentation/driver-model/design-patterns.txt) If there is a need to exclude certain GPIOs from the IRQ domain, one can set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is called. This allocates .irq_valid_mask with as many bits set as there are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this mask. The mask must be filled in before gpiochip_irqchip_add() is called. * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler data. (Notice handler data, since the irqchip data is likely used by the Loading
drivers/gpio/gpiolib.c +63 −3 Original line number Diff line number Diff line Loading @@ -71,6 +71,8 @@ LIST_HEAD(gpio_devices); static void gpiochip_free_hogs(struct gpio_chip *chip); static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip); static bool gpiolib_initialized; Loading Loading @@ -1167,6 +1169,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) if (status) goto err_remove_from_list; status = gpiochip_irqchip_init_valid_mask(chip); if (status) goto err_remove_from_list; status = of_gpiochip_add(chip); if (status) goto err_remove_chip; Loading @@ -1192,6 +1198,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) acpi_gpiochip_remove(chip); gpiochip_free_hogs(chip); of_gpiochip_remove(chip); gpiochip_irqchip_free_valid_mask(chip); err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); list_del(&gdev->list); Loading Loading @@ -1401,6 +1408,40 @@ static struct gpio_chip *find_chip_by_name(const char *name) * The following is irqchip helper code for gpiochips. */ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) { int i; if (!gpiochip->irq_need_valid_mask) return 0; gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio), sizeof(long), GFP_KERNEL); if (!gpiochip->irq_valid_mask) return -ENOMEM; /* Assume by default all GPIOs are valid */ for (i = 0; i < gpiochip->ngpio; i++) set_bit(i, gpiochip->irq_valid_mask); return 0; } static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) { kfree(gpiochip->irq_valid_mask); gpiochip->irq_valid_mask = NULL; } static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, unsigned int offset) { /* No mask means all valid */ if (likely(!gpiochip->irq_valid_mask)) return true; return test_bit(offset, gpiochip->irq_valid_mask); } /** * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip * @gpiochip: the gpiochip to set the irqchip chain to Loading Loading @@ -1442,10 +1483,13 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, } /* Set the parent IRQ for all affected IRQs */ for (offset = 0; offset < gpiochip->ngpio; offset++) for (offset = 0; offset < gpiochip->ngpio; offset++) { if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) continue; irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset), parent_irq); } } EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); /** Loading Loading @@ -1551,9 +1595,12 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) /* Remove all IRQ mappings and delete the domain */ if (gpiochip->irqdomain) { for (offset = 0; offset < gpiochip->ngpio; offset++) for (offset = 0; offset < gpiochip->ngpio; offset++) { if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) continue; irq_dispose_mapping( irq_find_mapping(gpiochip->irqdomain, offset)); } irq_domain_remove(gpiochip->irqdomain); } Loading @@ -1562,6 +1609,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) gpiochip->irqchip->irq_release_resources = NULL; gpiochip->irqchip = NULL; } gpiochip_irqchip_free_valid_mask(gpiochip); } /** Loading Loading @@ -1597,6 +1646,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, struct lock_class_key *lock_key) { struct device_node *of_node; bool irq_base_set = false; unsigned int offset; unsigned irq_base = 0; Loading Loading @@ -1646,13 +1696,17 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, * necessary to allocate descriptors for all IRQs. */ for (offset = 0; offset < gpiochip->ngpio; offset++) { if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) continue; irq_base = irq_create_mapping(gpiochip->irqdomain, offset); if (offset == 0) if (!irq_base_set) { /* * Store the base into the gpiochip to be used when * unmapping the irqs. */ gpiochip->irq_base = irq_base; irq_base_set = true; } } acpi_gpiochip_request_interrupts(gpiochip); Loading @@ -1664,6 +1718,12 @@ EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add); #else /* CONFIG_GPIOLIB_IRQCHIP */ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) { return 0; } static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) { } #endif /* CONFIG_GPIOLIB_IRQCHIP */ Loading
include/linux/gpio/driver.h +6 −0 Original line number Diff line number Diff line Loading @@ -112,6 +112,10 @@ enum single_ended_mode { * initialization, provided by GPIO driver * @irq_parent: GPIO IRQ chip parent/bank linux irq number, * provided by GPIO driver * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all * bits set to one * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to * be included in IRQ domain of the chip * @lock_key: per GPIO IRQ chip lockdep class * * A gpio_chip can help platforms abstract various sources of GPIOs so Loading Loading @@ -190,6 +194,8 @@ struct gpio_chip { irq_flow_handler_t irq_handler; unsigned int irq_default_type; int irq_parent; bool irq_need_valid_mask; unsigned long *irq_valid_mask; struct lock_class_key *lock_key; #endif Loading