From: "Cássio Gabriel" <cassiogabrielcontato@gmail.com>
To: Takashi Iwai <tiwai@suse.com>, Jaroslav Kysela <perex@perex.cz>
Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org,
"Cássio Gabriel" <cassiogabrielcontato@gmail.com>
Subject: [PATCH v2 3/3] ALSA: interwave: add ISA and PnP suspend and resume callbacks
Date: Tue, 07 Apr 2026 12:35:43 -0300 [thread overview]
Message-ID: <20260407-alsa-interwave-pm-v2-3-8dd96c6129e9@gmail.com> (raw)
In-Reply-To: <20260407-alsa-interwave-pm-v2-0-8dd96c6129e9@gmail.com>
interwave still leaves both its ISA and PnP PM callbacks disabled even
though the shared GUS suspend and resume path now exists.
This board needs InterWave-specific glue around the shared GUS PM path.
The attached WSS codec has its own register image that must be saved and
restored across suspend, the InterWave-specific GF1 compatibility,
decode, MPU401, and emulation settings must be rewritten after the
shared GF1 resume path reinitializes the chip, and the probe-detected
InterWave memory layout must be restored without rerunning the
destructive DRAM/ROM detection path.
Track the optional STB TEA6330T bus at probe time, restore its cached
mixer state after resume, add resume-safe helpers for the InterWave
register and memory-configuration state, and wire both the ISA and PnP
front-ends up to the shared GUS PM helpers.
The resume path intentionally restores only the cached hardware setup.
It does not attempt to preserve sample RAM contents across suspend.
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
---
sound/isa/gus/interwave.c | 178 +++++++++++++++++++++++++++++++++++++++-------
1 file changed, 151 insertions(+), 27 deletions(-)
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 18adcd35e117..616c11e51a2f 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -96,6 +96,7 @@ struct snd_interwave {
struct snd_gus_card *gus;
struct snd_wss *wss;
#ifdef SNDRV_STB
+ struct snd_i2c_bus *i2c_bus;
struct resource *i2c_res;
#endif
unsigned short gus_status_reg;
@@ -363,18 +364,30 @@ struct rom_hdr {
/* 511 */ unsigned char csum;
};
-static void snd_interwave_detect_memory(struct snd_gus_card *gus)
+static const unsigned int snd_interwave_memory_configs[] = {
+ 0x00000001, 0x00000101, 0x01010101, 0x00000401,
+ 0x04040401, 0x00040101, 0x04040101, 0x00000004,
+ 0x00000404, 0x04040404, 0x00000010, 0x00001010,
+ 0x10101010
+};
+
+static int snd_interwave_find_memory_config(unsigned int lmct)
{
- static const unsigned int lmc[13] =
- {
- 0x00000001, 0x00000101, 0x01010101, 0x00000401,
- 0x04040401, 0x00040101, 0x04040101, 0x00000004,
- 0x00000404, 0x04040404, 0x00000010, 0x00001010,
- 0x10101010
- };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(snd_interwave_memory_configs); i++) {
+ if (lmct == snd_interwave_memory_configs[i])
+ return i;
+ }
+
+ return -EINVAL;
+}
+static void snd_interwave_detect_memory(struct snd_gus_card *gus)
+{
int bank_pos, pages;
unsigned int i, lmct;
+ int lmc_cfg;
int psizes[4];
unsigned char iwave[8];
unsigned char csum;
@@ -399,17 +412,20 @@ static void snd_interwave_detect_memory(struct snd_gus_card *gus)
#if 0
dev_dbg(gus->card->dev, "lmct = 0x%08x\n", lmct);
#endif
- for (i = 0; i < ARRAY_SIZE(lmc); i++)
- if (lmct == lmc[i]) {
+ lmc_cfg = snd_interwave_find_memory_config(lmct);
+ if (lmc_cfg >= 0) {
#if 0
- dev_dbg(gus->card->dev, "found !!! %i\n", i);
+ dev_dbg(gus->card->dev, "found !!! %i\n", lmc_cfg);
#endif
- snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | i);
- snd_interwave_bank_sizes(gus, psizes);
- break;
- }
- if (i >= ARRAY_SIZE(lmc) && !gus->gf1.enh_mode)
- snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | 2);
+ snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG,
+ (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) |
+ lmc_cfg);
+ snd_interwave_bank_sizes(gus, psizes);
+ } else if (!gus->gf1.enh_mode) {
+ snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG,
+ (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) |
+ 2);
+ }
for (i = 0; i < 4; i++) {
gus->gf1.mem_alloc.banks_8[i].address =
gus->gf1.mem_alloc.banks_16[i].address = i << 22;
@@ -454,24 +470,66 @@ static void snd_interwave_detect_memory(struct snd_gus_card *gus)
snd_interwave_reset(gus);
}
+static void __snd_interwave_restore_regs(struct snd_gus_card *gus)
+{
+ snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30);
+ snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00);
+}
+
+static void snd_interwave_restore_regs(struct snd_gus_card *gus)
+{
+ scoped_guard(spinlock_irqsave, &gus->reg_lock)
+ __snd_interwave_restore_regs(gus);
+}
+
+static void snd_interwave_restore_memory(struct snd_gus_card *gus)
+{
+ unsigned short mem_cfg;
+ unsigned int lmct = 0;
+ int i, lmc_cfg;
+
+ if (!gus->gf1.memory)
+ return;
+
+ for (i = 0; i < 4; i++)
+ lmct |= (gus->gf1.mem_alloc.banks_16[i].size >> 18) << (i * 8);
+
+ lmc_cfg = snd_interwave_find_memory_config(lmct);
+ if (lmc_cfg < 0) {
+ if (!gus->gf1.enh_mode) {
+ lmc_cfg = 2;
+ } else {
+ dev_warn(gus->card->dev,
+ "cannot restore InterWave memory layout 0x%08x\n",
+ lmct);
+ return;
+ }
+ }
+
+ scoped_guard(spinlock_irqsave, &gus->reg_lock) {
+ mem_cfg = snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG);
+ mem_cfg = (mem_cfg & 0xfff0) | lmc_cfg;
+ mem_cfg = (mem_cfg & 0xff1f) | (4 << 5);
+ snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, mem_cfg);
+ }
+}
+
static void snd_interwave_init(int dev, struct snd_gus_card *gus)
{
- /* ok.. some InterWave specific initialization */
+ /* Probe-time setup also clears the timer control register. */
scoped_guard(spinlock_irqsave, &gus->reg_lock) {
snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0x00);
- snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f);
- snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49);
- snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11);
- snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00);
- snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30);
- snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00);
+ __snd_interwave_restore_regs(gus);
}
gus->equal_irq = 1;
gus->codec_flag = 1;
gus->interwave = 1;
gus->max_flag = 1;
gus->joystick_dac = joystick_dac[dev];
-
}
static const struct snd_kcontrol_new snd_interwave_controls[] = {
@@ -724,6 +782,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev,
err = snd_tea6330t_update_mixer(card, i2c_bus, 0, 1);
if (err < 0)
return err;
+ iwcard->i2c_bus = i2c_bus;
}
#endif
@@ -828,10 +887,59 @@ static int snd_interwave_isa_probe(struct device *pdev,
return 0;
}
+#ifdef CONFIG_PM
+static int snd_interwave_card_suspend(struct snd_card *card)
+{
+ struct snd_interwave *iwcard = card->private_data;
+
+ iwcard->wss->suspend(iwcard->wss);
+ return snd_gus_suspend(iwcard->gus);
+}
+
+static int snd_interwave_card_resume(struct snd_card *card)
+{
+ struct snd_interwave *iwcard = card->private_data;
+ int err;
+
+ err = snd_gus_resume(iwcard->gus);
+ if (err < 0)
+ return err;
+
+ snd_interwave_restore_regs(iwcard->gus);
+ snd_interwave_restore_memory(iwcard->gus);
+ iwcard->wss->resume(iwcard->wss);
+#ifdef SNDRV_STB
+ if (iwcard->i2c_bus) {
+ err = snd_tea6330t_restore_mixer(iwcard->i2c_bus);
+ if (err < 0)
+ dev_warn(card->dev,
+ "failed to restore TEA6330T mixer state: %d\n",
+ err);
+ }
+#endif
+
+ return 0;
+}
+
+static int snd_interwave_isa_suspend(struct device *pdev, unsigned int dev,
+ pm_message_t state)
+{
+ return snd_interwave_card_suspend(dev_get_drvdata(pdev));
+}
+
+static int snd_interwave_isa_resume(struct device *pdev, unsigned int dev)
+{
+ return snd_interwave_card_resume(dev_get_drvdata(pdev));
+}
+#endif
+
static struct isa_driver snd_interwave_driver = {
.match = snd_interwave_isa_match,
.probe = snd_interwave_isa_probe,
- /* FIXME: suspend,resume */
+#ifdef CONFIG_PM
+ .suspend = snd_interwave_isa_suspend,
+ .resume = snd_interwave_isa_resume,
+#endif
.driver = {
.name = INTERWAVE_DRIVER
},
@@ -871,12 +979,28 @@ static int snd_interwave_pnp_detect(struct pnp_card_link *pcard,
return 0;
}
+#ifdef CONFIG_PM
+static int snd_interwave_pnpc_suspend(struct pnp_card_link *pcard,
+ pm_message_t state)
+{
+ return snd_interwave_card_suspend(pnp_get_card_drvdata(pcard));
+}
+
+static int snd_interwave_pnpc_resume(struct pnp_card_link *pcard)
+{
+ return snd_interwave_card_resume(pnp_get_card_drvdata(pcard));
+}
+#endif
+
static struct pnp_card_driver interwave_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = INTERWAVE_PNP_DRIVER,
.id_table = snd_interwave_pnpids,
.probe = snd_interwave_pnp_detect,
- /* FIXME: suspend,resume */
+#ifdef CONFIG_PM
+ .suspend = snd_interwave_pnpc_suspend,
+ .resume = snd_interwave_pnpc_resume,
+#endif
};
#endif /* CONFIG_PNP */
--
2.53.0
next prev parent reply other threads:[~2026-04-07 15:36 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-07 15:35 [PATCH v2 0/3] ALSA: add suspend/resume support for InterWave ISA cards Cássio Gabriel
2026-04-07 15:35 ` [PATCH v2 1/3] ALSA: tea6330t: move snd_tea6330t_detect() EXPORT_SYMBOL Cássio Gabriel
2026-04-07 15:35 ` [PATCH v2 2/3] ALSA: tea6330t: add mixer state restore helper Cássio Gabriel
2026-04-07 15:35 ` Cássio Gabriel [this message]
2026-04-08 8:51 ` [PATCH v2 0/3] ALSA: add suspend/resume support for InterWave ISA cards Takashi Iwai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260407-alsa-interwave-pm-v2-3-8dd96c6129e9@gmail.com \
--to=cassiogabrielcontato@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=perex@perex.cz \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.