Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

André Draszik and committed by
Lee Jones
ee19b52c 56c1245d

+77 -25
+1 -22
drivers/mfd/sec-acpm.c
··· 325 325 return regmap; 326 326 } 327 327 328 - static void sec_pmic_acpm_mask_common_irqs(void *regmap_common) 329 - { 330 - regmap_write(regmap_common, S2MPG10_COMMON_INT_MASK, S2MPG10_COMMON_INT_SRC); 331 - } 332 - 333 328 static int sec_pmic_acpm_probe(struct platform_device *pdev) 334 329 { 335 330 struct regmap *regmap_common, *regmap_pmic, *regmap; ··· 355 360 shared_ctx->speedy_channel = pdata->speedy_channel; 356 361 357 362 regmap_common = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_COMMON, 358 - pdata->regmap_cfg_common, false); 363 + pdata->regmap_cfg_common, true); 359 364 if (IS_ERR(regmap_common)) 360 365 return PTR_ERR(regmap_common); 361 - 362 - /* Mask all interrupts from 'common' block, until successful init */ 363 - ret = regmap_write(regmap_common, S2MPG10_COMMON_INT_MASK, S2MPG10_COMMON_INT_SRC); 364 - if (ret) 365 - return dev_err_probe(dev, ret, "failed to mask common block interrupts\n"); 366 366 367 367 regmap_pmic = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_PMIC, 368 368 pdata->regmap_cfg_pmic, false); ··· 380 390 381 391 if (device_property_read_bool(dev, "wakeup-source")) 382 392 devm_device_init_wakeup(dev); 383 - 384 - /* Unmask PMIC interrupt from 'common' block, now that everything is in place. */ 385 - ret = regmap_clear_bits(regmap_common, S2MPG10_COMMON_INT_MASK, 386 - S2MPG10_COMMON_INT_SRC_PMIC); 387 - if (ret) 388 - return dev_err_probe(dev, ret, "failed to unmask PMIC interrupt\n"); 389 - 390 - /* Mask all interrupts from 'common' block on shutdown */ 391 - ret = devm_add_action_or_reset(dev, sec_pmic_acpm_mask_common_irqs, regmap_common); 392 - if (ret) 393 - return ret; 394 393 395 394 return 0; 396 395 }
+70 -3
drivers/mfd/sec-irq.c
··· 20 20 #include "sec-core.h" 21 21 22 22 static const struct regmap_irq s2mpg10_irqs[] = { 23 + REGMAP_IRQ_REG(S2MPG10_COMMON_IRQ_PMIC, 0, S2MPG10_COMMON_INT_SRC_PMIC), 24 + /* No documentation or other reference for remaining bits */ 25 + REGMAP_IRQ_REG(S2MPG10_COMMON_IRQ_UNUSED, 0, GENMASK(7, 1)), 26 + }; 27 + 28 + static const struct regmap_irq s2mpg10_pmic_irqs[] = { 23 29 REGMAP_IRQ_REG(S2MPG10_IRQ_PWRONF, 0, S2MPG10_IRQ_PWRONF_MASK), 24 30 REGMAP_IRQ_REG(S2MPG10_IRQ_PWRONR, 0, S2MPG10_IRQ_PWRONR_MASK), 25 31 REGMAP_IRQ_REG(S2MPG10_IRQ_JIGONBF, 0, S2MPG10_IRQ_JIGONBF_MASK), ··· 189 183 /* All S2MPG10 interrupt sources are read-only and don't require clearing */ 190 184 static const struct regmap_irq_chip s2mpg10_irq_chip = { 191 185 .name = "s2mpg10", 186 + .status_base = S2MPG10_COMMON_INT, 187 + .mask_base = S2MPG10_COMMON_INT_MASK, 188 + .num_regs = 1, 192 189 .irqs = s2mpg10_irqs, 193 190 .num_irqs = ARRAY_SIZE(s2mpg10_irqs), 194 - .num_regs = 6, 191 + }; 192 + 193 + static const struct regmap_irq_chip s2mpg10_irq_chip_pmic = { 194 + .name = "s2mpg10-pmic", 195 195 .status_base = S2MPG10_PMIC_INT1, 196 196 .mask_base = S2MPG10_PMIC_INT1M, 197 + .num_regs = 6, 198 + .irqs = s2mpg10_pmic_irqs, 199 + .num_irqs = ARRAY_SIZE(s2mpg10_pmic_irqs), 197 200 }; 198 201 199 202 static const struct regmap_irq_chip s2mps11_irq_chip = { ··· 268 253 .ack_base = S5M8767_REG_INT1, 269 254 }; 270 255 256 + static int s2mpg1x_add_chained_irq_chip(struct device *dev, struct regmap *regmap, int pirq, 257 + struct regmap_irq_chip_data *parent, 258 + const struct regmap_irq_chip *chip, 259 + struct regmap_irq_chip_data **data) 260 + { 261 + int irq, ret; 262 + 263 + irq = regmap_irq_get_virq(parent, pirq); 264 + if (irq < 0) 265 + return dev_err_probe(dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", pirq, 266 + chip->name); 267 + 268 + ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT | IRQF_SHARED, 0, chip, data); 269 + if (ret) 270 + return dev_err_probe(dev, ret, "Failed to add %s IRQ chip\n", chip->name); 271 + 272 + return 0; 273 + } 274 + 275 + static int sec_irq_init_s2mpg1x(struct sec_pmic_dev *sec_pmic) 276 + { 277 + const struct regmap_irq_chip *irq_chip, *chained_irq_chip; 278 + struct regmap_irq_chip_data *irq_data; 279 + struct regmap *regmap_common; 280 + int chained_pirq; 281 + int ret; 282 + 283 + switch (sec_pmic->device_type) { 284 + case S2MPG10: 285 + irq_chip = &s2mpg10_irq_chip; 286 + chained_irq_chip = &s2mpg10_irq_chip_pmic; 287 + chained_pirq = S2MPG10_COMMON_IRQ_PMIC; 288 + break; 289 + default: 290 + return dev_err_probe(sec_pmic->dev, -EINVAL, "Unsupported device type %d\n", 291 + sec_pmic->device_type); 292 + }; 293 + 294 + regmap_common = dev_get_regmap(sec_pmic->dev, "common"); 295 + if (!regmap_common) 296 + return dev_err_probe(sec_pmic->dev, -EINVAL, "No 'common' regmap %d\n", 297 + sec_pmic->device_type); 298 + 299 + ret = devm_regmap_add_irq_chip(sec_pmic->dev, regmap_common, sec_pmic->irq, IRQF_ONESHOT, 0, 300 + irq_chip, &irq_data); 301 + if (ret) 302 + return dev_err_probe(sec_pmic->dev, ret, "Failed to add %s IRQ chip\n", 303 + irq_chip->name); 304 + 305 + return s2mpg1x_add_chained_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic, chained_pirq, 306 + irq_data, chained_irq_chip, &sec_pmic->irq_data); 307 + } 308 + 271 309 int sec_irq_init(struct sec_pmic_dev *sec_pmic) 272 310 { 273 311 const struct regmap_irq_chip *sec_irq_chip; ··· 336 268 sec_irq_chip = &s2mps14_irq_chip; 337 269 break; 338 270 case S2MPG10: 339 - sec_irq_chip = &s2mpg10_irq_chip; 340 - break; 271 + return sec_irq_init_s2mpg1x(sec_pmic); 341 272 case S2MPS11X: 342 273 sec_irq_chip = &s2mps11_irq_chip; 343 274 break;
+6
include/linux/mfd/samsung/irq.h
··· 57 57 #define S2MPA01_IRQ_B24_TSD_MASK (1 << 4) 58 58 #define S2MPA01_IRQ_B35_TSD_MASK (1 << 5) 59 59 60 + enum s2mpg10_common_irq { 61 + /* Top-level (common) block */ 62 + S2MPG10_COMMON_IRQ_PMIC, 63 + S2MPG10_COMMON_IRQ_UNUSED, 64 + }; 65 + 60 66 enum s2mpg10_irq { 61 67 /* PMIC */ 62 68 S2MPG10_IRQ_PWRONF,