From b056ca1c2f01b2d261c2dd6d167c17ac27977034 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Nov 2019 18:09:39 +0200 Subject: [PATCH 1/3] gpiolib: Introduce ->add_pin_ranges() callback When IRQ chip is being added by GPIO library, the ACPI based platform expects GPIO <-> pin mapping ranges to be initialized in order to correctly initialize ACPI event mechanism on affected platforms. Unfortunately this step is missed. Introduce ->add_pin_ranges() callback to fill the above mentioned gap. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Reviewed-by: Mika Westerberg Reviewed-by: Hans de Goede Tested-by: Hans de Goede --- drivers/gpio/gpiolib.c | 12 ++++++++++++ include/linux/gpio/driver.h | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 731d732cdc2b..1dc144f83483 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -390,6 +390,14 @@ static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip) gpiochip->valid_mask = NULL; } +static int gpiochip_add_pin_ranges(struct gpio_chip *gc) +{ + if (gc->add_pin_ranges) + return gc->add_pin_ranges(gc); + + return 0; +} + bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip, unsigned int offset) { @@ -1397,6 +1405,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, } } + ret = gpiochip_add_pin_ranges(chip); + if (ret) + goto err_remove_of_chip; + acpi_gpiochip_add(chip); machine_gpiochip_add(chip); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index cc9ade4552d9..e2480ef94c55 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -289,6 +289,9 @@ struct gpio_irq_chip { * state (such as pullup/pulldown configuration). * @init_valid_mask: optional routine to initialize @valid_mask, to be used if * not all GPIOs are valid. + * @add_pin_ranges: optional routine to initialize pin ranges, to be used when + * requires special mapping of the pins that provides GPIO functionality. + * It is called after adding GPIO chip and before adding IRQ chip. * @base: identifies the first GPIO number handled by this chip; * or, if negative during registration, requests dynamic ID allocation. * DEPRECATION: providing anything non-negative and nailing the base @@ -379,6 +382,8 @@ struct gpio_chip { unsigned long *valid_mask, unsigned int ngpios); + int (*add_pin_ranges)(struct gpio_chip *chip); + int base; u16 ngpio; const char *const *names; From cd242b333b0059fab46063f7f9cf8fd0d196d1c9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Nov 2019 19:07:30 +0200 Subject: [PATCH 2/3] gpio: merrifield: Add GPIO <-> pin mapping ranges via callback When IRQ chip is instantiated via GPIO library flow, the few functions, in particular the ACPI event registration mechanism, on some of ACPI based platforms expect that the pin ranges are initialized to that point. Add GPIO <-> pin mapping ranges via callback in the GPIO library flow. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Reviewed-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-merrifield.c | 42 ++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 0ee29c2049be..89550f38e061 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -396,14 +396,35 @@ static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) return name; } -static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip) { + struct mrfld_gpio *priv = gpiochip_get_data(chip); const struct mrfld_gpio_pinrange *range; const char *pinctrl_dev_name; + unsigned int i; + int retval; + + pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); + for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { + range = &mrfld_gpio_ranges[i]; + retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name, + range->gpio_base, + range->pin_base, + range->npins); + if (retval) { + dev_err(priv->dev, "failed to add GPIO pin range\n"); + return retval; + } + } + + return 0; +} + +static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ struct mrfld_gpio *priv; u32 gpio_base, irq_base; void __iomem *base; - unsigned int i; int retval; retval = pcim_enable_device(pdev); @@ -444,30 +465,16 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id priv->chip.base = gpio_base; priv->chip.ngpio = MRFLD_NGPIO; priv->chip.can_sleep = false; + priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges; raw_spin_lock_init(&priv->lock); - pci_set_drvdata(pdev, priv); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); return retval; } - pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); - for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { - range = &mrfld_gpio_ranges[i]; - retval = gpiochip_add_pin_range(&priv->chip, - pinctrl_dev_name, - range->gpio_base, - range->pin_base, - range->npins); - if (retval) { - dev_err(&pdev->dev, "failed to add GPIO pin range\n"); - return retval; - } - } - retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, handle_bad_irq, IRQ_TYPE_NONE); if (retval) { @@ -480,6 +487,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq, mrfld_irq_handler); + pci_set_drvdata(pdev, priv); return 0; } From 4a5e0f9e73511595c68f907a15772e5d1ba4aac6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Nov 2019 19:10:10 +0200 Subject: [PATCH 3/3] gpio: merrifield: Pass irqchip when adding gpiochip We need to convert all old gpio irqchips to pass the irqchip setup along when adding the gpio_chip. For more info see drivers/gpio/TODO. For chained irqchips this is a pretty straight-forward conversion. Cc: Andy Shevchenko Cc: Mika Westerberg Cc: Thierry Reding Signed-off-by: Linus Walleij Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Reviewed-by: Hans de Goede --- drivers/gpio/gpio-merrifield.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 89550f38e061..48918a016cd8 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -365,8 +365,9 @@ static void mrfld_irq_handler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } -static void mrfld_irq_init_hw(struct mrfld_gpio *priv) +static int mrfld_irq_init_hw(struct gpio_chip *chip) { + struct mrfld_gpio *priv = gpiochip_get_data(chip); void __iomem *reg; unsigned int base; @@ -378,6 +379,8 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv) reg = gpio_reg(&priv->chip, base, GFER); writel(0, reg); } + + return 0; } static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) @@ -422,6 +425,7 @@ static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip) static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct gpio_irq_chip *girq; struct mrfld_gpio *priv; u32 gpio_base, irq_base; void __iomem *base; @@ -469,24 +473,26 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id raw_spin_lock_init(&priv->lock); + girq = &priv->chip.irq; + girq->chip = &mrfld_irqchip; + girq->init_hw = mrfld_irq_init_hw; + girq->parent_handler = mrfld_irq_handler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, + sizeof(*girq->parents), GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = pdev->irq; + girq->first = irq_base; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); return retval; } - retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, - handle_bad_irq, IRQ_TYPE_NONE); - if (retval) { - dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); - return retval; - } - - mrfld_irq_init_hw(priv); - - gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq, - mrfld_irq_handler); - pci_set_drvdata(pdev, priv); return 0; }