Commit ae436fe8 authored by Brian Masney's avatar Brian Masney Committed by Linus Walleij
Browse files

pinctrl: ssbi-gpio: convert to hierarchical IRQ helpers in gpio core



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: default avatarBrian Masney <masneyb@onstation.org>
Link: https://lore.kernel.org/r/20190914111010.24384-1-masneyb@onstation.org


Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent be4c60b5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+33 −88
Original line number Diff line number Diff line
@@ -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;
}