[PATCH 09/27] gpio: rockchip: Add RK3572 GPIO support

Cunhao Lu via B4 Relay devnull+1579567540.qq.com at kernel.org
Wed Oct 21 09:11:06 PDT 2026


From: Cunhao Lu <1579567540 at qq.com>

Support GPIO V2.7, four parent interrupts, and firmware-provided
interrupt-group masks. Keep all pins on the primary interrupt when group
queries are unavailable.

Signed-off-by: Cunhao Lu <1579567540 at qq.com>
---
 drivers/gpio/gpio-rockchip.c        | 91 +++++++++++++++++++++++++++++++++----
 drivers/pinctrl/pinctrl-rockchip.h  |  8 +++-
 include/soc/rockchip/rockchip_sip.h |  5 ++
 3 files changed, 92 insertions(+), 12 deletions(-)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 77b239a9a601e..35894a68b5446 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -6,6 +6,7 @@
  * Copyright (c) 2021 Rockchip Electronics Co. Ltd.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/device.h>
@@ -21,6 +22,7 @@
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <soc/rockchip/rockchip_sip.h>
 
 #include "../pinctrl/core.h"
 #include "../pinctrl/pinctrl-rockchip.h"
@@ -35,6 +37,7 @@
 #define GPIO_TYPE_V2		(0x01000C2B)
 #define GPIO_TYPE_V2_1		(0x0101157C)
 #define GPIO_TYPE_V2_2		(0x010219C8)
+#define GPIO_TYPE_V2_7		(0x01074D2E)
 
 static const struct rockchip_gpio_regs gpio_regs_v1 = {
 	.port_dr = 0x00,
@@ -209,12 +212,27 @@ static int rockchip_gpio_set_debounce(struct gpio_chip *gc,
 	if (bank->gpio_type == GPIO_TYPE_V2 && !IS_ERR(bank->db_clk)) {
 		div_debounce_support = true;
 		freq = clk_get_rate(bank->db_clk);
-		max_debounce = (GENMASK(23, 0) + 1) * 2 * 1000000 / freq;
-		if (debounce > max_debounce)
-			return -EINVAL;
 
-		div = debounce * freq;
-		div_reg = DIV_ROUND_CLOSEST_ULL(div, 2 * USEC_PER_SEC) - 1;
+		if (of_device_is_compatible(bank->of_node, "rockchip,rk3572-gpio-bank")) {
+			if (!freq)
+				return -EINVAL;
+
+			div = (u64)(GENMASK(23, 0) + 1) * USEC_PER_SEC;
+			max_debounce = div_u64(div, 2 * freq);
+			if (debounce > max_debounce)
+				return -EINVAL;
+
+			div = (u64)debounce * freq * 2;
+			div_reg = DIV_ROUND_CLOSEST_ULL(div, USEC_PER_SEC);
+			div_reg = div_reg ? div_reg - 1 : 0;
+		} else {
+			max_debounce = (GENMASK(23, 0) + 1) * 2 * 1000000 / freq;
+			if (debounce > max_debounce)
+				return -EINVAL;
+
+			div = debounce * freq;
+			div_reg = DIV_ROUND_CLOSEST_ULL(div, 2 * USEC_PER_SEC) - 1;
+		}
 	} else {
 		div_debounce_support = false;
 	}
@@ -342,6 +360,12 @@ static void rockchip_irq_demux(struct irq_desc *desc)
 	chained_irq_enter(chip, desc);
 
 	pending = readl_relaxed(bank->reg_base + bank->gpio_regs->int_status);
+	for (unsigned int i = 0; i < bank->nr_irqs; i++) {
+		if (bank->irqs[i] == irq_desc_get_irq(desc)) {
+			pending &= bank->irq_masks[i];
+			break;
+		}
+	}
 	for_each_set_bit(irq, &pending, 32) {
 		dev_dbg(bank->dev, "handling irq %d\n", irq);
 
@@ -568,8 +592,9 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank)
 	rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->int_en);
 	gc->mask_cache = 0xffffffff;
 
-	irq_set_chained_handler_and_data(bank->irq,
-					 rockchip_irq_demux, bank);
+	for (unsigned int i = 0; i < bank->nr_irqs; i++)
+		irq_set_chained_handler_and_data(bank->irqs[i],
+						 rockchip_irq_demux, bank);
 
 	return 0;
 }
@@ -645,6 +670,36 @@ static void rockchip_clk_put(void *data)
 	clk_put(clk);
 }
 
+static int rockchip_gpio_read_irq_groups(struct rockchip_pin_bank *bank)
+{
+	struct arm_smccc_res res;
+	u32 assigned = 0;
+	int status;
+
+	for (unsigned int i = 1; i < bank->nr_irqs; i++) {
+		arm_smccc_smc(ROCKCHIP_SIP_GPIO_CONFIG, ROCKCHIP_SIP_GPIO_GET_GROUP,
+			      bank->bank_num, i, 0, 0, 0, 0, &res);
+		status = (int)res.a0;
+		if (i == 1 && (status == SMCCC_RET_NOT_SUPPORTED ||
+			       status == ROCKCHIP_SIP_RET_NOT_SUPPORTED)) {
+			/* Older firmware leaves all pins on the primary IRQ. */
+			dev_dbg(bank->dev, "GPIO group query unsupported: %d\n",
+				status);
+			break;
+		}
+		if (status)
+			return dev_err_probe(bank->dev, -EIO,
+					     "cannot read interrupt group %u: %d\n",
+					     i, status);
+		bank->irq_masks[i] = res.a1;
+		if (assigned & bank->irq_masks[i])
+			return -EINVAL;
+		assigned |= bank->irq_masks[i];
+	}
+	bank->irq_masks[0] = ~assigned;
+	return 0;
+}
+
 static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
 {
 	struct platform_device *pdev = to_platform_device(bank->dev);
@@ -654,10 +709,23 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
 	if (IS_ERR(bank->reg_base))
 		return PTR_ERR(bank->reg_base);
 
-	ret = platform_get_irq(pdev, 0);
+	ret = platform_irq_count(pdev);
 	if (ret < 0)
 		return ret;
-	bank->irq = ret;
+	if (ret != (of_device_is_compatible(bank->of_node,
+					    "rockchip,rk3572-gpio-bank") ? 4 : 1))
+		return -EINVAL;
+	bank->nr_irqs = ret;
+	for (unsigned int i = 0; i < bank->nr_irqs; i++) {
+		ret = platform_get_irq(pdev, i);
+		if (ret < 0)
+			return ret;
+		bank->irqs[i] = ret;
+	}
+
+	ret = rockchip_gpio_read_irq_groups(bank);
+	if (ret)
+		return ret;
 
 	bank->clk = devm_clk_get_enabled(bank->dev, NULL);
 	if (IS_ERR(bank->clk))
@@ -669,6 +737,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
 	case GPIO_TYPE_V2:
 	case GPIO_TYPE_V2_1:
 	case GPIO_TYPE_V2_2:
+	case GPIO_TYPE_V2_7:
 		bank->gpio_regs = &gpio_regs_v2;
 		bank->gpio_type = GPIO_TYPE_V2;
 		bank->db_clk = of_clk_get(bank->of_node, 1);
@@ -797,7 +866,8 @@ static void rockchip_gpio_remove(struct platform_device *pdev)
 {
 	struct rockchip_pin_bank *bank = platform_get_drvdata(pdev);
 
-	irq_set_chained_handler_and_data(bank->irq, NULL, NULL);
+	for (unsigned int i = 0; i < bank->nr_irqs; i++)
+		irq_set_chained_handler_and_data(bank->irqs[i], NULL, NULL);
 	if (bank->domain) {
 		irq_domain_remove_generic_chips(bank->domain);
 		irq_domain_remove(bank->domain);
@@ -807,6 +877,7 @@ static void rockchip_gpio_remove(struct platform_device *pdev)
 
 static const struct of_device_id rockchip_gpio_match[] = {
 	{ .compatible = "rockchip,gpio-bank", },
+	{ .compatible = "rockchip,rk3572-gpio-bank" },
 	{ .compatible = "rockchip,rk3188-gpio-bank0" },
 	{ },
 };
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 553197f6dc690..058b58dcde404 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -302,7 +302,9 @@ struct rockchip_drv {
  *	    bank has its own IOC block
  * @clk: clock of the gpio bank
  * @db_clk: clock of the gpio debounce
- * @irq: interrupt of the gpio bank
+ * @irqs: parent interrupts of the GPIO bank
+ * @irq_masks: pins assigned to each parent interrupt
+ * @nr_irqs: number of parent interrupts
  * @saved_masks: Saved content of GPIO_INTEN at suspend time.
  * @pin_base: first pin number
  * @nr_pins: number of pins in this bank
@@ -331,7 +333,9 @@ struct rockchip_pin_bank {
 	struct regmap			*regmap_ioc;
 	struct clk			*clk;
 	struct clk			*db_clk;
-	int				irq;
+	unsigned int			irqs[4];
+	u32				irq_masks[4];
+	unsigned int			nr_irqs;
 	u32				saved_masks;
 	u32				pin_base;
 	u8				nr_pins;
diff --git a/include/soc/rockchip/rockchip_sip.h b/include/soc/rockchip/rockchip_sip.h
index 501ad1fedb201..984272ede3baf 100644
--- a/include/soc/rockchip/rockchip_sip.h
+++ b/include/soc/rockchip/rockchip_sip.h
@@ -20,4 +20,9 @@
 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM	0x07
 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD	0x08
 
+#define ROCKCHIP_SIP_RET_NOT_SUPPORTED		-2
+
+#define ROCKCHIP_SIP_GPIO_CONFIG		0x8200002c
+#define ROCKCHIP_SIP_GPIO_GET_GROUP		0
+
 #endif

-- 
2.34.1





More information about the Linux-rockchip mailing list