Merge branch 'gpio-irq-validmask' of /home/linus/linux-pinctrl into devel

This commit is contained in:
Linus Walleij
2016-09-23 14:51:18 +02:00
3 changed files with 75 additions and 3 deletions

View File

@ -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);
@ -1397,6 +1404,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
@ -1438,9 +1479,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);
@ -1547,9 +1591,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);
}
@ -1558,6 +1605,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);
}
/**
@ -1593,6 +1642,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;
@ -1656,13 +1706,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);
@ -1674,6 +1728,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 */