After changing the drivers to use GPIO core to add an IRQ chip it appears that some of them requires a hardware initialization before adding the IRQ chip. Add an optional callback ->init_hw() to allow that drivers to initialize hardware if needed. This change is a part of the fix NULL pointer dereference brought to the several drivers recently.
Unified · Split
| @@ -86,6 +86,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, · 85 unmodified lines | ||
| 86 | 86 | struct lock_class_key *lock_key, |
| 87 | 87 | struct lock_class_key *request_key); |
| 88 | 88 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); |
| 89 | +static int gpiochip_irqchip_init_hw(struct gpio_chip *gpiochip); | |
| 89 | 90 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); |
| 90 | 91 | static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip); |
| 91 | 92 | |
| @@ -1406,6 +1407,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, · 1314 unmodified lines | ||
| 1406 | 1407 | |
| 1407 | 1408 | machine_gpiochip_add(chip); |
| 1408 | 1409 | |
| 1410 | + ret = gpiochip_irqchip_init_hw(chip); | |
| 1411 | + if (ret) | |
| 1412 | + goto err_remove_acpi_chip; | |
| 1413 | + | |
| 1409 | 1414 | ret = gpiochip_irqchip_init_valid_mask(chip); |
| 1410 | 1415 | if (ret) |
| 1411 | 1416 | goto err_remove_acpi_chip; |
| @@ -1622,6 +1627,16 @@ static struct gpio_chip *find_chip_by_name(const char *name) · 210 unmodified lines | ||
| 1622 | 1627 | * The following is irqchip helper code for gpiochips. |
| 1623 | 1628 | */ |
| 1624 | 1629 | |
| 1630 | +static int gpiochip_irqchip_init_hw(struct gpio_chip *gc) | |
| 1631 | +{ | |
| 1632 | + struct gpio_irq_chip *girq = &gc->irq; | |
| 1633 | + | |
| 1634 | + if (!girq->init_hw) | |
| 1635 | + return 0; | |
| 1636 | + | |
| 1637 | + return girq->init_hw(gc); | |
| 1638 | +} | |
| 1639 | + | |
| 1625 | 1640 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc) |
| 1626 | 1641 | { |
| 1627 | 1642 | struct gpio_irq_chip *girq = &gc->irq; |
| @@ -2446,8 +2461,13 @@ static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip, · 818 unmodified lines | ||
| 2446 | 2461 | { |
| 2447 | 2462 | return 0; |
| 2448 | 2463 | } |
| 2449 | − | |
| 2450 | 2464 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} |
| 2465 | + | |
| 2466 | +static inline int gpiochip_irqchip_init_hw(struct gpio_chip *gpiochip) | |
| 2467 | +{ | |
| 2468 | + return 0; | |
| 2469 | +} | |
| 2470 | + | |
| 2451 | 2471 | static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) |
| 2452 | 2472 | { |
| 2453 | 2473 | return 0; |
| @@ -201,6 +201,14 @@ struct gpio_irq_chip { · 200 unmodified lines | ||
| 201 | 201 | */ |
| 202 | 202 | bool threaded; |
| 203 | 203 | |
| 204 | + /** | |
| 205 | + * @init_hw: optional routine to initialize hardware before | |
| 206 | + * an IRQ chip will be added. This is quite useful when | |
| 207 | + * a particular driver wants to clear IRQ related registers | |
| 208 | + * in order to avoid undesired events. | |
| 209 | + */ | |
| 210 | + int (*init_hw)(struct gpio_chip *chip); | |
| 211 | + | |
| 204 | 212 | /** |
| 205 | 213 | * @init_valid_mask: optional routine to initialize @valid_mask, to be |
| 206 | 214 | * used if not all GPIO lines are valid interrupts. Sometimes some |