Merge branch 'gpio-irq-validmask' into devel
This commit is contained in:
Коммит
ccf1e9e1c0
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче