]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ALSA: msnd: add ISA and PnP system sleep callbacks
authorCássio Gabriel <cassiogabrielcontato@gmail.com>
Thu, 9 Apr 2026 05:07:46 +0000 (02:07 -0300)
committerTakashi Iwai <tiwai@suse.de>
Thu, 9 Apr 2026 10:02:39 +0000 (12:02 +0200)
The msnd drivers do not implement system sleep callbacks today, so
they have no defined way to recover DSP state after suspend.

Add common card suspend/resume helpers, rerun the DSP
initialization path on resume, restore the cached capture-source
state, and rearm the shared IRQ for already-open users.

Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260409-msnd-pm-support-v1-2-2abef720d0e7@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/isa/msnd/msnd.h
sound/isa/msnd/msnd_pinnacle.c

index b25beca25c0ddaedda0ca911b8e70bd912e87f52..56a700e6a5cbf52781c5b883631317257c02f668 100644 (file)
@@ -253,6 +253,8 @@ struct snd_msnd {
        spinlock_t mixer_lock;
        int nresets;
        unsigned recsrc;
+       u8 pm_recsrc;
+       bool pm_mpu_input;
 #define LEVEL_ENTRIES 32
        int left_levels[LEVEL_ENTRIES];
        int right_levels[LEVEL_ENTRIES];
index c4eec391cd298c3a64215be9fb46382c48f8e76f..5b729bb02ef6287a4d7d17c557cbec577761e4db 100644 (file)
@@ -513,6 +513,19 @@ static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)
        snd_msnd_disable_irq(mpu->private_data);
 }
 
+#ifdef CONFIG_PM
+static u8 snd_msnd_pm_recsrc(struct snd_msnd *chip)
+{
+       /* Convert recsrc to the Capture Source selector: 0=Analog, 1=MASS, 2=SPDIF. */
+       if (chip->recsrc & BIT(4))
+               return 1;
+       if ((chip->recsrc & BIT(17)) &&
+           test_bit(F_HAVEDIGITAL, &chip->flags))
+               return 2;
+       return 0;
+}
+#endif
+
 static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
 
@@ -1001,10 +1014,73 @@ static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int snd_msnd_card_suspend(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+       struct snd_mpu401 *mpu;
+       int err;
+
+       mpu = chip->rmidi ? chip->rmidi->private_data : NULL;
+       chip->pm_recsrc = snd_msnd_pm_recsrc(chip);
+       chip->pm_mpu_input = mpu && test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode);
+       if (chip->pm_mpu_input)
+               snd_msnd_send_dsp_cmd(chip, HDEX_MIDI_IN_STOP);
+
+       err = snd_msnd_force_irq(chip, false);
+       if (err < 0) {
+               if (chip->pm_mpu_input)
+                       snd_msnd_send_dsp_cmd(chip, HDEX_MIDI_IN_START);
+               return err;
+       }
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       return 0;
+}
+
+static int snd_msnd_card_resume(struct snd_card *card)
+{
+       struct snd_msnd *chip = card->private_data;
+       int err;
+
+       err = snd_msnd_initialize(card);
+       if (err < 0)
+               return err;
+
+       snd_msnd_calibrate_adc(chip, chip->play_sample_rate);
+       snd_msndmix_force_recsrc(chip, chip->pm_recsrc);
+
+       err = snd_msnd_force_irq(chip, true);
+       if (err < 0)
+               return err;
+
+       if (chip->pm_mpu_input)
+               snd_msnd_send_dsp_cmd(chip, HDEX_MIDI_IN_START);
+
+       chip->nresets = 0;
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+
+static int snd_msnd_isa_suspend(struct device *dev, unsigned int idx,
+                               pm_message_t state)
+{
+       return snd_msnd_card_suspend(dev_get_drvdata(dev));
+}
+
+static int snd_msnd_isa_resume(struct device *dev, unsigned int idx)
+{
+       return snd_msnd_card_resume(dev_get_drvdata(dev));
+}
+#endif
+
 static struct isa_driver snd_msnd_driver = {
        .match          = snd_msnd_isa_match,
        .probe          = snd_msnd_isa_probe,
-       /* FIXME: suspend, resume */
+#ifdef CONFIG_PM
+       .suspend        = snd_msnd_isa_suspend,
+       .resume         = snd_msnd_isa_resume,
+#endif
        .driver         = {
                .name   = DEV_NAME
        },
@@ -1111,6 +1187,18 @@ static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int snd_msnd_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
+{
+       return snd_msnd_card_suspend(pnp_get_card_drvdata(pcard));
+}
+
+static int snd_msnd_pnp_resume(struct pnp_card_link *pcard)
+{
+       return snd_msnd_card_resume(pnp_get_card_drvdata(pcard));
+}
+#endif
+
 static int isa_registered;
 static int pnp_registered;
 
@@ -1127,6 +1215,10 @@ static struct pnp_card_driver msnd_pnpc_driver = {
        .name = "msnd_pinnacle",
        .id_table = msnd_pnpids,
        .probe = snd_msnd_pnp_detect,
+#ifdef CONFIG_PM
+       .suspend = snd_msnd_pnp_suspend,
+       .resume = snd_msnd_pnp_resume,
+#endif
 };
 #endif /* CONFIG_PNP */
 
@@ -1161,4 +1253,3 @@ static void __exit snd_msnd_exit(void)
 
 module_init(snd_msnd_init);
 module_exit(snd_msnd_exit);
-