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@linaro.org>
Link: https://patch.msgid.link/20251114-s2mpg10-chained-irq-v1-1-34ddfa49c4cd@linaro.org
Signed-off-by: Lee Jones <lee@kernel.org>
This commit is contained in:
André Draszik 2025-11-14 14:10:59 +00:00 committed by Lee Jones
parent 56c1245d51
commit ee19b52c31
3 changed files with 77 additions and 25 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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,