Re: RFC: qcom spmi/ssbi-gpio hierarchical irqchip problems

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Dec 04, 2018 at 11:20:54AM +0100, Linus Walleij wrote:
> I'm a bit confused because the PM8xxx has its irqdomain
> inside drivers/mfd/qcom-pm8xxx.c and the PM8941 driver
> in drivers/mfd/qcom-spmi-pmic.c does not.
> 
> This on the PM8941 there appears to be no irqchip.
> Then it falls upward to the spmi bus. This is
> (qcom-msm8974.dtsi) an interrupt-controller with
> four cells, so it should be:
> 
> interrupt-parent = <&spmi_bus>;
> 
> The irqchip and domain of the parent should be what
> you find in drivers/spmi/spmi-pmic-arb.c

I attached what I have so far for hierarchical IRQs for spmi-gpio.
I hope it is alright to attach them directly and not use git send-email.

1) Patch 1 adds an alloc function to spmi-pmic-arb.c so that the IRQ
   chip is set properly for the parent IRQ domain.

2) Patch 2 adds the IRQ hierarchy support to pinctrl-spmi-gpio.c.

3) Patch 3 is how I'm planning to test that this is working properly on
   the Nexus 5 phone.

With this series, I see a long delay on startup and the following errors
in the console log:

[    1.374586] spmi spmi-0: pmic_arb_wait_for_done: transaction denied (0x5)
[    1.393541] qcom-spmi-iadc fc4cf000.spmi:pm8941@0:iadc@3600: conversion failed
[    1.393587] qcom-spmi-iadc fc4cf000.spmi:pm8941@0:iadc@3600: failed offset calibration
[    1.399681] spmi spmi-0: pmic_arb_wait_for_done: transaction denied (0x5)
[    1.407629] qcom-spmi-iadc: probe of fc4cf000.spmi:pm8941@0:iadc@3600 failed with error -110
[    1.414900] spmi spmi-0: pmic_arb_wait_for_done: transaction denied (0x5)
[    1.422949] spmi spmi-0: pmic_arb_wait_for_done: transaction denied (0x5)
[   41.433579] qcom-spmi-vadc fc4cf000.spmi:pm8941@0:vadc@3100: conversion failed
[   41.433626] qcom-spmi-vadc fc4cf000.spmi:pm8941@0:vadc@3100: measure reference points failed
[   41.439722] spmi spmi-0: pmic_arb_wait_for_done: transaction denied (0x5)
[   41.448296] qpnpint_spmi_write: 21 callbacks suppressed
[   41.448305] spmi spmi-0: failed irqchip transaction on d7

I'm going to keep digging but I'm posting this to see if anyone has any
suggestions.

Brian

>From c47691608856bb93fbbbfd74e4c1387376a7bc56 Mon Sep 17 00:00:00 2001
From: Brian Masney <masneyb@xxxxxxxxxxxxx>
Date: Sun, 16 Dec 2018 17:31:18 -0500
Subject: [PATCH 1/3] spmi: pmic-arb: irq hierarchy WIP

This is a work in progress that adds support for hierarchical irqs.

Signed-off-by: Brian Masney <masneyb@xxxxxxxxxxxxx>
---
 drivers/spmi/spmi-pmic-arb.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 360b8218f322..ce3e72003d95 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -1125,7 +1125,33 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
 	.apid_map_offset	= pmic_arb_apid_map_offset_v5,
 };
 
+static int qpnpint_irq_domain_alloc(struct irq_domain *domain,
+				    unsigned int virq, unsigned int nr_irqs,
+				    void *data)
+{
+	struct spmi_pmic_arb *pmic_arb = domain->host_data;
+	struct irq_fwspec *fwspec = data;
+	irq_hw_number_t hwirq;
+	unsigned int type;
+	int ret, i;
+
+	ret = qpnpint_irq_domain_dt_translate(domain,
+					      pmic_arb->spmic->dev.of_node,
+					      fwspec->param,
+					      fwspec->param_count, &hwirq,
+					      &type);
+
+	for (i = 0; i < nr_irqs; i++) {
+		ret = qpnpint_irq_domain_map(domain, virq + i, hwirq + i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
+	.alloc	= qpnpint_irq_domain_alloc,
 	.map	= qpnpint_irq_domain_map,
 	.xlate	= qpnpint_irq_domain_dt_translate,
 };
-- 
2.17.2

>From f5a1924dac8212c5ae3bad61530b6f25c398b620 Mon Sep 17 00:00:00 2001
From: Brian Masney <masneyb@xxxxxxxxxxxxx>
Date: Sun, 16 Dec 2018 20:32:55 -0500
Subject: [PATCH 2/3] pinctrl: qcom: spmi-gpio: irq hierarchy WIP

This is a work in progress that adds support for hierarchical irqs.

Signed-off-by: Brian Masney <masneyb@xxxxxxxxxxxxx>
---
 drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 131 ++++++++++++++++++++++-
 1 file changed, 130 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 4458d44dfcf6..03393cf3b883 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -179,6 +179,7 @@ struct pmic_gpio_state {
 	struct regmap	*map;
 	struct pinctrl_dev *ctrl;
 	struct gpio_chip chip;
+	struct irq_domain *parent_domain;
 };
 
 static const struct pinconf_generic_params pmic_gpio_bindings[] = {
@@ -935,13 +936,121 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state,
 	return 0;
 }
 
+static int pmic_gpio_irq_request_resources(struct irq_data *data)
+{
+	struct pmic_gpio_state *state = data->domain->host_data;
+	struct irq_data *parent_data = data->parent_data;
+	int ret;
+
+	ret = gpiochip_lock_as_irq(&state->chip, data->hwirq);
+	if (ret) {
+		dev_err(state->dev, "unable to lock HW IRQ %lu for IRQ: %d\n",
+			data->hwirq, ret);
+		return ret;
+	}
+
+	if (parent_data && parent_data->chip->irq_request_resources) {
+		ret = parent_data->chip->irq_request_resources(parent_data);
+		if (ret)
+			goto error;
+	}
+
+	return 0;
+error:
+	gpiochip_unlock_as_irq(&state->chip, data->hwirq);
+	return ret;
+}
+
+static void pmic_gpio_irq_release_resources(struct irq_data *data)
+{
+	struct pmic_gpio_state *state = data->domain->host_data;
+	struct irq_data *parent_data = data->parent_data;
+
+	if (parent_data && parent_data->chip->irq_release_resources)
+		parent_data->chip->irq_release_resources(parent_data);
+
+	gpiochip_unlock_as_irq(&state->chip, data->hwirq);
+}
+
+static struct irq_chip pmic_gpio_irq_chip = {
+	.name			= "spmi-gpio",
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_ack		= irq_chip_ack_parent,
+	.irq_mask		= irq_chip_mask_parent,
+	.irq_unmask		= irq_chip_unmask_parent,
+	.irq_set_type		= irq_chip_set_type_parent,
+	.irq_set_wake		= irq_chip_set_wake_parent,
+	.irq_request_resources	= pmic_gpio_irq_request_resources,
+	.irq_release_resources	= pmic_gpio_irq_release_resources,
+};
+
+static int pmic_gpio_domain_translate(struct irq_domain *domain,
+				      struct irq_fwspec *fwspec,
+				      unsigned long *hwirq,
+				      unsigned int *type)
+{
+	struct pmic_gpio_state *state = domain->host_data;
+
+	if ((fwspec->param_count != 4) ||
+	    (fwspec->param[1] >= state->chip.ngpio))
+		return -EINVAL;
+
+	*hwirq = fwspec->param[1];
+	*type = fwspec->param[3];
+
+	return 0;
+}
+
+static int pmic_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
+				  unsigned int nr_irqs, void *data)
+{
+	struct pmic_gpio_state *state = domain->host_data;
+	struct irq_fwspec *fwspec = data;
+	struct irq_fwspec parent_fwspec;
+	irq_hw_number_t hwirq;
+	unsigned int type;
+	int ret;
+
+	if (WARN_ON(nr_irqs != 1))
+		return -EINVAL;
+
+	ret = pmic_gpio_domain_translate(domain, fwspec, &hwirq, &type);
+	if (ret)
+		return ret;
+
+	ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+					    &pmic_gpio_irq_chip, state);
+	if (ret)
+		dev_info(state->dev,
+			 "Error setting up domain hwirq and chip: %d", ret);
+
+	parent_fwspec.fwnode = domain->parent->fwnode;
+	parent_fwspec.param_count = 4;
+	parent_fwspec.param[0] = fwspec->param[0];
+	parent_fwspec.param[1] = fwspec->param[1];
+	parent_fwspec.param[2] = fwspec->param[2];
+	parent_fwspec.param[3] = fwspec->param[3];
+
+	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+					    &parent_fwspec);
+}
+
+static const struct irq_domain_ops pmic_gpio_domain_ops = {
+	.alloc		= pmic_gpio_domain_alloc,
+	.free		= irq_domain_free_irqs_common,
+	.translate	= pmic_gpio_domain_translate,
+};
+
 static int pmic_gpio_probe(struct platform_device *pdev)
 {
+	struct irq_domain *parent_domain;
 	struct device *dev = &pdev->dev;
 	struct pinctrl_pin_desc *pindesc;
 	struct pinctrl_desc *pctrldesc;
 	struct pmic_gpio_pad *pad, *pads;
 	struct pmic_gpio_state *state;
+	struct fwnode_handle *fwnode;
+	struct device_node *parent;
 	int ret, npins, i;
 	u32 reg;
 
@@ -1022,10 +1131,27 @@ static int pmic_gpio_probe(struct platform_device *pdev)
 	if (IS_ERR(state->ctrl))
 		return PTR_ERR(state->ctrl);
 
+	parent = of_irq_find_parent(state->dev->of_node);
+	if (!parent)
+		return -ENXIO;
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain)
+		return -ENXIO;
+
+	fwnode = of_node_to_fwnode(state->dev->of_node);
+	state->parent_domain = irq_domain_create_hierarchy(parent_domain, 0,
+							   state->chip.ngpio,
+							   fwnode,
+							   &pmic_gpio_domain_ops,
+							   state);
+	if (!state->parent_domain)
+		return -ENODEV;
+
 	ret = gpiochip_add_data(&state->chip, state);
 	if (ret) {
 		dev_err(state->dev, "can't add gpio chip\n");
-		return ret;
+		goto err_chip_add_data;
 	}
 
 	/*
@@ -1051,6 +1177,8 @@ static int pmic_gpio_probe(struct platform_device *pdev)
 
 err_range:
 	gpiochip_remove(&state->chip);
+err_chip_add_data:
+	irq_domain_remove(state->parent_domain);
 	return ret;
 }
 
@@ -1059,6 +1187,7 @@ static int pmic_gpio_remove(struct platform_device *pdev)
 	struct pmic_gpio_state *state = platform_get_drvdata(pdev);
 
 	gpiochip_remove(&state->chip);
+	irq_domain_remove(state->parent_domain);
 	return 0;
 }
 
-- 
2.17.2

>From 3a6fff025d9c6423d2023090700654bb1a3fcff9 Mon Sep 17 00:00:00 2001
From: Brian Masney <masneyb@xxxxxxxxxxxxx>
Date: Sun, 16 Dec 2018 20:33:10 -0500
Subject: [PATCH 3/3] irq hierarchy test

This is what I am using to test that hierarchical irqs are working
correctly on spmi-gpio.

Signed-off-by: Brian Masney <masneyb@xxxxxxxxxxxxx>
---
 arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts | 4 ++--
 arch/arm/boot/dts/qcom-pm8941.dtsi                       | 3 +++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
index 551d262a044a..afe396293bf3 100644
--- a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
+++ b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
@@ -333,14 +333,14 @@
 
 		volume-up {
 			label = "volume_up";
-			gpios = <&pm8941_gpios 2 GPIO_ACTIVE_LOW>;
+			interrupts-extended = <&pm8941_gpios 0 2 0 IRQ_TYPE_EDGE_RISING>;
 			linux,input-type = <1>;
 			linux,code = <KEY_VOLUMEUP>;
 		};
 
 		volume-down {
 			label = "volume_down";
-			gpios = <&pm8941_gpios 3 GPIO_ACTIVE_LOW>;
+			interrupts-extended = <&pm8941_gpios 0 3 0 IRQ_TYPE_EDGE_RISING>;
 			linux,input-type = <1>;
 			linux,code = <KEY_VOLUMEDOWN>;
 		};
diff --git a/arch/arm/boot/dts/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom-pm8941.dtsi
index 9a91b758f7aa..d0b7f0eff288 100644
--- a/arch/arm/boot/dts/qcom-pm8941.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8941.dtsi
@@ -65,6 +65,9 @@
 			gpio-controller;
 			gpio-ranges = <&pm8941_gpios 0 0 36>;
 			#gpio-cells = <2>;
+			interrupt-parent = <&spmi_bus>;
+			interrupt-controller;
+			#interrupt-cells = <4>;
 			interrupts = <0 0xc0 0 IRQ_TYPE_NONE>,
 				     <0 0xc1 0 IRQ_TYPE_NONE>,
 				     <0 0xc2 0 IRQ_TYPE_NONE>,
-- 
2.17.2


[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux