ALSA: emu10k1: make E-MU dock monitoring interrupt-driven
authorOswald Buddenhagen <oswald.buddenhagen@gmx.de>
Mon, 10 Jul 2023 06:59:55 +0000 (08:59 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 10 Jul 2023 14:56:59 +0000 (16:56 +0200)
... instead of using a one-second polling timer.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Link: https://lore.kernel.org/r/20230710065956.1246364-1-oswald.buddenhagen@gmx.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/sound/emu10k1.h
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/io.c
sound/pci/emu10k1/irq.c

index 386a5f3..43c0979 100644 (file)
@@ -1678,8 +1678,7 @@ struct snd_emu1010 {
        unsigned int clock_fallback;
        unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
        unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
-       struct delayed_work firmware_work;
-       u32 last_reg;
+       struct work_struct firmware_work;
 };
 
 struct snd_emu10k1 {
@@ -1761,6 +1760,7 @@ struct snd_emu10k1 {
        void (*capture_efx_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
        void (*spdif_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
        void (*dsp_interrupt)(struct snd_emu10k1 *emu);
+       void (*gpio_interrupt)(struct snd_emu10k1 *emu);
        void (*p16v_interrupt)(struct snd_emu10k1 *emu);
 
        struct snd_pcm_substream *pcm_capture_substream;
index 23adace..1a13c08 100644 (file)
@@ -176,9 +176,6 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
        if (err < 0)
                return err;
 
-       if (emu->card_capabilities->emu_model)
-               schedule_delayed_work(&emu->emu1010.firmware_work, 0);
-
        pci_set_drvdata(pci, card);
        dev++;
        return 0;
@@ -194,7 +191,7 @@ static int snd_emu10k1_suspend(struct device *dev)
 
        emu->suspend = 1;
 
-       cancel_delayed_work_sync(&emu->emu1010.firmware_work);
+       cancel_work_sync(&emu->emu1010.firmware_work);
 
        snd_ac97_suspend(emu->ac97);
 
@@ -224,9 +221,6 @@ static int snd_emu10k1_resume(struct device *dev)
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
-       if (emu->card_capabilities->emu_model)
-               schedule_delayed_work(&emu->emu1010.firmware_work, 0);
-
        return 0;
 }
 
index 58ed72d..661164d 100644 (file)
@@ -391,7 +391,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
        }
 #endif
 
-       snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
+       if (emu->card_capabilities->emu_model)
+               snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE | INTE_A_GPIOENABLE);
+       else
+               snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
 }
 
 int snd_emu10k1_done(struct snd_emu10k1 *emu)
@@ -745,14 +748,13 @@ static void emu1010_firmware_work(struct work_struct *work)
        int err;
 
        emu = container_of(work, struct snd_emu10k1,
-                          emu1010.firmware_work.work);
+                          emu1010.firmware_work);
        if (emu->card->shutdown)
                return;
 #ifdef CONFIG_PM_SLEEP
        if (emu->suspend)
                return;
 #endif
-       snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */
        snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
        if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
                /* Audio Dock attached */
@@ -763,13 +765,8 @@ static void emu1010_firmware_work(struct work_struct *work)
                                       EMU_HANA_FPGA_CONFIG_AUDIODOCK);
                err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
                if (err < 0)
-                       goto next;
-
+                       return;
                snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
-               snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp);
-               dev_info(emu->card->dev,
-                        "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", tmp);
-               /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
                snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
                dev_info(emu->card->dev,
                         "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
@@ -778,7 +775,7 @@ static void emu1010_firmware_work(struct work_struct *work)
                        dev_info(emu->card->dev,
                                 "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
                                 tmp);
-                       goto next;
+                       return;
                }
                dev_info(emu->card->dev,
                         "emu1010: Audio Dock Firmware loaded\n");
@@ -790,18 +787,22 @@ static void emu1010_firmware_work(struct work_struct *work)
                msleep(10);
                /* Unmute all. Default is muted after a firmware load */
                snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
-       } else if (!reg && emu->emu1010.last_reg) {
+       }
+}
+
+static void emu1010_interrupt(struct snd_emu10k1 *emu)
+{
+       u32 sts;
+
+       snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
+       if (sts & EMU_HANA_IRQ_DOCK_LOST) {
                /* Audio Dock removed */
                dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
                /* The hardware auto-mutes all, so we unmute again */
                snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
+       } else if (sts & EMU_HANA_IRQ_DOCK) {
+               schedule_work(&emu->emu1010.firmware_work);
        }
-
- next:
-       emu->emu1010.last_reg = reg;
-       if (!emu->card->shutdown)
-               schedule_delayed_work(&emu->emu1010.firmware_work,
-                                     msecs_to_jiffies(1000));
 }
 
 /*
@@ -870,6 +871,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
 
        snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
        dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
+       if (reg & EMU_HANA_OPTION_DOCK_OFFLINE)
+               schedule_work(&emu->emu1010.firmware_work);
        if (emu->card_capabilities->no_adat) {
                emu->emu1010.optical_in = 0; /* IN_SPDIF */
                emu->emu1010.optical_out = 0; /* OUT_SPDIF */
@@ -895,10 +898,12 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
        /* MIDI routing */
        snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, EMU_HANA_MIDI_INA_FROM_HAMOA | EMU_HANA_MIDI_INB_FROM_DOCK2);
        snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, EMU_HANA_MIDI_OUT_DOCK2 | EMU_HANA_MIDI_OUT_SYNC2);
-       /* IRQ Enable: All on */
-       /* snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x0f); */
-       /* IRQ Enable: All off */
-       snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);
+
+       emu->gpio_interrupt = emu1010_interrupt;
+       // Note: The Audigy INTE is set later
+       snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE,
+                              EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST);
+       snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg);  // Clear pending IRQs
 
        emu->emu1010.clock_source = 1;  /* 48000 */
        emu->emu1010.clock_fallback = 1;  /* 48000 */
@@ -938,7 +943,7 @@ static void snd_emu10k1_free(struct snd_card *card)
                /* Disable 48Volt power to Audio Dock */
                snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
        }
-       cancel_delayed_work_sync(&emu->emu1010.firmware_work);
+       cancel_work_sync(&emu->emu1010.firmware_work);
        release_firmware(emu->firmware);
        release_firmware(emu->dock_fw);
        snd_util_memhdr_free(emu->memhdr);
@@ -1517,7 +1522,7 @@ int snd_emu10k1_create(struct snd_card *card,
        emu->irq = -1;
        emu->synth = NULL;
        emu->get_synth_voice = NULL;
-       INIT_DELAYED_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
+       INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
        /* read revision & serial */
        emu->revision = pci->revision;
        pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
index a0d66ce..c695cb8 100644 (file)
@@ -302,6 +302,8 @@ static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *
 {
        // The higest input pin is used as the designated interrupt trigger,
        // so it needs to be masked out.
+       // But note that any other input pin change will also cause an IRQ,
+       // so using this function often causes an IRQ as a side effect.
        u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f;
        if (snd_BUG_ON(reg > 0x3f))
                return;
index a813ef8..8573248 100644 (file)
@@ -149,6 +149,13 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
                                outl(0, emu->port + INTE2);
                        status &= ~IPR_P16V;
                }
+               if (status & IPR_A_GPIO) {
+                       if (emu->gpio_interrupt)
+                               emu->gpio_interrupt(emu);
+                       else
+                               snd_emu10k1_intr_disable(emu, INTE_A_GPIOENABLE);
+                       status &= ~IPR_A_GPIO;
+               }
 
                if (status) {
                        dev_err(emu->card->dev,