diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 7 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 66 |
2 files changed, 69 insertions, 4 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 1b342a3842c8..e38989a4fa0c 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -458,6 +458,11 @@ static int mxc_gpio_probe(struct platform_device *pdev) if (err) goto out_bgio; + if (of_property_read_bool(np, "gpio-ranges")) { + port->gc.request = gpiochip_generic_request; + port->gc.free = gpiochip_generic_free; + } + port->gc.to_irq = mxc_gpio_to_irq; port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 : pdev->id * 32; @@ -510,7 +515,7 @@ static int __init gpio_mxc_init(void) { return platform_driver_register(&mxc_gpio_driver); } -postcore_initcall(gpio_mxc_init); +subsys_initcall(gpio_mxc_init); MODULE_AUTHOR("Freescale Semiconductor, " "Daniel Mack <danielncaiaq.de>, " diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 53ff25ac66d8..23be4daefeed 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -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; @@ -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; @@ -1192,6 +1198,7 @@ err_remove_chip: 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); @@ -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 @@ -1442,9 +1483,12 @@ 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); @@ -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); } @@ -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); } /** @@ -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; @@ -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); @@ -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 */ |