[tip: irq/drivers] irqchip/qcom-pdc: Differentiate between direct SPI and GPIO as SPI

From: tip-bot2 for Maulik Shah

Date: Tue Jul 07 2026 - 16:33:55 EST


The following commit has been merged into the irq/drivers branch of tip:

Commit-ID: 45af2d61edf62938b021b86439a1dd797fd74a91
Gitweb: https://git.kernel.org/tip/45af2d61edf62938b021b86439a1dd797fd74a91
Author: Maulik Shah <maulik.shah@xxxxxxxxxxxxxxxx>
AuthorDate: Tue, 07 Jul 2026 14:51:35 +05:30
Committer: Thomas Gleixner <tglx@xxxxxxxxxx>
CommitterDate: Tue, 07 Jul 2026 22:03:09 +02:00

irqchip/qcom-pdc: Differentiate between direct SPI and GPIO as SPI

Before commit 4dc70713dc24 ("irqchip/qcom-pdc: Kill non-wakeup irqdomain")
there were separate domains for direct SPIs and GPIOs used as SPIs.

Separate domains can be useful to have separate interrupt chips for
different functionalities. Since the commit unified both domains there
is no way to differentiate.

In preparation to add the second level interrupt controller support where
GPIO interrupts get latched at PDC (but not direct SPIs) there is a need to
differentiate between SPIs and GPIOs as SPIs. Reverting above commit does
is not a good option as it leads to waste of resources.

PDC hardware provides the IRQ_PARAM register to enumerate the number of
direct SPIs and the number of GPIOs as SPIs. Further PDC allocates direct
SPIs at the beginning and all GPIOs as SPIs are allocated at the end. This
information can be used in the driver to differentiate them.

Add the support to read this register and keep this information in struct
pdc_desc. Later change utilizes it.

[ tglx: Massage change log ]

Signed-off-by: Maulik Shah <maulik.shah@xxxxxxxxxxxxxxxx>
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
Link: https://patch.msgid.link/20260707-hamoa_pdc_v3-v4-3-dfd1f4a3ae89@xxxxxxxxxxxxxxxx
---
drivers/irqchip/qcom-pdc.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)

diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index 5100a10..253fb69 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -61,6 +61,11 @@
* | | [4] GPIO_STATUS| [4] GPIO_MASK |
* | [31:3] Unused | [3] GPIO_MASK | [3] IRQ_ENABLE |
* | [0:2] Type | [0:2] Type | [0:2] Type |
+ * |---------------------------------------------------------------|
+ * | IRQ_PARAM | IRQ_PARAM | IRQ_PARAM |
+ * | | |
+ * | [15:8] NUM_GPIO | [15:8] NUM_GPIO | [15:8] NUM_GPIO |
+ * | [7:0] NUM_SPI | [7:0] NUM_SPI | [7:0] NUM_SPI |
* +---------------------------------------------------------------+
*/

@@ -69,10 +74,12 @@
*
* @irq_en_reg: IRQ_ENABLE_BANK register location
* @irq_cfg_reg: IRQ_CFG register location
+ * @irq_param_reg: IRQ_PARAM register location
*/
struct pdc_regs {
u32 irq_en_reg;
u32 irq_cfg_reg;
+ u32 irq_param_reg;
};

/**
@@ -92,6 +99,7 @@ struct pdc_irq_cfg {
* @base: PDC base register for DRV2 / HLOS
* @prev_base: PDC DRV1 base, applicable only for x1e RTL bug.
* @version: PDC version
+ * @num_spis: Total number of direct SPI interrupts
* @region: PDC interrupt continuous range
* @region_cnt: Total PDC ranges
* @x1e_quirk: x1e H/W Bug handling
@@ -104,6 +112,7 @@ struct pdc_desc {
void __iomem *base;
void __iomem *prev_base;
u32 version;
+ u32 num_spis;

struct pdc_pin_region *region;
int region_cnt;
@@ -120,6 +129,7 @@ struct pdc_desc {

static const struct pdc_regs pdc_v3_2 = {
.irq_cfg_reg = 0x110,
+ .irq_param_reg = 0x100c,
};

static const struct pdc_irq_cfg pdc_cfg_v3_2 = {
@@ -130,6 +140,7 @@ static const struct pdc_irq_cfg pdc_cfg_v3_2 = {
static const struct pdc_regs pdc_v3_0 = {
.irq_en_reg = 0x10,
.irq_cfg_reg = 0x110,
+ .irq_param_reg = 0x100c,
};

static const struct pdc_irq_cfg pdc_cfg_v3_0 = {
@@ -139,6 +150,7 @@ static const struct pdc_irq_cfg pdc_cfg_v3_0 = {
static const struct pdc_regs pdc_v2_7 = {
.irq_en_reg = 0x10,
.irq_cfg_reg = 0x110,
+ .irq_param_reg = 0x100c,
};

static const struct pdc_irq_cfg pdc_cfg_v2_7 = {
@@ -445,6 +457,7 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare
struct device *dev = &pdev->dev;
resource_size_t res_size;
struct resource res;
+ u32 irq_param;
int ret;

/* compat with old sm8150 DT which had very small region for PDC */
@@ -500,6 +513,9 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare
pdc->x1e_quirk = true;
}

+ irq_param = pdc_reg_read(pdc->regs->irq_param_reg, 0);
+ pdc->num_spis = FIELD_GET(GENMASK(7, 0), irq_param);
+
parent_domain = irq_find_host(parent);
if (!parent_domain) {
pr_err("%pOF: unable to find PDC's parent domain\n", node);