ALSA: msnd: add ISA and PnP system sleep callbacks

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>
This commit is contained in:
Cássio Gabriel 2026-04-09 02:07:46 -03:00 committed by Takashi Iwai
parent 49690509eb
commit efca489a86
2 changed files with 95 additions and 2 deletions

View 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];

View 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);