patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / sound / sparc / amd7930.c
1 /*
2  * Driver for AMD7930 sound chips found on Sparcs.
3  * Copyright (C) 2002 David S. Miller <davem@redhat.com>
4  *
5  * Based entirely upon drivers/sbus/audio/amd7930.c which is:
6  * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
7  *
8  * --- Notes from Thomas's original driver ---
9  * This is the lowlevel driver for the AMD7930 audio chip found on all
10  * sun4c machines and some sun4m machines.
11  *
12  * The amd7930 is actually an ISDN chip which has a very simple
13  * integrated audio encoder/decoder. When Sun decided on what chip to
14  * use for audio, they had the brilliant idea of using the amd7930 and
15  * only connecting the audio encoder/decoder pins.
16  *
17  * Thanks to the AMD engineer who was able to get us the AMD79C30
18  * databook which has all the programming information and gain tables.
19  *
20  * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
21  * SparcStation 1+.  The chip provides microphone and speaker interfaces
22  * which provide mono-channel audio at 8K samples per second via either
23  * 8-bit A-law or 8-bit mu-law encoding.  Also, the chip features an
24  * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
25  * which performs basic D channel LAPD processing and provides raw
26  * B channel data.  The digital audio channel, the two ISDN B channels,
27  * and two 64 Kbps channels to the microprocessor are all interconnected
28  * via a multiplexer.
29  * --- End of notes from Thoamas's original driver ---
30  */
31
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/slab.h>
35 #include <linux/init.h>
36 #include <linux/interrupt.h>
37 #include <linux/moduleparam.h>
38
39 #include <sound/driver.h>
40 #include <sound/core.h>
41 #include <sound/pcm.h>
42 #include <sound/info.h>
43 #include <sound/control.h>
44 #include <sound/initval.h>
45
46 #include <asm/io.h>
47 #include <asm/irq.h>
48 #include <asm/sbus.h>
49
50 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
51 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
52 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;      /* Enable this card */
53 static int boot_devs;
54
55 module_param_array(index, int, boot_devs, 0444);
56 MODULE_PARM_DESC(index, "Index value for Sun AMD7930 soundcard.");
57 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
58 module_param_array(id, charp, boot_devs, 0444);
59 MODULE_PARM_DESC(id, "ID string for Sun AMD7930 soundcard.");
60 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
61 module_param_array(enable, bool, boot_devs, 0444);
62 MODULE_PARM_DESC(enable, "Enable Sun AMD7930 soundcard.");
63 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
64 MODULE_AUTHOR("Thomas K. Dyas and David S. Miller");
65 MODULE_DESCRIPTION("Sun AMD7930");
66 MODULE_LICENSE("GPL");
67 MODULE_CLASSES("{sound}");
68 MODULE_DEVICES("{{Sun,AMD7930}}");
69
70 /* Device register layout.  */
71
72 /* Register interface presented to the CPU by the amd7930. */
73 #define AMD7930_CR      0x00UL          /* Command Register (W) */
74 #define AMD7930_IR      AMD7930_CR      /* Interrupt Register (R) */
75 #define AMD7930_DR      0x01UL          /* Data Register (R/W) */
76 #define AMD7930_DSR1    0x02UL          /* D-channel Status Register 1 (R) */
77 #define AMD7930_DER     0x03UL          /* D-channel Error Register (R) */
78 #define AMD7930_DCTB    0x04UL          /* D-channel Transmit Buffer (W) */
79 #define AMD7930_DCRB    AMD7930_DCTB    /* D-channel Receive Buffer (R) */
80 #define AMD7930_BBTB    0x05UL          /* Bb-channel Transmit Buffer (W) */
81 #define AMD7930_BBRB    AMD7930_BBTB    /* Bb-channel Receive Buffer (R) */
82 #define AMD7930_BCTB    0x06UL          /* Bc-channel Transmit Buffer (W) */
83 #define AMD7930_BCRB    AMD7930_BCTB    /* Bc-channel Receive Buffer (R) */
84 #define AMD7930_DSR2    0x07UL          /* D-channel Status Register 2 (R) */
85
86 /* Indirect registers in the Main Audio Processor. */
87 struct amd7930_map {
88         __u16   x[8];
89         __u16   r[8];
90         __u16   gx;
91         __u16   gr;
92         __u16   ger;
93         __u16   stgr;
94         __u16   ftgr;
95         __u16   atgr;
96         __u8    mmr1;
97         __u8    mmr2;
98 };
99
100 /* After an amd7930 interrupt, reading the Interrupt Register (ir)
101  * clears the interrupt and returns a bitmask indicating which
102  * interrupt source(s) require service.
103  */
104
105 #define AMR_IR_DTTHRSH                  0x01 /* D-channel xmit threshold */
106 #define AMR_IR_DRTHRSH                  0x02 /* D-channel recv threshold */
107 #define AMR_IR_DSRI                     0x04 /* D-channel packet status */
108 #define AMR_IR_DERI                     0x08 /* D-channel error */
109 #define AMR_IR_BBUF                     0x10 /* B-channel data xfer */
110 #define AMR_IR_LSRI                     0x20 /* LIU status */
111 #define AMR_IR_DSR2I                    0x40 /* D-channel buffer status */
112 #define AMR_IR_MLTFRMI                  0x80 /* multiframe or PP */
113
114 /* The amd7930 has "indirect registers" which are accessed by writing
115  * the register number into the Command Register and then reading or
116  * writing values from the Data Register as appropriate. We define the
117  * AMR_* macros to be the indirect register numbers and AM_* macros to
118  * be bits in whatever register is referred to.
119  */
120
121 /* Initialization */
122 #define AMR_INIT                        0x21
123 #define         AM_INIT_ACTIVE                  0x01
124 #define         AM_INIT_DATAONLY                0x02
125 #define         AM_INIT_POWERDOWN               0x03
126 #define         AM_INIT_DISABLE_INTS            0x04
127 #define AMR_INIT2                       0x20
128 #define         AM_INIT2_ENABLE_POWERDOWN       0x20
129 #define         AM_INIT2_ENABLE_MULTIFRAME      0x10
130
131 /* Line Interface Unit */
132 #define AMR_LIU_LSR                     0xA1
133 #define         AM_LIU_LSR_STATE                0x07
134 #define         AM_LIU_LSR_F3                   0x08
135 #define         AM_LIU_LSR_F7                   0x10
136 #define         AM_LIU_LSR_F8                   0x20
137 #define         AM_LIU_LSR_HSW                  0x40
138 #define         AM_LIU_LSR_HSW_CHG              0x80
139 #define AMR_LIU_LPR                     0xA2
140 #define AMR_LIU_LMR1                    0xA3
141 #define         AM_LIU_LMR1_B1_ENABL            0x01
142 #define         AM_LIU_LMR1_B2_ENABL            0x02
143 #define         AM_LIU_LMR1_F_DISABL            0x04
144 #define         AM_LIU_LMR1_FA_DISABL           0x08
145 #define         AM_LIU_LMR1_REQ_ACTIV           0x10
146 #define         AM_LIU_LMR1_F8_F3               0x20
147 #define         AM_LIU_LMR1_LIU_ENABL           0x40
148 #define AMR_LIU_LMR2                    0xA4
149 #define         AM_LIU_LMR2_DECHO               0x01
150 #define         AM_LIU_LMR2_DLOOP               0x02
151 #define         AM_LIU_LMR2_DBACKOFF            0x04
152 #define         AM_LIU_LMR2_EN_F3_INT           0x08
153 #define         AM_LIU_LMR2_EN_F8_INT           0x10
154 #define         AM_LIU_LMR2_EN_HSW_INT          0x20
155 #define         AM_LIU_LMR2_EN_F7_INT           0x40
156 #define AMR_LIU_2_4                     0xA5
157 #define AMR_LIU_MF                      0xA6
158 #define AMR_LIU_MFSB                    0xA7
159 #define AMR_LIU_MFQB                    0xA8
160
161 /* Multiplexor */
162 #define AMR_MUX_MCR1                    0x41
163 #define AMR_MUX_MCR2                    0x42
164 #define AMR_MUX_MCR3                    0x43
165 #define         AM_MUX_CHANNEL_B1               0x01
166 #define         AM_MUX_CHANNEL_B2               0x02
167 #define         AM_MUX_CHANNEL_Ba               0x03
168 #define         AM_MUX_CHANNEL_Bb               0x04
169 #define         AM_MUX_CHANNEL_Bc               0x05
170 #define         AM_MUX_CHANNEL_Bd               0x06
171 #define         AM_MUX_CHANNEL_Be               0x07
172 #define         AM_MUX_CHANNEL_Bf               0x08
173 #define AMR_MUX_MCR4                    0x44
174 #define         AM_MUX_MCR4_ENABLE_INTS         0x08
175 #define         AM_MUX_MCR4_REVERSE_Bb          0x10
176 #define         AM_MUX_MCR4_REVERSE_Bc          0x20
177 #define AMR_MUX_1_4                     0x45
178
179 /* Main Audio Processor */
180 #define AMR_MAP_X                       0x61
181 #define AMR_MAP_R                       0x62
182 #define AMR_MAP_GX                      0x63
183 #define AMR_MAP_GR                      0x64
184 #define AMR_MAP_GER                     0x65
185 #define AMR_MAP_STGR                    0x66
186 #define AMR_MAP_FTGR_1_2                0x67
187 #define AMR_MAP_ATGR_1_2                0x68
188 #define AMR_MAP_MMR1                    0x69
189 #define         AM_MAP_MMR1_ALAW                0x01
190 #define         AM_MAP_MMR1_GX                  0x02
191 #define         AM_MAP_MMR1_GR                  0x04
192 #define         AM_MAP_MMR1_GER                 0x08
193 #define         AM_MAP_MMR1_X                   0x10
194 #define         AM_MAP_MMR1_R                   0x20
195 #define         AM_MAP_MMR1_STG                 0x40
196 #define         AM_MAP_MMR1_LOOPBACK            0x80
197 #define AMR_MAP_MMR2                    0x6A
198 #define         AM_MAP_MMR2_AINB                0x01
199 #define         AM_MAP_MMR2_LS                  0x02
200 #define         AM_MAP_MMR2_ENABLE_DTMF         0x04
201 #define         AM_MAP_MMR2_ENABLE_TONEGEN      0x08
202 #define         AM_MAP_MMR2_ENABLE_TONERING     0x10
203 #define         AM_MAP_MMR2_DISABLE_HIGHPASS    0x20
204 #define         AM_MAP_MMR2_DISABLE_AUTOZERO    0x40
205 #define AMR_MAP_1_10                    0x6B
206 #define AMR_MAP_MMR3                    0x6C
207 #define AMR_MAP_STRA                    0x6D
208 #define AMR_MAP_STRF                    0x6E
209 #define AMR_MAP_PEAKX                   0x70
210 #define AMR_MAP_PEAKR                   0x71
211 #define AMR_MAP_15_16                   0x72
212
213 /* Data Link Controller */
214 #define AMR_DLC_FRAR_1_2_3              0x81
215 #define AMR_DLC_SRAR_1_2_3              0x82
216 #define AMR_DLC_TAR                     0x83
217 #define AMR_DLC_DRLR                    0x84
218 #define AMR_DLC_DTCR                    0x85
219 #define AMR_DLC_DMR1                    0x86
220 #define         AMR_DLC_DMR1_DTTHRSH_INT        0x01
221 #define         AMR_DLC_DMR1_DRTHRSH_INT        0x02
222 #define         AMR_DLC_DMR1_TAR_ENABL          0x04
223 #define         AMR_DLC_DMR1_EORP_INT           0x08
224 #define         AMR_DLC_DMR1_EN_ADDR1           0x10
225 #define         AMR_DLC_DMR1_EN_ADDR2           0x20
226 #define         AMR_DLC_DMR1_EN_ADDR3           0x40
227 #define         AMR_DLC_DMR1_EN_ADDR4           0x80
228 #define         AMR_DLC_DMR1_EN_ADDRS           0xf0
229 #define AMR_DLC_DMR2                    0x87
230 #define         AMR_DLC_DMR2_RABRT_INT          0x01
231 #define         AMR_DLC_DMR2_RESID_INT          0x02
232 #define         AMR_DLC_DMR2_COLL_INT           0x04
233 #define         AMR_DLC_DMR2_FCS_INT            0x08
234 #define         AMR_DLC_DMR2_OVFL_INT           0x10
235 #define         AMR_DLC_DMR2_UNFL_INT           0x20
236 #define         AMR_DLC_DMR2_OVRN_INT           0x40
237 #define         AMR_DLC_DMR2_UNRN_INT           0x80
238 #define AMR_DLC_1_7                     0x88
239 #define AMR_DLC_DRCR                    0x89
240 #define AMR_DLC_RNGR1                   0x8A
241 #define AMR_DLC_RNGR2                   0x8B
242 #define AMR_DLC_FRAR4                   0x8C
243 #define AMR_DLC_SRAR4                   0x8D
244 #define AMR_DLC_DMR3                    0x8E
245 #define         AMR_DLC_DMR3_VA_INT             0x01
246 #define         AMR_DLC_DMR3_EOTP_INT           0x02
247 #define         AMR_DLC_DMR3_LBRP_INT           0x04
248 #define         AMR_DLC_DMR3_RBA_INT            0x08
249 #define         AMR_DLC_DMR3_LBT_INT            0x10
250 #define         AMR_DLC_DMR3_TBE_INT            0x20
251 #define         AMR_DLC_DMR3_RPLOST_INT         0x40
252 #define         AMR_DLC_DMR3_KEEP_FCS           0x80
253 #define AMR_DLC_DMR4                    0x8F
254 #define         AMR_DLC_DMR4_RCV_1              0x00
255 #define         AMR_DLC_DMR4_RCV_2              0x01
256 #define         AMR_DLC_DMR4_RCV_4              0x02
257 #define         AMR_DLC_DMR4_RCV_8              0x03
258 #define         AMR_DLC_DMR4_RCV_16             0x01
259 #define         AMR_DLC_DMR4_RCV_24             0x02
260 #define         AMR_DLC_DMR4_RCV_30             0x03
261 #define         AMR_DLC_DMR4_XMT_1              0x00
262 #define         AMR_DLC_DMR4_XMT_2              0x04
263 #define         AMR_DLC_DMR4_XMT_4              0x08
264 #define         AMR_DLC_DMR4_XMT_8              0x0c
265 #define         AMR_DLC_DMR4_XMT_10             0x08
266 #define         AMR_DLC_DMR4_XMT_14             0x0c
267 #define         AMR_DLC_DMR4_IDLE_MARK          0x00
268 #define         AMR_DLC_DMR4_IDLE_FLAG          0x10
269 #define         AMR_DLC_DMR4_ADDR_BOTH          0x00
270 #define         AMR_DLC_DMR4_ADDR_1ST           0x20
271 #define         AMR_DLC_DMR4_ADDR_2ND           0xa0
272 #define         AMR_DLC_DMR4_CR_ENABLE          0x40
273 #define AMR_DLC_12_15                   0x90
274 #define AMR_DLC_ASR                     0x91
275 #define AMR_DLC_EFCR                    0x92
276 #define         AMR_DLC_EFCR_EXTEND_FIFO        0x01
277 #define         AMR_DLC_EFCR_SEC_PKT_INT        0x02
278
279 #define AMR_DSR1_VADDR                  0x01
280 #define AMR_DSR1_EORP                   0x02
281 #define AMR_DSR1_PKT_IP                 0x04
282 #define AMR_DSR1_DECHO_ON               0x08
283 #define AMR_DSR1_DLOOP_ON               0x10
284 #define AMR_DSR1_DBACK_OFF              0x20
285 #define AMR_DSR1_EOTP                   0x40
286 #define AMR_DSR1_CXMT_ABRT              0x80
287
288 #define AMR_DSR2_LBRP                   0x01
289 #define AMR_DSR2_RBA                    0x02
290 #define AMR_DSR2_RPLOST                 0x04
291 #define AMR_DSR2_LAST_BYTE              0x08
292 #define AMR_DSR2_TBE                    0x10
293 #define AMR_DSR2_MARK_IDLE              0x20
294 #define AMR_DSR2_FLAG_IDLE              0x40
295 #define AMR_DSR2_SECOND_PKT             0x80
296
297 #define AMR_DER_RABRT                   0x01
298 #define AMR_DER_RFRAME                  0x02
299 #define AMR_DER_COLLISION               0x04
300 #define AMR_DER_FCS                     0x08
301 #define AMR_DER_OVFL                    0x10
302 #define AMR_DER_UNFL                    0x20
303 #define AMR_DER_OVRN                    0x40
304 #define AMR_DER_UNRN                    0x80
305
306 /* Peripheral Port */
307 #define AMR_PP_PPCR1                    0xC0
308 #define AMR_PP_PPSR                     0xC1
309 #define AMR_PP_PPIER                    0xC2
310 #define AMR_PP_MTDR                     0xC3
311 #define AMR_PP_MRDR                     0xC3
312 #define AMR_PP_CITDR0                   0xC4
313 #define AMR_PP_CIRDR0                   0xC4
314 #define AMR_PP_CITDR1                   0xC5
315 #define AMR_PP_CIRDR1                   0xC5
316 #define AMR_PP_PPCR2                    0xC8
317 #define AMR_PP_PPCR3                    0xC9
318
319 typedef struct snd_amd7930 {
320         spinlock_t              lock;
321         unsigned long           regs;
322         u32                     flags;
323 #define AMD7930_FLAG_PLAYBACK   0x00000001
324 #define AMD7930_FLAG_CAPTURE    0x00000002
325
326         struct amd7930_map      map;
327
328         snd_card_t              *card;
329         snd_pcm_t               *pcm;
330         snd_pcm_substream_t     *playback_substream;
331         snd_pcm_substream_t     *capture_substream;
332
333         /* Playback/Capture buffer state. */
334         unsigned char           *p_orig, *p_cur;
335         int                     p_left;
336         unsigned char           *c_orig, *c_cur;
337         int                     c_left;
338
339         int                     rgain;
340         int                     pgain;
341         int                     mgain;
342
343         struct sbus_dev         *sdev;
344         unsigned int            irq;
345         unsigned int            regs_size;
346         struct snd_amd7930      *next;
347 } amd7930_t;
348 #define chip_t amd7930_t
349
350 static amd7930_t *amd7930_list;
351
352 /* Idle the AMD7930 chip.  The amd->lock is not held.  */
353 static __inline__ void amd7930_idle(amd7930_t *amd)
354 {
355         unsigned long flags;
356
357         spin_lock_irqsave(&amd->lock, flags);
358         sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
359         sbus_writeb(0, amd->regs + AMD7930_DR);
360         spin_unlock_irqrestore(&amd->lock, flags);
361 }
362
363 /* Enable chip interrupts.  The amd->lock is not held.  */
364 static __inline__ void amd7930_enable_ints(amd7930_t *amd)
365 {
366         unsigned long flags;
367
368         spin_lock_irqsave(&amd->lock, flags);
369         sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
370         sbus_writeb(AM_INIT_ACTIVE, amd->regs + AMD7930_DR);
371         spin_unlock_irqrestore(&amd->lock, flags);
372 }
373
374 /* Disable chip interrupts.  The amd->lock is not held.  */
375 static __inline__ void amd7930_disable_ints(amd7930_t *amd)
376 {
377         unsigned long flags;
378
379         spin_lock_irqsave(&amd->lock, flags);
380         sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
381         sbus_writeb(AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS, amd->regs + AMD7930_DR);
382         spin_unlock_irqrestore(&amd->lock, flags);
383 }
384
385 /* Commit amd7930_map settings to the hardware.
386  * The amd->lock is held and local interrupts are disabled.
387  */
388 static void __amd7930_write_map(amd7930_t *amd)
389 {
390         struct amd7930_map *map = &amd->map;
391
392         sbus_writeb(AMR_MAP_GX, amd->regs + AMD7930_CR);
393         sbus_writeb(((map->gx >> 0) & 0xff), amd->regs + AMD7930_DR);
394         sbus_writeb(((map->gx >> 8) & 0xff), amd->regs + AMD7930_DR);
395
396         sbus_writeb(AMR_MAP_GR, amd->regs + AMD7930_CR);
397         sbus_writeb(((map->gr >> 0) & 0xff), amd->regs + AMD7930_DR);
398         sbus_writeb(((map->gr >> 8) & 0xff), amd->regs + AMD7930_DR);
399
400         sbus_writeb(AMR_MAP_STGR, amd->regs + AMD7930_CR);
401         sbus_writeb(((map->stgr >> 0) & 0xff), amd->regs + AMD7930_DR);
402         sbus_writeb(((map->stgr >> 8) & 0xff), amd->regs + AMD7930_DR);
403
404         sbus_writeb(AMR_MAP_GER, amd->regs + AMD7930_CR);
405         sbus_writeb(((map->ger >> 0) & 0xff), amd->regs + AMD7930_DR);
406         sbus_writeb(((map->ger >> 8) & 0xff), amd->regs + AMD7930_DR);
407
408         sbus_writeb(AMR_MAP_MMR1, amd->regs + AMD7930_CR);
409         sbus_writeb(map->mmr1, amd->regs + AMD7930_DR);
410
411         sbus_writeb(AMR_MAP_MMR2, amd->regs + AMD7930_CR);
412         sbus_writeb(map->mmr2, amd->regs + AMD7930_DR);
413 }
414
415 /* gx, gr & stg gains.  this table must contain 256 elements with
416  * the 0th being "infinity" (the magic value 9008).  The remaining
417  * elements match sun's gain curve (but with higher resolution):
418  * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
419  */
420 static __const__ __u16 gx_coeff[256] = {
421         0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
422         0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
423         0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
424         0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
425         0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
426         0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
427         0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
428         0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
429         0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
430         0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
431         0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
432         0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
433         0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
434         0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
435         0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
436         0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
437         0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
438         0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
439         0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
440         0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
441         0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
442         0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
443         0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
444         0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
445         0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
446         0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
447         0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
448         0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
449         0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
450         0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
451         0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
452         0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
453 };
454
455 static __const__ __u16 ger_coeff[] = {
456         0x431f, /* 5. dB */
457         0x331f, /* 5.5 dB */
458         0x40dd, /* 6. dB */
459         0x11dd, /* 6.5 dB */
460         0x440f, /* 7. dB */
461         0x411f, /* 7.5 dB */
462         0x311f, /* 8. dB */
463         0x5520, /* 8.5 dB */
464         0x10dd, /* 9. dB */
465         0x4211, /* 9.5 dB */
466         0x410f, /* 10. dB */
467         0x111f, /* 10.5 dB */
468         0x600b, /* 11. dB */
469         0x00dd, /* 11.5 dB */
470         0x4210, /* 12. dB */
471         0x110f, /* 13. dB */
472         0x7200, /* 14. dB */
473         0x2110, /* 15. dB */
474         0x2200, /* 15.9 dB */
475         0x000b, /* 16.9 dB */
476         0x000f  /* 18. dB */
477 };
478 #define NR_GER_COEFFS (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
479
480 /* Update amd7930_map settings and program them into the hardware.
481  * The amd->lock is held and local interrupts are disabled.
482  */
483 static void __amd7930_update_map(amd7930_t *amd)
484 {
485         struct amd7930_map *map = &amd->map;
486         int level;
487
488         map->gx = gx_coeff[amd->rgain];
489         map->stgr = gx_coeff[amd->mgain];
490         level = (amd->pgain * (256 + NR_GER_COEFFS)) >> 8;
491         if (level >= 256) {
492                 map->ger = ger_coeff[level - 256];
493                 map->gr = gx_coeff[255];
494         } else {
495                 map->ger = ger_coeff[0];
496                 map->gr = gx_coeff[level];
497         }
498         __amd7930_write_map(amd);
499 }
500
501 static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id, struct pt_regs *regs)
502 {
503         amd7930_t *amd = dev_id;
504         unsigned int elapsed;
505         u8 ir;
506
507         spin_lock(&amd->lock);
508
509         elapsed = 0;
510
511         ir = sbus_readb(amd->regs + AMD7930_IR);
512         if (ir & AMR_IR_BBUF) {
513                 u8 byte;
514
515                 if (amd->flags & AMD7930_FLAG_PLAYBACK) {
516                         if (amd->p_left > 0) {
517                                 byte = *(amd->p_cur++);
518                                 amd->p_left--;
519                                 sbus_writeb(byte, amd->regs + AMD7930_BBTB);
520                                 if (amd->p_left == 0)
521                                         elapsed |= AMD7930_FLAG_PLAYBACK;
522                         } else
523                                 sbus_writeb(0, amd->regs + AMD7930_BBTB);
524                 } else if (amd->flags & AMD7930_FLAG_CAPTURE) {
525                         byte = sbus_readb(amd->regs + AMD7930_BBRB);
526                         if (amd->c_left > 0) {
527                                 *(amd->c_cur++) = byte;
528                                 amd->c_left--;
529                                 if (amd->c_left == 0)
530                                         elapsed |= AMD7930_FLAG_CAPTURE;
531                         }
532                 }
533         }
534         spin_unlock(&amd->lock);
535
536         if (elapsed & AMD7930_FLAG_PLAYBACK)
537                 snd_pcm_period_elapsed(amd->playback_substream);
538         else
539                 snd_pcm_period_elapsed(amd->capture_substream);
540
541         return IRQ_HANDLED;
542 }
543
544 static int snd_amd7930_trigger(amd7930_t *amd, unsigned int flag, int cmd)
545 {
546         unsigned long flags;
547         int result = 0;
548
549         spin_lock_irqsave(&amd->lock, flags);
550         if (cmd == SNDRV_PCM_TRIGGER_START) {
551                 if (!(amd->flags & flag)) {
552                         amd->flags |= flag;
553
554                         /* Enable B channel interrupts.  */
555                         sbus_writeb(AMR_MUX_MCR4, amd->regs + AMD7930_CR);
556                         sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, amd->regs + AMD7930_DR);
557                 }
558         } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
559                 if (amd->flags & flag) {
560                         amd->flags &= ~flag;
561
562                         /* Disable B channel interrupts.  */
563                         sbus_writeb(AMR_MUX_MCR4, amd->regs + AMD7930_CR);
564                         sbus_writeb(0, amd->regs + AMD7930_DR);
565                 }
566         } else {
567                 result = -EINVAL;
568         }
569         spin_unlock_irqrestore(&amd->lock, flags);
570
571         return result;
572 }
573
574 static int snd_amd7930_playback_trigger(snd_pcm_substream_t * substream,
575                                         int cmd)
576 {
577         amd7930_t *amd = snd_pcm_substream_chip(substream);
578         return snd_amd7930_trigger(amd, AMD7930_FLAG_PLAYBACK, cmd);
579 }
580
581 static int snd_amd7930_capture_trigger(snd_pcm_substream_t * substream,
582                                        int cmd)
583 {
584         amd7930_t *amd = snd_pcm_substream_chip(substream);
585         return snd_amd7930_trigger(amd, AMD7930_FLAG_CAPTURE, cmd);
586 }
587
588 static int snd_amd7930_playback_prepare(snd_pcm_substream_t * substream)
589 {
590         amd7930_t *amd = snd_pcm_substream_chip(substream);
591         snd_pcm_runtime_t *runtime = substream->runtime;
592         unsigned int size = snd_pcm_lib_buffer_bytes(substream);
593         unsigned long flags;
594         u8 new_mmr1;
595
596         spin_lock_irqsave(&amd->lock, flags);
597
598         amd->flags |= AMD7930_FLAG_PLAYBACK;
599
600         /* Setup the pseudo-dma transfer pointers.  */
601         amd->p_orig = amd->p_cur = runtime->dma_area;
602         amd->p_left = size;
603
604         /* Put the chip into the correct encoding format.  */
605         new_mmr1 = amd->map.mmr1;
606         if (runtime->format == SNDRV_PCM_FORMAT_A_LAW)
607                 new_mmr1 |= AM_MAP_MMR1_ALAW;
608         else
609                 new_mmr1 &= ~AM_MAP_MMR1_ALAW;
610         if (new_mmr1 != amd->map.mmr1) {
611                 amd->map.mmr1 = new_mmr1;
612                 __amd7930_update_map(amd);
613         }
614
615         spin_unlock_irqrestore(&amd->lock, flags);
616
617         return 0;
618 }
619
620 static int snd_amd7930_capture_prepare(snd_pcm_substream_t * substream)
621 {
622         amd7930_t *amd = snd_pcm_substream_chip(substream);
623         snd_pcm_runtime_t *runtime = substream->runtime;
624         unsigned int size = snd_pcm_lib_buffer_bytes(substream);
625         unsigned long flags;
626         u8 new_mmr1;
627
628         spin_lock_irqsave(&amd->lock, flags);
629
630         amd->flags |= AMD7930_FLAG_CAPTURE;
631
632         /* Setup the pseudo-dma transfer pointers.  */
633         amd->c_orig = amd->c_cur = runtime->dma_area;
634         amd->c_left = size;
635
636         /* Put the chip into the correct encoding format.  */
637         new_mmr1 = amd->map.mmr1;
638         if (runtime->format == SNDRV_PCM_FORMAT_A_LAW)
639                 new_mmr1 |= AM_MAP_MMR1_ALAW;
640         else
641                 new_mmr1 &= ~AM_MAP_MMR1_ALAW;
642         if (new_mmr1 != amd->map.mmr1) {
643                 amd->map.mmr1 = new_mmr1;
644                 __amd7930_update_map(amd);
645         }
646
647         spin_unlock_irqrestore(&amd->lock, flags);
648
649         return 0;
650 }
651
652 static snd_pcm_uframes_t snd_amd7930_playback_pointer(snd_pcm_substream_t * substream)
653 {
654         amd7930_t *amd = snd_pcm_substream_chip(substream);
655         size_t ptr;
656
657         if (!(amd->flags & AMD7930_FLAG_PLAYBACK))
658                 return 0;
659         ptr = amd->p_cur - amd->p_orig;
660         return bytes_to_frames(substream->runtime, ptr);
661 }
662
663 static snd_pcm_uframes_t snd_amd7930_capture_pointer(snd_pcm_substream_t * substream)
664 {
665         amd7930_t *amd = snd_pcm_substream_chip(substream);
666         size_t ptr;
667
668         if (!(amd->flags & AMD7930_FLAG_CAPTURE))
669                 return 0;
670
671         ptr = amd->c_cur - amd->c_orig;
672         return bytes_to_frames(substream->runtime, ptr);
673 }
674
675 /* Playback and capture have identical properties.  */
676 static snd_pcm_hardware_t snd_amd7930_pcm_hw =
677 {
678         .info                   = (SNDRV_PCM_INFO_MMAP |
679                                    SNDRV_PCM_INFO_MMAP_VALID |
680                                    SNDRV_PCM_INFO_INTERLEAVED |
681                                    SNDRV_PCM_INFO_BLOCK_TRANSFER |
682                                    SNDRV_PCM_INFO_HALF_DUPLEX),
683         .formats                = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
684         .rates                  = SNDRV_PCM_RATE_8000,
685         .rate_min               = 8000,
686         .rate_max               = 8000,
687         .channels_min           = 1,
688         .channels_max           = 1,
689         .buffer_bytes_max       = (64*1024),
690         .period_bytes_min       = 1,
691         .period_bytes_max       = (64*1024),
692         .periods_min            = 1,
693         .periods_max            = 1024,
694 };
695
696 static int snd_amd7930_playback_open(snd_pcm_substream_t * substream)
697 {
698         amd7930_t *amd = snd_pcm_substream_chip(substream);
699         snd_pcm_runtime_t *runtime = substream->runtime;
700
701         amd->playback_substream = substream;
702         runtime->hw = snd_amd7930_pcm_hw;
703         return 0;
704 }
705
706 static int snd_amd7930_capture_open(snd_pcm_substream_t * substream)
707 {
708         amd7930_t *amd = snd_pcm_substream_chip(substream);
709         snd_pcm_runtime_t *runtime = substream->runtime;
710
711         amd->capture_substream = substream;
712         runtime->hw = snd_amd7930_pcm_hw;
713         return 0;
714 }
715
716 static int snd_amd7930_playback_close(snd_pcm_substream_t * substream)
717 {
718         amd7930_t *amd = snd_pcm_substream_chip(substream);
719
720         amd->playback_substream = NULL;
721         return 0;
722 }
723
724 static int snd_amd7930_capture_close(snd_pcm_substream_t * substream)
725 {
726         amd7930_t *amd = snd_pcm_substream_chip(substream);
727
728         amd->capture_substream = NULL;
729         return 0;
730 }
731
732 static int snd_amd7930_hw_params(snd_pcm_substream_t * substream,
733                                     snd_pcm_hw_params_t * hw_params)
734 {
735         return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
736 }
737
738 static int snd_amd7930_hw_free(snd_pcm_substream_t * substream)
739 {
740         return snd_pcm_lib_free_pages(substream);
741 }
742
743 static snd_pcm_ops_t snd_amd7930_playback_ops = {
744         .open           =       snd_amd7930_playback_open,
745         .close          =       snd_amd7930_playback_close,
746         .ioctl          =       snd_pcm_lib_ioctl,
747         .hw_params      =       snd_amd7930_hw_params,
748         .hw_free        =       snd_amd7930_hw_free,
749         .prepare        =       snd_amd7930_playback_prepare,
750         .trigger        =       snd_amd7930_playback_trigger,
751         .pointer        =       snd_amd7930_playback_pointer,
752 };
753
754 static snd_pcm_ops_t snd_amd7930_capture_ops = {
755         .open           =       snd_amd7930_capture_open,
756         .close          =       snd_amd7930_capture_close,
757         .ioctl          =       snd_pcm_lib_ioctl,
758         .hw_params      =       snd_amd7930_hw_params,
759         .hw_free        =       snd_amd7930_hw_free,
760         .prepare        =       snd_amd7930_capture_prepare,
761         .trigger        =       snd_amd7930_capture_trigger,
762         .pointer        =       snd_amd7930_capture_pointer,
763 };
764
765 static void snd_amd7930_pcm_free(snd_pcm_t *pcm)
766 {
767         amd7930_t *amd = snd_magic_cast(amd7930_t, pcm->private_data, return);
768
769         amd->pcm = NULL;
770         snd_pcm_lib_preallocate_free_for_all(pcm);
771 }
772
773 static int __init snd_amd7930_pcm(amd7930_t *amd)
774 {
775         snd_pcm_t *pcm;
776         int err;
777
778         if ((err = snd_pcm_new(amd->card,
779                                /* ID */             "sun_amd7930",
780                                /* device */         0,
781                                /* playback count */ 1,
782                                /* capture count */  1, &pcm)) < 0)
783                 return err;
784         snd_assert(pcm != NULL, return -EINVAL);
785
786         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_amd7930_playback_ops);
787         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_amd7930_capture_ops);
788
789         pcm->private_data = amd;
790         pcm->private_free = snd_amd7930_pcm_free;
791         pcm->info_flags = 0;
792         strcpy(pcm->name, amd->card->shortname);
793         amd->pcm = pcm;
794
795         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
796                                               snd_dma_continuous_data(GFP_KERNEL),
797                                               64*1024, 64*1024);
798
799         return 0;
800 }
801
802 #define VOLUME_MONITOR  0
803 #define VOLUME_CAPTURE  1
804 #define VOLUME_PLAYBACK 2
805
806 static int snd_amd7930_info_volume(snd_kcontrol_t *kctl, snd_ctl_elem_info_t *uinfo)
807 {
808         int type = kctl->private_value;
809
810         snd_assert(type == VOLUME_MONITOR ||
811                    type == VOLUME_CAPTURE ||
812                    type == VOLUME_PLAYBACK, return -EINVAL);
813         (void) type;
814
815         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
816         uinfo->count = 1;
817         uinfo->value.integer.min = 0;
818         uinfo->value.integer.max = 255;
819
820         return 0;
821 }
822
823 static int snd_amd7930_get_volume(snd_kcontrol_t *kctl, snd_ctl_elem_value_t *ucontrol)
824 {
825         amd7930_t *amd = snd_kcontrol_chip(kctl);
826         int type = kctl->private_value;
827         int *swval;
828
829         snd_assert(type == VOLUME_MONITOR ||
830                    type == VOLUME_CAPTURE ||
831                    type == VOLUME_PLAYBACK, return -EINVAL);
832
833         switch (type) {
834         case VOLUME_MONITOR:
835                 swval = &amd->mgain;
836                 break;
837         case VOLUME_CAPTURE:
838                 swval = &amd->rgain;
839                 break;
840         case VOLUME_PLAYBACK:
841         default:
842                 swval = &amd->pgain;
843                 break;
844         };
845
846         ucontrol->value.integer.value[0] = *swval;
847
848         return 0;
849 }
850
851 static int snd_amd7930_put_volume(snd_kcontrol_t *kctl, snd_ctl_elem_value_t *ucontrol)
852 {
853         amd7930_t *amd = snd_kcontrol_chip(kctl);
854         unsigned long flags;
855         int type = kctl->private_value;
856         int *swval, change;
857
858         snd_assert(type == VOLUME_MONITOR ||
859                    type == VOLUME_CAPTURE ||
860                    type == VOLUME_PLAYBACK, return -EINVAL);
861
862         switch (type) {
863         case VOLUME_MONITOR:
864                 swval = &amd->mgain;
865                 break;
866         case VOLUME_CAPTURE:
867                 swval = &amd->rgain;
868                 break;
869         case VOLUME_PLAYBACK:
870         default:
871                 swval = &amd->pgain;
872                 break;
873         };
874
875         spin_lock_irqsave(&amd->lock, flags);
876
877         if (*swval != ucontrol->value.integer.value[0]) {
878                 *swval = ucontrol->value.integer.value[0];
879                 __amd7930_update_map(amd);
880                 change = 1;
881         } else
882                 change = 0;
883
884         spin_unlock_irqrestore(&amd->lock, flags);
885
886         return change;
887 }
888
889 static snd_kcontrol_new_t amd7930_controls[] __initdata = {
890         {
891                 .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
892                 .name           =       "Monitor Volume",
893                 .index          =       0,
894                 .info           =       snd_amd7930_info_volume,
895                 .get            =       snd_amd7930_get_volume,
896                 .put            =       snd_amd7930_put_volume,
897                 .private_value  =       VOLUME_MONITOR,
898         },
899         {
900                 .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
901                 .name           =       "Capture Volume",
902                 .index          =       0,
903                 .info           =       snd_amd7930_info_volume,
904                 .get            =       snd_amd7930_get_volume,
905                 .put            =       snd_amd7930_put_volume,
906                 .private_value  =       VOLUME_CAPTURE,
907         },
908         {
909                 .iface          =       SNDRV_CTL_ELEM_IFACE_MIXER,
910                 .name           =       "Playback Volume",
911                 .index          =       0,
912                 .info           =       snd_amd7930_info_volume,
913                 .get            =       snd_amd7930_get_volume,
914                 .put            =       snd_amd7930_put_volume,
915                 .private_value  =       VOLUME_PLAYBACK,
916         },
917 };
918
919 #define NUM_AMD7930_CONTROLS (sizeof(amd7930_controls)/sizeof(snd_kcontrol_new_t))
920
921 static int __init snd_amd7930_mixer(amd7930_t *amd)
922 {
923         snd_card_t *card;
924         int idx, err;
925
926         snd_assert(amd != NULL && amd->card != NULL, return -EINVAL);
927
928         card = amd->card;
929         strcpy(card->mixername, card->shortname);
930
931         for (idx = 0; idx < NUM_AMD7930_CONTROLS; idx++) {
932                 if ((err = snd_ctl_add(card,
933                                        snd_ctl_new1(&amd7930_controls[idx], amd))) < 0)
934                         return err;
935         }
936
937         return 0;
938 }
939
940 static int snd_amd7930_free(amd7930_t *amd)
941 {
942         amd7930_idle(amd);
943
944         if (amd->irq)
945                 free_irq(amd->irq, amd);
946
947         if (amd->regs)
948                 sbus_iounmap(amd->regs, amd->regs_size);
949
950         snd_magic_kfree(amd);
951
952         return 0;
953 }
954
955 static int snd_amd7930_dev_free(snd_device_t *device)
956 {
957         amd7930_t *amd = snd_magic_cast(amd7930_t, device->device_data, return -ENXIO);
958
959         return snd_amd7930_free(amd);
960 }
961
962 static snd_device_ops_t snd_amd7930_dev_ops = {
963         .dev_free       =       snd_amd7930_dev_free,
964 };
965
966 static int __init snd_amd7930_create(snd_card_t *card,
967                                      struct sbus_dev *sdev,
968                                      struct resource *rp,
969                                      unsigned int reg_size,
970                                      struct linux_prom_irqs *irq_prop,
971                                      int dev,
972                                      amd7930_t **ramd)
973 {
974         unsigned long flags;
975         amd7930_t *amd;
976         int err;
977
978         *ramd = NULL;
979         amd = snd_magic_kcalloc(amd7930_t, 0, GFP_KERNEL);
980         if (amd == NULL)
981                 return -ENOMEM;
982
983         spin_lock_init(&amd->lock);
984         amd->card = card;
985         amd->sdev = sdev;
986         amd->regs_size = reg_size;
987
988         amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
989         if (!amd->regs) {
990                 snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
991                 return -EIO;
992         }
993
994         amd7930_idle(amd);
995
996         if (request_irq(irq_prop->pri, snd_amd7930_interrupt,
997                         SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) {
998                 snd_printk("amd7930-%d: Unable to grab IRQ %s\n",
999                            dev,
1000                            __irq_itoa(irq_prop->pri));
1001                 snd_amd7930_free(amd);
1002                 return -EBUSY;
1003         }
1004         amd->irq = irq_prop->pri;
1005
1006         amd7930_enable_ints(amd);
1007
1008         spin_lock_irqsave(&amd->lock, flags);
1009
1010         amd->rgain = 128;
1011         amd->pgain = 200;
1012         amd->mgain = 0;
1013
1014         memset(&amd->map, 0, sizeof(amd->map));
1015         amd->map.mmr1 = (AM_MAP_MMR1_GX | AM_MAP_MMR1_GER |
1016                          AM_MAP_MMR1_GR | AM_MAP_MMR1_STG);
1017         amd->map.mmr2 = (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB);
1018
1019         __amd7930_update_map(amd);
1020
1021         /* Always MUX audio (Ba) to channel Bb. */
1022         sbus_writeb(AMR_MUX_MCR1, amd->regs + AMD7930_CR);
1023         sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4),
1024                     amd->regs + AMD7930_DR);
1025
1026         spin_unlock_irqrestore(&amd->lock, flags);
1027
1028         if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
1029                                   amd, &snd_amd7930_dev_ops)) < 0) {
1030                 snd_amd7930_free(amd);
1031                 return err;
1032         }
1033
1034         *ramd = amd;
1035         return 0;
1036 }
1037
1038 static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
1039 {
1040         static int dev;
1041         struct linux_prom_registers reg_prop;
1042         struct linux_prom_irqs irq_prop;
1043         struct resource res, *rp;
1044         snd_card_t *card;
1045         amd7930_t *amd;
1046         int err;
1047
1048         if (dev >= SNDRV_CARDS)
1049                 return -ENODEV;
1050         if (!enable[dev]) {
1051                 dev++;
1052                 return -ENOENT;
1053         }
1054
1055         err = prom_getproperty(prom_node, "intr",
1056                                (char *) &irq_prop, sizeof(irq_prop));
1057         if (err < 0) {
1058                 snd_printk("amd7930-%d: Firmware node lacks IRQ property.\n", dev);
1059                 return -ENODEV;
1060         }
1061
1062         err = prom_getproperty(prom_node, "reg",
1063                                (char *) &reg_prop, sizeof(reg_prop));
1064         if (err < 0) {
1065                 snd_printk("amd7930-%d: Firmware node lacks register property.\n", dev);
1066                 return -ENODEV;
1067         }
1068
1069         if (sdev) {
1070                 rp = &sdev->resource[0];
1071         } else {
1072                 rp = &res;
1073                 rp->start = reg_prop.phys_addr;
1074                 rp->end = rp->start + reg_prop.reg_size - 1;
1075                 rp->flags = IORESOURCE_IO | (reg_prop.which_io & 0xff);
1076         }
1077
1078         card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
1079         if (card == NULL)
1080                 return -ENOMEM;
1081
1082         strcpy(card->driver, "AMD7930");
1083         strcpy(card->shortname, "Sun AMD7930");
1084         sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s",
1085                 card->shortname,
1086                 rp->flags & 0xffL,
1087                 rp->start,
1088                 __irq_itoa(irq_prop.pri));
1089
1090         if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size,
1091                                           &irq_prop, dev, &amd)) < 0)
1092                 goto out_err;
1093
1094         if ((err = snd_amd7930_pcm(amd)) < 0)
1095                 goto out_err;
1096
1097         if ((err = snd_amd7930_mixer(amd)) < 0)
1098                 goto out_err;
1099
1100         if ((err = snd_card_register(card)) < 0)
1101                 goto out_err;
1102
1103         amd->next = amd7930_list;
1104         amd7930_list = amd;
1105
1106         dev++;
1107         return 0;
1108
1109 out_err:
1110         snd_card_free(card);
1111         return err;
1112 }
1113
1114 static int __init amd7930_init(void)
1115 {
1116         struct sbus_bus *sbus;
1117         struct sbus_dev *sdev;
1118         int node, found;
1119
1120         found = 0;
1121
1122         /* Try to find the sun4c "audio" node first. */
1123         node = prom_getchild(prom_root_node);
1124         node = prom_searchsiblings(node, "audio");
1125         if (node && amd7930_attach(node, NULL) == 0)
1126                 found++;
1127
1128         /* Probe each SBUS for amd7930 chips. */
1129         for_all_sbusdev(sdev, sbus) {
1130                 if (!strcmp(sdev->prom_name, "audio")) {
1131                         if (amd7930_attach(sdev->prom_node, sdev) == 0)
1132                                 found++;
1133                 }
1134         }
1135
1136         return (found > 0) ? 0 : -EIO;
1137 }
1138
1139 static void __exit amd7930_exit(void)
1140 {
1141         amd7930_t *p = amd7930_list;
1142
1143         while (p != NULL) {
1144                 amd7930_t *next = p->next;
1145
1146                 snd_card_free(p->card);
1147
1148                 p = next;
1149         }
1150
1151         amd7930_list = NULL;
1152 }
1153
1154 module_init(amd7930_init);
1155 module_exit(amd7930_exit);