pinctrl: ssbi-gpio: convert to hierarchical IRQ helpers in gpio core
authorBrian Masney <masneyb@onstation.org>
Sat, 14 Sep 2019 11:10:10 +0000 (07:10 -0400)
committerLinus Walleij <linus.walleij@linaro.org>
Thu, 3 Oct 2019 13:02:40 +0000 (15:02 +0200)
Now that the GPIO core has support for hierarchical IRQ chips, convert
Qualcomm's ssbi-gpio over to use these new helpers to reduce duplicated
code across drivers.

Signed-off-by: Brian Masney <masneyb@onstation.org>
Link: https://lore.kernel.org/r/20190914111010.24384-1-masneyb@onstation.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/pinctrl/qcom/Kconfig
drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c

index 32fc2458b8eb98ded5a9fe7343ef5ce7dca2b320..41fab621de1bc67bbccde163b9156637b104c129 100644 (file)
@@ -152,6 +152,7 @@ config PINCTRL_QCOM_SSBI_PMIC
        select PINMUX
        select PINCONF
        select GENERIC_PINCONF
+       select GPIOLIB_IRQCHIP
        select IRQ_DOMAIN_HIERARCHY
        help
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
index c1f7d0799ebedcf9d56ae967afcb0a85f73a454f..dca86886b1f99c7bfabde96ea76331f78539edad 100644 (file)
@@ -56,7 +56,6 @@
 /**
  * struct pm8xxx_pin_data - dynamic configuration for a pin
  * @reg:               address of the control register
- * @irq:               IRQ from the PMIC interrupt controller
  * @power_source:      logical selected voltage source, mapping in static data
  *                     is used translate to register values
  * @mode:              operating mode for the pin (input/output)
@@ -72,7 +71,6 @@
  */
 struct pm8xxx_pin_data {
        unsigned reg;
-       int irq;
        u8 power_source;
        u8 mode;
        bool open_drain;
@@ -93,9 +91,6 @@ struct pm8xxx_gpio {
 
        struct pinctrl_desc desc;
        unsigned npins;
-
-       struct fwnode_handle *fwnode;
-       struct irq_domain *domain;
 };
 
 static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = {
@@ -491,13 +486,16 @@ static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
        struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
+       int ret, irq;
        bool state;
-       int ret;
 
-       if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) {
-               ret = pin->output_value;
-       } else if (pin->irq >= 0) {
-               ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state);
+       if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT)
+               return pin->output_value;
+
+       irq = chip->to_irq(chip, offset);
+       if (irq >= 0) {
+               ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL,
+                                           &state);
                if (!ret)
                        ret = !!state;
        } else
@@ -535,37 +533,6 @@ static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip,
 }
 
 
-static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
-       struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
-       struct irq_fwspec fwspec;
-       int ret;
-
-       fwspec.fwnode = pctrl->fwnode;
-       fwspec.param_count = 2;
-       fwspec.param[0] = offset + PM8XXX_GPIO_PHYSICAL_OFFSET;
-       fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
-
-       ret = irq_create_fwspec_mapping(&fwspec);
-
-       /*
-        * Cache the IRQ since pm8xxx_gpio_get() needs this to get determine the
-        * line level.
-        */
-       pin->irq = ret;
-
-       return ret;
-}
-
-static void pm8xxx_gpio_free(struct gpio_chip *chip, unsigned int offset)
-{
-       struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
-       struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
-
-       pin->irq = -1;
-}
-
 #ifdef CONFIG_DEBUG_FS
 #include <linux/seq_file.h>
 
@@ -624,13 +591,11 @@ static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 #endif
 
 static const struct gpio_chip pm8xxx_gpio_template = {
-       .free = pm8xxx_gpio_free,
        .direction_input = pm8xxx_gpio_direction_input,
        .direction_output = pm8xxx_gpio_direction_output,
        .get = pm8xxx_gpio_get,
        .set = pm8xxx_gpio_set,
        .of_xlate = pm8xxx_gpio_of_xlate,
-       .to_irq = pm8xxx_gpio_to_irq,
        .dbg_show = pm8xxx_gpio_dbg_show,
        .owner = THIS_MODULE,
 };
@@ -712,43 +677,24 @@ static int pm8xxx_domain_translate(struct irq_domain *domain,
        return 0;
 }
 
-static int pm8xxx_domain_alloc(struct irq_domain *domain, unsigned int virq,
-                              unsigned int nr_irqs, void *data)
+static unsigned int pm8xxx_child_offset_to_irq(struct gpio_chip *chip,
+                                              unsigned int offset)
 {
-       struct pm8xxx_gpio *pctrl = container_of(domain->host_data,
-                                                struct pm8xxx_gpio, chip);
-       struct irq_fwspec *fwspec = data;
-       struct irq_fwspec parent_fwspec;
-       irq_hw_number_t hwirq;
-       unsigned int type;
-       int ret, i;
-
-       ret = pm8xxx_domain_translate(domain, fwspec, &hwirq, &type);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < nr_irqs; i++)
-               irq_domain_set_info(domain, virq + i, hwirq + i,
-                                   &pm8xxx_irq_chip, pctrl, handle_level_irq,
-                                   NULL, NULL);
+       return offset + PM8XXX_GPIO_PHYSICAL_OFFSET;
+}
 
-       parent_fwspec.fwnode = domain->parent->fwnode;
-       parent_fwspec.param_count = 2;
-       parent_fwspec.param[0] = hwirq + 0xc0;
-       parent_fwspec.param[1] = fwspec->param[1];
+static int pm8xxx_child_to_parent_hwirq(struct gpio_chip *chip,
+                                       unsigned int child_hwirq,
+                                       unsigned int child_type,
+                                       unsigned int *parent_hwirq,
+                                       unsigned int *parent_type)
+{
+       *parent_hwirq = child_hwirq + 0xc0;
+       *parent_type = child_type;
 
-       return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
-                                           &parent_fwspec);
+       return 0;
 }
 
-static const struct irq_domain_ops pm8xxx_domain_ops = {
-       .activate = gpiochip_irq_domain_activate,
-       .alloc = pm8xxx_domain_alloc,
-       .deactivate = gpiochip_irq_domain_deactivate,
-       .free = irq_domain_free_irqs_common,
-       .translate = pm8xxx_domain_translate,
-};
-
 static const struct of_device_id pm8xxx_gpio_of_match[] = {
        { .compatible = "qcom,pm8018-gpio", .data = (void *) 6 },
        { .compatible = "qcom,pm8038-gpio", .data = (void *) 12 },
@@ -765,6 +711,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
        struct irq_domain *parent_domain;
        struct device_node *parent_node;
        struct pinctrl_pin_desc *pins;
+       struct gpio_irq_chip *girq;
        struct pm8xxx_gpio *pctrl;
        int ret, i;
 
@@ -800,7 +747,6 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
 
        for (i = 0; i < pctrl->desc.npins; i++) {
                pin_data[i].reg = SSBI_REG_ADDR_GPIO(i);
-               pin_data[i].irq = -1;
 
                ret = pm8xxx_pin_populate(pctrl, &pin_data[i]);
                if (ret)
@@ -841,19 +787,21 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
        if (!parent_domain)
                return -ENXIO;
 
-       pctrl->fwnode = of_node_to_fwnode(pctrl->dev->of_node);
-       pctrl->domain = irq_domain_create_hierarchy(parent_domain, 0,
-                                                   pctrl->chip.ngpio,
-                                                   pctrl->fwnode,
-                                                   &pm8xxx_domain_ops,
-                                                   &pctrl->chip);
-       if (!pctrl->domain)
-               return -ENODEV;
+       girq = &pctrl->chip.irq;
+       girq->chip = &pm8xxx_irq_chip;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_level_irq;
+       girq->fwnode = of_node_to_fwnode(pctrl->dev->of_node);
+       girq->parent_domain = parent_domain;
+       girq->child_to_parent_hwirq = pm8xxx_child_to_parent_hwirq;
+       girq->populate_parent_fwspec = gpiochip_populate_parent_fwspec_fourcell;
+       girq->child_offset_to_irq = pm8xxx_child_offset_to_irq;
+       girq->child_irq_domain_ops.translate = pm8xxx_domain_translate;
 
        ret = gpiochip_add_data(&pctrl->chip, pctrl);
        if (ret) {
                dev_err(&pdev->dev, "failed register gpiochip\n");
-               goto err_chip_add_data;
+               return ret;
        }
 
        /*
@@ -883,8 +831,6 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
 
 unregister_gpiochip:
        gpiochip_remove(&pctrl->chip);
-err_chip_add_data:
-       irq_domain_remove(pctrl->domain);
 
        return ret;
 }
@@ -894,7 +840,6 @@ static int pm8xxx_gpio_remove(struct platform_device *pdev)
        struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev);
 
        gpiochip_remove(&pctrl->chip);
-       irq_domain_remove(pctrl->domain);
 
        return 0;
 }