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 | struct lock_class_key *lock_key, | 86 | struct lock_class_key *lock_key, |
| 87 | struct lock_class_key *request_key); | 87 | struct lock_class_key *request_key); |
| 88 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); | 88 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); |
| 89 | static int gpiochip_irqchip_init_hw(struct gpio_chip *gpiochip); | ||
| 89 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); | 90 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); |
| 90 | static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip); | 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 | machine_gpiochip_add(chip); | 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 | ret = gpiochip_irqchip_init_valid_mask(chip); | 1414 | ret = gpiochip_irqchip_init_valid_mask(chip); |
| 1410 | if (ret) | 1415 | if (ret) |
| 1411 | goto err_remove_acpi_chip; | 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 | * The following is irqchip helper code for gpiochips. | 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 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc) | 1640 | static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc) |
| 1626 | { | 1641 | { |
| 1627 | struct gpio_irq_chip *girq = &gc->irq; | 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 | return 0; | 2462 | return 0; |
| 2448 | } | 2463 | } |
| 2449 | |||
| 2450 | static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} | 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 | static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) | 2471 | static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) |
| 2452 | { | 2472 | { |
| 2453 | return 0; | 2473 | return 0; |
| @@ -201,6 +201,14 @@ struct gpio_irq_chip { · 200 unmodified lines | |||
| 201 | */ | 201 | */ |
| 202 | bool threaded; | 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 | * @init_valid_mask: optional routine to initialize @valid_mask, to be | 213 | * @init_valid_mask: optional routine to initialize @valid_mask, to be |
| 206 | * used if not all GPIO lines are valid interrupts. Sometimes some | 214 | * used if not all GPIO lines are valid interrupts. Sometimes some |