Skip to content

Commit

Permalink
gpiolib: Initialize the hardware with a callback
Browse files Browse the repository at this point in the history
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.

Cc: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Andy Shevchenko authored and Linus Walleij committed Oct 14, 2019
1 parent 6658f87 commit 9411e3a
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 1 deletion.
22 changes: 21 additions & 1 deletion drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
struct lock_class_key *lock_key,
struct lock_class_key *request_key);
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
static int gpiochip_irqchip_init_hw(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);

Expand Down Expand Up @@ -1406,6 +1407,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,

machine_gpiochip_add(chip);

ret = gpiochip_irqchip_init_hw(chip);
if (ret)
goto err_remove_acpi_chip;

ret = gpiochip_irqchip_init_valid_mask(chip);
if (ret)
goto err_remove_acpi_chip;
Expand Down Expand Up @@ -1622,6 +1627,16 @@ static struct gpio_chip *find_chip_by_name(const char *name)
* The following is irqchip helper code for gpiochips.
*/

static int gpiochip_irqchip_init_hw(struct gpio_chip *gc)
{
struct gpio_irq_chip *girq = &gc->irq;

if (!girq->init_hw)
return 0;

return girq->init_hw(gc);
}

static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc)
{
struct gpio_irq_chip *girq = &gc->irq;
Expand Down Expand Up @@ -2446,8 +2461,13 @@ static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
{
return 0;
}

static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}

static inline int gpiochip_irqchip_init_hw(struct gpio_chip *gpiochip)
{
return 0;
}

static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
{
return 0;
Expand Down
8 changes: 8 additions & 0 deletions include/linux/gpio/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@ struct gpio_irq_chip {
*/
bool threaded;

/**
* @init_hw: optional routine to initialize hardware before
* an IRQ chip will be added. This is quite useful when
* a particular driver wants to clear IRQ related registers
* in order to avoid undesired events.
*/
int (*init_hw)(struct gpio_chip *chip);

/**
* @init_valid_mask: optional routine to initialize @valid_mask, to be
* used if not all GPIO lines are valid interrupts. Sometimes some
Expand Down

0 comments on commit 9411e3a

Please sign in to comment.