lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20251114-s2mpg10-chained-irq-v1-1-34ddfa49c4cd@linaro.org>
Date: Fri, 14 Nov 2025 14:10:59 +0000
From: André Draszik <andre.draszik@...aro.org>
To: Krzysztof Kozlowski <krzk@...nel.org>, Lee Jones <lee@...nel.org>
Cc: Peter Griffin <peter.griffin@...aro.org>, 
 Tudor Ambarus <tudor.ambarus@...aro.org>, 
 Will McVicker <willmcvicker@...gle.com>, Juan Yescas <jyescas@...gle.com>, 
 Douglas Anderson <dianders@...omium.org>, kernel-team@...roid.com, 
 linux-kernel@...r.kernel.org, linux-samsung-soc@...r.kernel.org, 
 André Draszik <andre.draszik@...aro.org>
Subject: [PATCH] mfd: sec: Use chained IRQs for s2mpg10

On S2MPG10 (and similar like S2MPG11), top-level interrupt status and
mask registers exist which need to be unmasked to get the PMIC
interrupts. This additional status doesn't seem to exist on other PMICs
in the S2MP* family, and the S2MPG10 driver is manually dealing with
masking and unmasking currently.

The correct approach here is to register this hierarchy as chained
interrupts, though, without any additional manual steps. Doing so will
also simplify addition of other, similar, PMICs (like S2MPG11) in the
future.

Update the driver to do just that.

Signed-off-by: André Draszik <andre.draszik@...aro.org>
---
This patch and
https://lore.kernel.org/all/20251114-s5m-alarm-v1-0-c9b3bebae65f@linaro.org/
that I sent earlier will conflict due to patch context.

I propose to have this one here merged first (as it should be more
straight forward and I think it's simpler and hopefully less
controversial), and then I can send a rebased version of the other
series if you agree.
---
 drivers/mfd/sec-acpm.c          | 23 +------------
 drivers/mfd/sec-irq.c           | 73 +++++++++++++++++++++++++++++++++++++++--
 include/linux/mfd/samsung/irq.h |  6 ++++
 3 files changed, 77 insertions(+), 25 deletions(-)

diff --git a/drivers/mfd/sec-acpm.c b/drivers/mfd/sec-acpm.c
index 8b31c816d65b86c54a108fa994384abfac0e7da4..36622069a7885c9b5fc74329efec34e1e4bcc106 100644
--- a/drivers/mfd/sec-acpm.c
+++ b/drivers/mfd/sec-acpm.c
@@ -325,11 +325,6 @@ static struct regmap *sec_pmic_acpm_regmap_init(struct device *dev,
 	return regmap;
 }
 
-static void sec_pmic_acpm_mask_common_irqs(void *regmap_common)
-{
-	regmap_write(regmap_common, S2MPG10_COMMON_INT_MASK, S2MPG10_COMMON_INT_SRC);
-}
-
 static int sec_pmic_acpm_probe(struct platform_device *pdev)
 {
 	struct regmap *regmap_common, *regmap_pmic, *regmap;
@@ -360,15 +355,10 @@ static int sec_pmic_acpm_probe(struct platform_device *pdev)
 	shared_ctx->speedy_channel = pdata->speedy_channel;
 
 	regmap_common = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_COMMON,
-						  pdata->regmap_cfg_common, false);
+						  pdata->regmap_cfg_common, true);
 	if (IS_ERR(regmap_common))
 		return PTR_ERR(regmap_common);
 
-	/* Mask all interrupts from 'common' block, until successful init */
-	ret = regmap_write(regmap_common, S2MPG10_COMMON_INT_MASK, S2MPG10_COMMON_INT_SRC);
-	if (ret)
-		return dev_err_probe(dev, ret, "failed to mask common block interrupts\n");
-
 	regmap_pmic = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_PMIC,
 						pdata->regmap_cfg_pmic, false);
 	if (IS_ERR(regmap_pmic))
@@ -391,17 +381,6 @@ static int sec_pmic_acpm_probe(struct platform_device *pdev)
 	if (device_property_read_bool(dev, "wakeup-source"))
 		devm_device_init_wakeup(dev);
 
-	/* Unmask PMIC interrupt from 'common' block, now that everything is in place. */
-	ret = regmap_clear_bits(regmap_common, S2MPG10_COMMON_INT_MASK,
-				S2MPG10_COMMON_INT_SRC_PMIC);
-	if (ret)
-		return dev_err_probe(dev, ret, "failed to unmask PMIC interrupt\n");
-
-	/* Mask all interrupts from 'common' block on shutdown */
-	ret = devm_add_action_or_reset(dev, sec_pmic_acpm_mask_common_irqs, regmap_common);
-	if (ret)
-		return ret;
-
 	return 0;
 }
 
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index c5c80b1ba104e6c5a55b442d2f10a8554201a961..d992e41e716dcdc060421e1db8475523842a12be 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -20,6 +20,12 @@
 #include "sec-core.h"
 
 static const struct regmap_irq s2mpg10_irqs[] = {
+	REGMAP_IRQ_REG(S2MPG10_COMMON_IRQ_PMIC, 0, S2MPG10_COMMON_INT_SRC_PMIC),
+	/* No documentation or other reference for remaining bits */
+	REGMAP_IRQ_REG(S2MPG10_COMMON_IRQ_UNUSED, 0, GENMASK(7, 1)),
+};
+
+static const struct regmap_irq s2mpg10_pmic_irqs[] = {
 	REGMAP_IRQ_REG(S2MPG10_IRQ_PWRONF, 0, S2MPG10_IRQ_PWRONF_MASK),
 	REGMAP_IRQ_REG(S2MPG10_IRQ_PWRONR, 0, S2MPG10_IRQ_PWRONR_MASK),
 	REGMAP_IRQ_REG(S2MPG10_IRQ_JIGONBF, 0, S2MPG10_IRQ_JIGONBF_MASK),
@@ -183,11 +189,20 @@ static const struct regmap_irq s5m8767_irqs[] = {
 /* All S2MPG10 interrupt sources are read-only and don't require clearing */
 static const struct regmap_irq_chip s2mpg10_irq_chip = {
 	.name = "s2mpg10",
+	.status_base = S2MPG10_COMMON_INT,
+	.mask_base = S2MPG10_COMMON_INT_MASK,
+	.num_regs = 1,
 	.irqs = s2mpg10_irqs,
 	.num_irqs = ARRAY_SIZE(s2mpg10_irqs),
-	.num_regs = 6,
+};
+
+static const struct regmap_irq_chip s2mpg10_irq_chip_pmic = {
+	.name = "s2mpg10-pmic",
 	.status_base = S2MPG10_PMIC_INT1,
 	.mask_base = S2MPG10_PMIC_INT1M,
+	.num_regs = 6,
+	.irqs = s2mpg10_pmic_irqs,
+	.num_irqs = ARRAY_SIZE(s2mpg10_pmic_irqs),
 };
 
 static const struct regmap_irq_chip s2mps11_irq_chip = {
@@ -253,6 +268,59 @@ static const struct regmap_irq_chip s5m8767_irq_chip = {
 	.ack_base = S5M8767_REG_INT1,
 };
 
+static int s2mpg1x_add_chained_irq_chip(struct device *dev, struct regmap *regmap, int pirq,
+					struct regmap_irq_chip_data *parent,
+					const struct regmap_irq_chip *chip,
+					struct regmap_irq_chip_data **data)
+{
+	int irq, ret;
+
+	irq = regmap_irq_get_virq(parent, pirq);
+	if (irq < 0)
+		return dev_err_probe(dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", pirq,
+				     chip->name);
+
+	ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT | IRQF_SHARED, 0, chip, data);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add %s IRQ chip\n", chip->name);
+
+	return 0;
+}
+
+static int sec_irq_init_s2mpg1x(struct sec_pmic_dev *sec_pmic)
+{
+	const struct regmap_irq_chip *irq_chip, *chained_irq_chip;
+	struct regmap_irq_chip_data *irq_data;
+	struct regmap *regmap_common;
+	int chained_pirq;
+	int ret;
+
+	switch (sec_pmic->device_type) {
+	case S2MPG10:
+		irq_chip = &s2mpg10_irq_chip;
+		chained_irq_chip = &s2mpg10_irq_chip_pmic;
+		chained_pirq = S2MPG10_COMMON_IRQ_PMIC;
+		break;
+	default:
+		return dev_err_probe(sec_pmic->dev, -EINVAL, "Unsupported device type %d\n",
+				     sec_pmic->device_type);
+	};
+
+	regmap_common = dev_get_regmap(sec_pmic->dev, "common");
+	if (!regmap_common)
+		return dev_err_probe(sec_pmic->dev, -EINVAL, "No 'common' regmap %d\n",
+				     sec_pmic->device_type);
+
+	ret = devm_regmap_add_irq_chip(sec_pmic->dev, regmap_common, sec_pmic->irq, IRQF_ONESHOT, 0,
+				       irq_chip, &irq_data);
+	if (ret)
+		return dev_err_probe(sec_pmic->dev, ret, "Failed to add %s IRQ chip\n",
+				     irq_chip->name);
+
+	return s2mpg1x_add_chained_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic, chained_pirq,
+					    irq_data, chained_irq_chip, &sec_pmic->irq_data);
+}
+
 int sec_irq_init(struct sec_pmic_dev *sec_pmic)
 {
 	const struct regmap_irq_chip *sec_irq_chip;
@@ -268,8 +336,7 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
 		sec_irq_chip = &s2mps14_irq_chip;
 		break;
 	case S2MPG10:
-		sec_irq_chip = &s2mpg10_irq_chip;
-		break;
+		return sec_irq_init_s2mpg1x(sec_pmic);
 	case S2MPS11X:
 		sec_irq_chip = &s2mps11_irq_chip;
 		break;
diff --git a/include/linux/mfd/samsung/irq.h b/include/linux/mfd/samsung/irq.h
index b4805cbd949bd605004bd88cf361109d1cbbc3bf..8402a5f8e18ab62b4bec89541d785442674adee0 100644
--- a/include/linux/mfd/samsung/irq.h
+++ b/include/linux/mfd/samsung/irq.h
@@ -57,6 +57,12 @@ enum s2mpa01_irq {
 #define S2MPA01_IRQ_B24_TSD_MASK	(1 << 4)
 #define S2MPA01_IRQ_B35_TSD_MASK	(1 << 5)
 
+enum s2mpg10_common_irq {
+	/* Top-level (common) block */
+	S2MPG10_COMMON_IRQ_PMIC,
+	S2MPG10_COMMON_IRQ_UNUSED,
+};
+
 enum s2mpg10_irq {
 	/* PMIC */
 	S2MPG10_IRQ_PWRONF,

---
base-commit: b179ce312bafcb8c68dc718e015aee79b7939ff0
change-id: 20251114-s2mpg10-chained-irq-5c0956ef0a21

Best regards,
-- 
André Draszik <andre.draszik@...aro.org>


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ