mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-12 20:31:49 +00:00
Merge branch 'gpio-irq-validmask' into devel
This commit is contained in:
commit
ccf1e9e1c0
@ -262,6 +262,12 @@ symbol:
|
|||||||
to the container using container_of().
|
to the container using container_of().
|
||||||
(See Documentation/driver-model/design-patterns.txt)
|
(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
|
* 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
|
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
|
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_free_hogs(struct gpio_chip *chip);
|
||||||
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
|
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;
|
static bool gpiolib_initialized;
|
||||||
|
|
||||||
@ -1167,6 +1169,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
|
|||||||
if (status)
|
if (status)
|
||||||
goto err_remove_from_list;
|
goto err_remove_from_list;
|
||||||
|
|
||||||
|
status = gpiochip_irqchip_init_valid_mask(chip);
|
||||||
|
if (status)
|
||||||
|
goto err_remove_from_list;
|
||||||
|
|
||||||
status = of_gpiochip_add(chip);
|
status = of_gpiochip_add(chip);
|
||||||
if (status)
|
if (status)
|
||||||
goto err_remove_chip;
|
goto err_remove_chip;
|
||||||
@ -1192,6 +1198,7 @@ err_remove_chip:
|
|||||||
acpi_gpiochip_remove(chip);
|
acpi_gpiochip_remove(chip);
|
||||||
gpiochip_free_hogs(chip);
|
gpiochip_free_hogs(chip);
|
||||||
of_gpiochip_remove(chip);
|
of_gpiochip_remove(chip);
|
||||||
|
gpiochip_irqchip_free_valid_mask(chip);
|
||||||
err_remove_from_list:
|
err_remove_from_list:
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
list_del(&gdev->list);
|
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.
|
* 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_set_chained_irqchip() - sets a chained irqchip to a gpiochip
|
||||||
* @gpiochip: the gpiochip to set the irqchip chain to
|
* @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 */
|
/* 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),
|
irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
|
||||||
parent_irq);
|
parent_irq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
|
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 */
|
/* Remove all IRQ mappings and delete the domain */
|
||||||
if (gpiochip->irqdomain) {
|
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_dispose_mapping(
|
||||||
irq_find_mapping(gpiochip->irqdomain, offset));
|
irq_find_mapping(gpiochip->irqdomain, offset));
|
||||||
|
}
|
||||||
irq_domain_remove(gpiochip->irqdomain);
|
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->irq_release_resources = NULL;
|
||||||
gpiochip->irqchip = 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 lock_class_key *lock_key)
|
||||||
{
|
{
|
||||||
struct device_node *of_node;
|
struct device_node *of_node;
|
||||||
|
bool irq_base_set = false;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
unsigned irq_base = 0;
|
unsigned irq_base = 0;
|
||||||
|
|
||||||
@ -1646,13 +1696,17 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
|||||||
* necessary to allocate descriptors for all IRQs.
|
* necessary to allocate descriptors for all IRQs.
|
||||||
*/
|
*/
|
||||||
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
||||||
|
if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
|
||||||
|
continue;
|
||||||
irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
|
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
|
* Store the base into the gpiochip to be used when
|
||||||
* unmapping the irqs.
|
* unmapping the irqs.
|
||||||
*/
|
*/
|
||||||
gpiochip->irq_base = irq_base;
|
gpiochip->irq_base = irq_base;
|
||||||
|
irq_base_set = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
acpi_gpiochip_request_interrupts(gpiochip);
|
acpi_gpiochip_request_interrupts(gpiochip);
|
||||||
@ -1664,6 +1718,12 @@ EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add);
|
|||||||
#else /* CONFIG_GPIOLIB_IRQCHIP */
|
#else /* CONFIG_GPIOLIB_IRQCHIP */
|
||||||
|
|
||||||
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
|
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 */
|
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||||
|
|
||||||
|
@ -112,6 +112,10 @@ enum single_ended_mode {
|
|||||||
* initialization, provided by GPIO driver
|
* initialization, provided by GPIO driver
|
||||||
* @irq_parent: GPIO IRQ chip parent/bank linux irq number,
|
* @irq_parent: GPIO IRQ chip parent/bank linux irq number,
|
||||||
* provided by GPIO driver
|
* 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
|
* @lock_key: per GPIO IRQ chip lockdep class
|
||||||
*
|
*
|
||||||
* A gpio_chip can help platforms abstract various sources of GPIOs so
|
* 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;
|
irq_flow_handler_t irq_handler;
|
||||||
unsigned int irq_default_type;
|
unsigned int irq_default_type;
|
||||||
int irq_parent;
|
int irq_parent;
|
||||||
|
bool irq_need_valid_mask;
|
||||||
|
unsigned long *irq_valid_mask;
|
||||||
struct lock_class_key *lock_key;
|
struct lock_class_key *lock_key;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user