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

Configure Feed

Select the types of activity you want to include in your feed.

mfd: cs42l43: Disable IRQs during suspend

The ASoC CODEC driver masks the IRQs whilst entering and exiting
system suspend to avoid issues where the IRQ handler can run but PM
runtime is disabled. However, as the IRQs could also be used from
other parts of the driver, it would be better to move this handling to
the MFD level.

Remove the handling from the ASoC driver and move it to the MFD
driver. Whilst moving also ensure the IRQs are all masked at the device
level before powering down the device, as per hardware recommendations.

Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Acked-by: Mark Brown <broonie@kernel.org.>
Link: https://lore.kernel.org/r/20241014095202.828194-1-ckeepax@opensource.cirrus.com
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Charles Keepax and committed by
Lee Jones
2bb0106d a0f8a889

+54 -50
+54 -8
drivers/mfd/cs42l43.c
··· 1109 1109 static int cs42l43_suspend(struct device *dev) 1110 1110 { 1111 1111 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); 1112 + static const struct reg_sequence mask_all[] = { 1113 + { CS42L43_DECIM_MASK, 0xFFFFFFFF, }, 1114 + { CS42L43_EQ_MIX_MASK, 0xFFFFFFFF, }, 1115 + { CS42L43_ASP_MASK, 0xFFFFFFFF, }, 1116 + { CS42L43_PLL_MASK, 0xFFFFFFFF, }, 1117 + { CS42L43_SOFT_MASK, 0xFFFFFFFF, }, 1118 + { CS42L43_SWIRE_MASK, 0xFFFFFFFF, }, 1119 + { CS42L43_MSM_MASK, 0xFFFFFFFF, }, 1120 + { CS42L43_ACC_DET_MASK, 0xFFFFFFFF, }, 1121 + { CS42L43_I2C_TGT_MASK, 0xFFFFFFFF, }, 1122 + { CS42L43_SPI_MSTR_MASK, 0xFFFFFFFF, }, 1123 + { CS42L43_SW_TO_SPI_BRIDGE_MASK, 0xFFFFFFFF, }, 1124 + { CS42L43_OTP_MASK, 0xFFFFFFFF, }, 1125 + { CS42L43_CLASS_D_AMP_MASK, 0xFFFFFFFF, }, 1126 + { CS42L43_GPIO_INT_MASK, 0xFFFFFFFF, }, 1127 + { CS42L43_ASRC_MASK, 0xFFFFFFFF, }, 1128 + { CS42L43_HPOUT_MASK, 0xFFFFFFFF, }, 1129 + }; 1112 1130 int ret; 1113 1131 1114 - /* 1115 - * Don't care about being resumed here, but the driver does want 1116 - * force_resume to always trigger an actual resume, so that register 1117 - * state for the MCU/GPIOs is returned as soon as possible after system 1118 - * resume. force_resume will resume if the reference count is resumed on 1119 - * suspend hence the get_noresume. 1120 - */ 1121 - pm_runtime_get_noresume(dev); 1132 + ret = pm_runtime_resume_and_get(dev); 1133 + if (ret) { 1134 + dev_err(cs42l43->dev, "Failed to resume for suspend: %d\n", ret); 1135 + return ret; 1136 + } 1137 + 1138 + /* The IRQs will be re-enabled on resume by the cache sync */ 1139 + ret = regmap_multi_reg_write_bypassed(cs42l43->regmap, 1140 + mask_all, ARRAY_SIZE(mask_all)); 1141 + if (ret) { 1142 + dev_err(cs42l43->dev, "Failed to mask IRQs: %d\n", ret); 1143 + return ret; 1144 + } 1122 1145 1123 1146 ret = pm_runtime_force_suspend(dev); 1124 1147 if (ret) { ··· 1156 1133 if (ret) 1157 1134 return ret; 1158 1135 1136 + disable_irq(cs42l43->irq); 1137 + 1138 + return 0; 1139 + } 1140 + 1141 + static int cs42l43_suspend_noirq(struct device *dev) 1142 + { 1143 + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); 1144 + 1145 + enable_irq(cs42l43->irq); 1146 + 1147 + return 0; 1148 + } 1149 + 1150 + static int cs42l43_resume_noirq(struct device *dev) 1151 + { 1152 + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); 1153 + 1154 + disable_irq(cs42l43->irq); 1155 + 1159 1156 return 0; 1160 1157 } 1161 1158 ··· 1187 1144 ret = cs42l43_power_up(cs42l43); 1188 1145 if (ret) 1189 1146 return ret; 1147 + 1148 + enable_irq(cs42l43->irq); 1190 1149 1191 1150 ret = pm_runtime_force_resume(dev); 1192 1151 if (ret) { ··· 1257 1212 1258 1213 EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = { 1259 1214 SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume) 1215 + NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend_noirq, cs42l43_resume_noirq) 1260 1216 RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL) 1261 1217 }; 1262 1218
-42
sound/soc/codecs/cs42l43.c
··· 2402 2402 return 0; 2403 2403 } 2404 2404 2405 - static int cs42l43_codec_suspend(struct device *dev) 2406 - { 2407 - struct cs42l43_codec *priv = dev_get_drvdata(dev); 2408 - struct cs42l43 *cs42l43 = priv->core; 2409 - 2410 - disable_irq(cs42l43->irq); 2411 - 2412 - return 0; 2413 - } 2414 - 2415 - static int cs42l43_codec_suspend_noirq(struct device *dev) 2416 - { 2417 - struct cs42l43_codec *priv = dev_get_drvdata(dev); 2418 - struct cs42l43 *cs42l43 = priv->core; 2419 - 2420 - enable_irq(cs42l43->irq); 2421 - 2422 - return 0; 2423 - } 2424 - 2425 - static int cs42l43_codec_resume(struct device *dev) 2426 - { 2427 - struct cs42l43_codec *priv = dev_get_drvdata(dev); 2428 - struct cs42l43 *cs42l43 = priv->core; 2429 - 2430 - enable_irq(cs42l43->irq); 2431 - 2432 - return 0; 2433 - } 2434 - 2435 - static int cs42l43_codec_resume_noirq(struct device *dev) 2436 - { 2437 - struct cs42l43_codec *priv = dev_get_drvdata(dev); 2438 - struct cs42l43 *cs42l43 = priv->core; 2439 - 2440 - disable_irq(cs42l43->irq); 2441 - 2442 - return 0; 2443 - } 2444 - 2445 2405 static const struct dev_pm_ops cs42l43_codec_pm_ops = { 2446 - SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume) 2447 - NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend_noirq, cs42l43_codec_resume_noirq) 2448 2406 RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL) 2449 2407 }; 2450 2408