arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / sound / pci / emu10k1 / irq.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4  *                   Creative Labs, Inc.
5  *  Routines for IRQ control of EMU10K1 chips
6  */
7
8 #include <linux/time.h>
9 #include <sound/core.h>
10 #include <sound/emu10k1.h>
11
12 irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
13 {
14         struct snd_emu10k1 *emu = dev_id;
15         unsigned int status, orig_status;
16         int handled = 0;
17         int timeout = 0;
18
19         while ((status = inl(emu->port + IPR)) != 0) {
20                 handled = 1;
21                 if ((status & 0xffffffff) == 0xffffffff) {
22                         dev_info(emu->card->dev,
23                                  "Suspected sound card removal\n");
24                         break;
25                 }
26                 if (++timeout == 1000) {
27                         dev_info(emu->card->dev, "emu10k1 irq routine failure\n");
28                         break;
29                 }
30                 orig_status = status;
31                 if (status & IPR_PCIERROR) {
32                         dev_err(emu->card->dev, "interrupt: PCI error\n");
33                         snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
34                         status &= ~IPR_PCIERROR;
35                 }
36                 if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) {
37                         if (emu->hwvol_interrupt)
38                                 emu->hwvol_interrupt(emu, status);
39                         else
40                                 snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE);
41                         status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE);
42                 }
43                 if (status & IPR_CHANNELLOOP) {
44                         struct snd_emu10k1_voice *pvoice;
45                         int voice;
46                         int voice_max = status & IPR_CHANNELNUMBERMASK;
47                         u32 val;
48
49                         val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
50                         pvoice = emu->voices;
51                         for (voice = 0; voice <= voice_max; voice++) {
52                                 if (voice == 0x20)
53                                         val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
54                                 if (val & 1) {
55                                         if (pvoice->use && pvoice->interrupt != NULL) {
56                                                 pvoice->interrupt(emu, pvoice);
57                                                 snd_emu10k1_voice_intr_ack(emu, voice);
58                                         } else {
59                                                 snd_emu10k1_voice_intr_disable(emu, voice);
60                                         }
61                                 }
62                                 val >>= 1;
63                                 pvoice++;
64                         }
65                         val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
66                         pvoice = emu->voices;
67                         for (voice = 0; voice <= voice_max; voice++) {
68                                 if (voice == 0x20)
69                                         val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
70                                 if (val & 1) {
71                                         if (pvoice->use && pvoice->interrupt != NULL) {
72                                                 pvoice->interrupt(emu, pvoice);
73                                                 snd_emu10k1_voice_half_loop_intr_ack(emu, voice);
74                                         } else {
75                                                 snd_emu10k1_voice_half_loop_intr_disable(emu, voice);
76                                         }
77                                 }
78                                 val >>= 1;
79                                 pvoice++;
80                         }
81                         status &= ~(IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK);
82                 }
83                 if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) {
84                         if (emu->capture_interrupt)
85                                 emu->capture_interrupt(emu, status);
86                         else
87                                 snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE);
88                         status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL);
89                 }
90                 if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) {
91                         if (emu->capture_mic_interrupt)
92                                 emu->capture_mic_interrupt(emu, status);
93                         else
94                                 snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE);
95                         status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL);
96                 }
97                 if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) {
98                         if (emu->capture_efx_interrupt)
99                                 emu->capture_efx_interrupt(emu, status);
100                         else
101                                 snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE);
102                         status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL);
103                 }
104                 if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) {
105                         if (emu->midi.interrupt)
106                                 emu->midi.interrupt(emu, status);
107                         else
108                                 snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE);
109                         status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY);
110                 }
111                 if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) {
112                         if (emu->midi2.interrupt)
113                                 emu->midi2.interrupt(emu, status);
114                         else
115                                 snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2);
116                         status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2);
117                 }
118                 if (status & IPR_INTERVALTIMER) {
119                         if (emu->timer)
120                                 snd_timer_interrupt(emu->timer, emu->timer->sticks);
121                         else
122                                 snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
123                         status &= ~IPR_INTERVALTIMER;
124                 }
125                 if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) {
126                         if (emu->spdif_interrupt)
127                                 emu->spdif_interrupt(emu, status);
128                         else
129                                 snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE);
130                         status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE);
131                 }
132                 if (status & IPR_FXDSP) {
133                         if (emu->dsp_interrupt)
134                                 emu->dsp_interrupt(emu);
135                         else
136                                 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
137                         status &= ~IPR_FXDSP;
138                 }
139                 if (status & IPR_P16V) {
140                         if (emu->p16v_interrupt)
141                                 emu->p16v_interrupt(emu);
142                         else
143                                 outl(0, emu->port + INTE2);
144                         status &= ~IPR_P16V;
145                 }
146                 if (status & IPR_A_GPIO) {
147                         if (emu->gpio_interrupt)
148                                 emu->gpio_interrupt(emu);
149                         else
150                                 snd_emu10k1_intr_disable(emu, INTE_A_GPIOENABLE);
151                         status &= ~IPR_A_GPIO;
152                 }
153
154                 if (status) {
155                         dev_err(emu->card->dev,
156                                 "unhandled interrupt: 0x%08x\n", status);
157                 }
158                 outl(orig_status, emu->port + IPR); /* ack all */
159         }
160
161         return IRQ_RETVAL(handled);
162 }