blob: f4361c518e460565d147542636c5eda196905f1e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Driver for CS4231 sound chips found on Sparcs.
3 * Copyright (C) 2002 David S. Miller <davem@redhat.com>
4 *
5 * Based entirely upon drivers/sbus/audio/cs4231.c which is:
6 * Copyright (C) 1996, 1997, 1998, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
7 * and also sound/isa/cs423x/cs4231_lib.c which is:
8 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
9 */
10
11#include <linux/config.h>
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/slab.h>
15#include <linux/delay.h>
16#include <linux/init.h>
17#include <linux/interrupt.h>
18#include <linux/moduleparam.h>
19
20#include <sound/driver.h>
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/info.h>
24#include <sound/control.h>
25#include <sound/timer.h>
26#include <sound/initval.h>
27#include <sound/pcm_params.h>
28
29#include <asm/io.h>
30#include <asm/irq.h>
31
32#ifdef CONFIG_SBUS
33#define SBUS_SUPPORT
34#endif
35
36#ifdef SBUS_SUPPORT
37#include <asm/sbus.h>
38#endif
39
40#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
41#define EBUS_SUPPORT
42#endif
43
44#ifdef EBUS_SUPPORT
45#include <linux/pci.h>
46#include <asm/ebus.h>
47#endif
48
49static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
50static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
51static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
52
53module_param_array(index, int, NULL, 0444);
54MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard.");
55module_param_array(id, charp, NULL, 0444);
56MODULE_PARM_DESC(id, "ID string for Sun CS4231 soundcard.");
57module_param_array(enable, bool, NULL, 0444);
58MODULE_PARM_DESC(enable, "Enable Sun CS4231 soundcard.");
59MODULE_AUTHOR("Jaroslav Kysela, Derrick J. Brashear and David S. Miller");
60MODULE_DESCRIPTION("Sun CS4231");
61MODULE_LICENSE("GPL");
62MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}");
63
64typedef struct snd_cs4231 {
65 spinlock_t lock;
66 void __iomem *port;
67#ifdef EBUS_SUPPORT
68 struct ebus_dma_info eb2c;
69 struct ebus_dma_info eb2p;
70#endif
71
72 u32 flags;
73#define CS4231_FLAG_EBUS 0x00000001
74#define CS4231_FLAG_PLAYBACK 0x00000002
75#define CS4231_FLAG_CAPTURE 0x00000004
76
77 snd_card_t *card;
78 snd_pcm_t *pcm;
79 snd_pcm_substream_t *playback_substream;
80 unsigned int p_periods_sent;
81 snd_pcm_substream_t *capture_substream;
82 unsigned int c_periods_sent;
83 snd_timer_t *timer;
84
85 unsigned short mode;
86#define CS4231_MODE_NONE 0x0000
87#define CS4231_MODE_PLAY 0x0001
88#define CS4231_MODE_RECORD 0x0002
89#define CS4231_MODE_TIMER 0x0004
90#define CS4231_MODE_OPEN (CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER)
91
92 unsigned char image[32]; /* registers image */
93 int mce_bit;
94 int calibrate_mute;
95 struct semaphore mce_mutex;
96 struct semaphore open_mutex;
97
98 union {
99#ifdef SBUS_SUPPORT
100 struct sbus_dev *sdev;
101#endif
102#ifdef EBUS_SUPPORT
103 struct pci_dev *pdev;
104#endif
105 } dev_u;
106 unsigned int irq[2];
107 unsigned int regs_size;
108 struct snd_cs4231 *next;
109} cs4231_t;
110
111static cs4231_t *cs4231_list;
112
113/* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for
114 * now.... -DaveM
115 */
116
117/* IO ports */
118
119#define CS4231P(chip, x) ((chip)->port + c_d_c_CS4231##x)
120
121/* XXX offsets are different than PC ISA chips... */
122#define c_d_c_CS4231REGSEL 0x0
123#define c_d_c_CS4231REG 0x4
124#define c_d_c_CS4231STATUS 0x8
125#define c_d_c_CS4231PIO 0xc
126
127/* codec registers */
128
129#define CS4231_LEFT_INPUT 0x00 /* left input control */
130#define CS4231_RIGHT_INPUT 0x01 /* right input control */
131#define CS4231_AUX1_LEFT_INPUT 0x02 /* left AUX1 input control */
132#define CS4231_AUX1_RIGHT_INPUT 0x03 /* right AUX1 input control */
133#define CS4231_AUX2_LEFT_INPUT 0x04 /* left AUX2 input control */
134#define CS4231_AUX2_RIGHT_INPUT 0x05 /* right AUX2 input control */
135#define CS4231_LEFT_OUTPUT 0x06 /* left output control register */
136#define CS4231_RIGHT_OUTPUT 0x07 /* right output control register */
137#define CS4231_PLAYBK_FORMAT 0x08 /* clock and data format - playback - bits 7-0 MCE */
138#define CS4231_IFACE_CTRL 0x09 /* interface control - bits 7-2 MCE */
139#define CS4231_PIN_CTRL 0x0a /* pin control */
140#define CS4231_TEST_INIT 0x0b /* test and initialization */
141#define CS4231_MISC_INFO 0x0c /* miscellaneaous information */
142#define CS4231_LOOPBACK 0x0d /* loopback control */
143#define CS4231_PLY_UPR_CNT 0x0e /* playback upper base count */
144#define CS4231_PLY_LWR_CNT 0x0f /* playback lower base count */
145#define CS4231_ALT_FEATURE_1 0x10 /* alternate #1 feature enable */
146#define CS4231_ALT_FEATURE_2 0x11 /* alternate #2 feature enable */
147#define CS4231_LEFT_LINE_IN 0x12 /* left line input control */
148#define CS4231_RIGHT_LINE_IN 0x13 /* right line input control */
149#define CS4231_TIMER_LOW 0x14 /* timer low byte */
150#define CS4231_TIMER_HIGH 0x15 /* timer high byte */
151#define CS4231_LEFT_MIC_INPUT 0x16 /* left MIC input control register (InterWave only) */
152#define CS4231_RIGHT_MIC_INPUT 0x17 /* right MIC input control register (InterWave only) */
153#define CS4236_EXT_REG 0x17 /* extended register access */
154#define CS4231_IRQ_STATUS 0x18 /* irq status register */
155#define CS4231_LINE_LEFT_OUTPUT 0x19 /* left line output control register (InterWave only) */
156#define CS4231_VERSION 0x19 /* CS4231(A) - version values */
157#define CS4231_MONO_CTRL 0x1a /* mono input/output control */
158#define CS4231_LINE_RIGHT_OUTPUT 0x1b /* right line output control register (InterWave only) */
159#define CS4235_LEFT_MASTER 0x1b /* left master output control */
160#define CS4231_REC_FORMAT 0x1c /* clock and data format - record - bits 7-0 MCE */
161#define CS4231_PLY_VAR_FREQ 0x1d /* playback variable frequency */
162#define CS4235_RIGHT_MASTER 0x1d /* right master output control */
163#define CS4231_REC_UPR_CNT 0x1e /* record upper count */
164#define CS4231_REC_LWR_CNT 0x1f /* record lower count */
165
166/* definitions for codec register select port - CODECP( REGSEL ) */
167
168#define CS4231_INIT 0x80 /* CODEC is initializing */
169#define CS4231_MCE 0x40 /* mode change enable */
170#define CS4231_TRD 0x20 /* transfer request disable */
171
172/* definitions for codec status register - CODECP( STATUS ) */
173
174#define CS4231_GLOBALIRQ 0x01 /* IRQ is active */
175
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700176/* definitions for codec irq status - CS4231_IRQ_STATUS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178#define CS4231_PLAYBACK_IRQ 0x10
179#define CS4231_RECORD_IRQ 0x20
180#define CS4231_TIMER_IRQ 0x40
181#define CS4231_ALL_IRQS 0x70
182#define CS4231_REC_UNDERRUN 0x08
183#define CS4231_REC_OVERRUN 0x04
184#define CS4231_PLY_OVERRUN 0x02
185#define CS4231_PLY_UNDERRUN 0x01
186
187/* definitions for CS4231_LEFT_INPUT and CS4231_RIGHT_INPUT registers */
188
189#define CS4231_ENABLE_MIC_GAIN 0x20
190
191#define CS4231_MIXS_LINE 0x00
192#define CS4231_MIXS_AUX1 0x40
193#define CS4231_MIXS_MIC 0x80
194#define CS4231_MIXS_ALL 0xc0
195
196/* definitions for clock and data format register - CS4231_PLAYBK_FORMAT */
197
198#define CS4231_LINEAR_8 0x00 /* 8-bit unsigned data */
199#define CS4231_ALAW_8 0x60 /* 8-bit A-law companded */
200#define CS4231_ULAW_8 0x20 /* 8-bit U-law companded */
201#define CS4231_LINEAR_16 0x40 /* 16-bit twos complement data - little endian */
202#define CS4231_LINEAR_16_BIG 0xc0 /* 16-bit twos complement data - big endian */
203#define CS4231_ADPCM_16 0xa0 /* 16-bit ADPCM */
204#define CS4231_STEREO 0x10 /* stereo mode */
205/* bits 3-1 define frequency divisor */
206#define CS4231_XTAL1 0x00 /* 24.576 crystal */
207#define CS4231_XTAL2 0x01 /* 16.9344 crystal */
208
209/* definitions for interface control register - CS4231_IFACE_CTRL */
210
211#define CS4231_RECORD_PIO 0x80 /* record PIO enable */
212#define CS4231_PLAYBACK_PIO 0x40 /* playback PIO enable */
213#define CS4231_CALIB_MODE 0x18 /* calibration mode bits */
214#define CS4231_AUTOCALIB 0x08 /* auto calibrate */
215#define CS4231_SINGLE_DMA 0x04 /* use single DMA channel */
216#define CS4231_RECORD_ENABLE 0x02 /* record enable */
217#define CS4231_PLAYBACK_ENABLE 0x01 /* playback enable */
218
219/* definitions for pin control register - CS4231_PIN_CTRL */
220
221#define CS4231_IRQ_ENABLE 0x02 /* enable IRQ */
222#define CS4231_XCTL1 0x40 /* external control #1 */
223#define CS4231_XCTL0 0x80 /* external control #0 */
224
225/* definitions for test and init register - CS4231_TEST_INIT */
226
227#define CS4231_CALIB_IN_PROGRESS 0x20 /* auto calibrate in progress */
228#define CS4231_DMA_REQUEST 0x10 /* DMA request in progress */
229
230/* definitions for misc control register - CS4231_MISC_INFO */
231
232#define CS4231_MODE2 0x40 /* MODE 2 */
233#define CS4231_IW_MODE3 0x6c /* MODE 3 - InterWave enhanced mode */
234#define CS4231_4236_MODE3 0xe0 /* MODE 3 - CS4236+ enhanced mode */
235
236/* definitions for alternate feature 1 register - CS4231_ALT_FEATURE_1 */
237
238#define CS4231_DACZ 0x01 /* zero DAC when underrun */
239#define CS4231_TIMER_ENABLE 0x40 /* codec timer enable */
240#define CS4231_OLB 0x80 /* output level bit */
241
242/* SBUS DMA register defines. */
243
244#define APCCSR 0x10UL /* APC DMA CSR */
245#define APCCVA 0x20UL /* APC Capture DMA Address */
246#define APCCC 0x24UL /* APC Capture Count */
247#define APCCNVA 0x28UL /* APC Capture DMA Next Address */
248#define APCCNC 0x2cUL /* APC Capture Next Count */
249#define APCPVA 0x30UL /* APC Play DMA Address */
250#define APCPC 0x34UL /* APC Play Count */
251#define APCPNVA 0x38UL /* APC Play DMA Next Address */
252#define APCPNC 0x3cUL /* APC Play Next Count */
253
254/* APCCSR bits */
255
256#define APC_INT_PENDING 0x800000 /* Interrupt Pending */
257#define APC_PLAY_INT 0x400000 /* Playback interrupt */
258#define APC_CAPT_INT 0x200000 /* Capture interrupt */
259#define APC_GENL_INT 0x100000 /* General interrupt */
260#define APC_XINT_ENA 0x80000 /* General ext int. enable */
261#define APC_XINT_PLAY 0x40000 /* Playback ext intr */
262#define APC_XINT_CAPT 0x20000 /* Capture ext intr */
263#define APC_XINT_GENL 0x10000 /* Error ext intr */
264#define APC_XINT_EMPT 0x8000 /* Pipe empty interrupt (0 write to pva) */
265#define APC_XINT_PEMP 0x4000 /* Play pipe empty (pva and pnva not set) */
266#define APC_XINT_PNVA 0x2000 /* Playback NVA dirty */
267#define APC_XINT_PENA 0x1000 /* play pipe empty Int enable */
268#define APC_XINT_COVF 0x800 /* Cap data dropped on floor */
269#define APC_XINT_CNVA 0x400 /* Capture NVA dirty */
270#define APC_XINT_CEMP 0x200 /* Capture pipe empty (cva and cnva not set) */
271#define APC_XINT_CENA 0x100 /* Cap. pipe empty int enable */
272#define APC_PPAUSE 0x80 /* Pause the play DMA */
273#define APC_CPAUSE 0x40 /* Pause the capture DMA */
274#define APC_CDC_RESET 0x20 /* CODEC RESET */
275#define APC_PDMA_READY 0x08 /* Play DMA Go */
276#define APC_CDMA_READY 0x04 /* Capture DMA Go */
277#define APC_CHIP_RESET 0x01 /* Reset the chip */
278
279/* EBUS DMA register offsets */
280
281#define EBDMA_CSR 0x00UL /* Control/Status */
282#define EBDMA_ADDR 0x04UL /* DMA Address */
283#define EBDMA_COUNT 0x08UL /* DMA Count */
284
285/*
286 * Some variables
287 */
288
289static unsigned char freq_bits[14] = {
290 /* 5510 */ 0x00 | CS4231_XTAL2,
291 /* 6620 */ 0x0E | CS4231_XTAL2,
292 /* 8000 */ 0x00 | CS4231_XTAL1,
293 /* 9600 */ 0x0E | CS4231_XTAL1,
294 /* 11025 */ 0x02 | CS4231_XTAL2,
295 /* 16000 */ 0x02 | CS4231_XTAL1,
296 /* 18900 */ 0x04 | CS4231_XTAL2,
297 /* 22050 */ 0x06 | CS4231_XTAL2,
298 /* 27042 */ 0x04 | CS4231_XTAL1,
299 /* 32000 */ 0x06 | CS4231_XTAL1,
300 /* 33075 */ 0x0C | CS4231_XTAL2,
301 /* 37800 */ 0x08 | CS4231_XTAL2,
302 /* 44100 */ 0x0A | CS4231_XTAL2,
303 /* 48000 */ 0x0C | CS4231_XTAL1
304};
305
306static unsigned int rates[14] = {
307 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
308 27042, 32000, 33075, 37800, 44100, 48000
309};
310
311static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
312 .count = 14,
313 .list = rates,
314};
315
316static int snd_cs4231_xrate(snd_pcm_runtime_t *runtime)
317{
318 return snd_pcm_hw_constraint_list(runtime, 0,
319 SNDRV_PCM_HW_PARAM_RATE,
320 &hw_constraints_rates);
321}
322
323static unsigned char snd_cs4231_original_image[32] =
324{
325 0x00, /* 00/00 - lic */
326 0x00, /* 01/01 - ric */
327 0x9f, /* 02/02 - la1ic */
328 0x9f, /* 03/03 - ra1ic */
329 0x9f, /* 04/04 - la2ic */
330 0x9f, /* 05/05 - ra2ic */
331 0xbf, /* 06/06 - loc */
332 0xbf, /* 07/07 - roc */
333 0x20, /* 08/08 - pdfr */
334 CS4231_AUTOCALIB, /* 09/09 - ic */
335 0x00, /* 0a/10 - pc */
336 0x00, /* 0b/11 - ti */
337 CS4231_MODE2, /* 0c/12 - mi */
338 0x00, /* 0d/13 - lbc */
339 0x00, /* 0e/14 - pbru */
340 0x00, /* 0f/15 - pbrl */
341 0x80, /* 10/16 - afei */
342 0x01, /* 11/17 - afeii */
343 0x9f, /* 12/18 - llic */
344 0x9f, /* 13/19 - rlic */
345 0x00, /* 14/20 - tlb */
346 0x00, /* 15/21 - thb */
347 0x00, /* 16/22 - la3mic/reserved */
348 0x00, /* 17/23 - ra3mic/reserved */
349 0x00, /* 18/24 - afs */
350 0x00, /* 19/25 - lamoc/version */
351 0x00, /* 1a/26 - mioc */
352 0x00, /* 1b/27 - ramoc/reserved */
353 0x20, /* 1c/28 - cdfr */
354 0x00, /* 1d/29 - res4 */
355 0x00, /* 1e/30 - cbru */
356 0x00, /* 1f/31 - cbrl */
357};
358
359static u8 __cs4231_readb(cs4231_t *cp, void __iomem *reg_addr)
360{
361#ifdef EBUS_SUPPORT
362 if (cp->flags & CS4231_FLAG_EBUS) {
363 return readb(reg_addr);
364 } else {
365#endif
366#ifdef SBUS_SUPPORT
367 return sbus_readb(reg_addr);
368#endif
369#ifdef EBUS_SUPPORT
370 }
371#endif
372}
373
374static void __cs4231_writeb(cs4231_t *cp, u8 val, void __iomem *reg_addr)
375{
376#ifdef EBUS_SUPPORT
377 if (cp->flags & CS4231_FLAG_EBUS) {
378 return writeb(val, reg_addr);
379 } else {
380#endif
381#ifdef SBUS_SUPPORT
382 return sbus_writeb(val, reg_addr);
383#endif
384#ifdef EBUS_SUPPORT
385 }
386#endif
387}
388
389/*
390 * Basic I/O functions
391 */
392
393static void snd_cs4231_outm(cs4231_t *chip, unsigned char reg,
394 unsigned char mask, unsigned char value)
395{
396 int timeout;
397 unsigned char tmp;
398
399 for (timeout = 250;
400 timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
401 timeout--)
402 udelay(100);
403#ifdef CONFIG_SND_DEBUG
404 if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700405 snd_printdd("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406#endif
407 if (chip->calibrate_mute) {
408 chip->image[reg] &= mask;
409 chip->image[reg] |= value;
410 } else {
411 __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
412 mb();
413 tmp = (chip->image[reg] & mask) | value;
414 __cs4231_writeb(chip, tmp, CS4231P(chip, REG));
415 chip->image[reg] = tmp;
416 mb();
417 }
418}
419
420static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char value)
421{
422 int timeout;
423
424 for (timeout = 250;
425 timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
426 timeout--)
427 udelay(100);
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700428#ifdef CONFIG_SND_DEBUG
429 if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
430 snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
431#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
433 __cs4231_writeb(chip, value, CS4231P(chip, REG));
434 mb();
435}
436
437static void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char value)
438{
439 int timeout;
440
441 for (timeout = 250;
442 timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
443 timeout--)
444 udelay(100);
445#ifdef CONFIG_SND_DEBUG
446 if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700447 snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448#endif
449 __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
450 __cs4231_writeb(chip, value, CS4231P(chip, REG));
451 chip->image[reg] = value;
452 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453}
454
455static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
456{
457 int timeout;
458 unsigned char ret;
459
460 for (timeout = 250;
461 timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
462 timeout--)
463 udelay(100);
464#ifdef CONFIG_SND_DEBUG
465 if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700466 snd_printdd("in: auto calibration time out - reg = 0x%x\n", reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467#endif
468 __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
469 mb();
470 ret = __cs4231_readb(chip, CS4231P(chip, REG));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 return ret;
472}
473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474/*
475 * CS4231 detection / MCE routines
476 */
477
478static void snd_cs4231_busy_wait(cs4231_t *chip)
479{
480 int timeout;
481
482 /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
483 for (timeout = 5; timeout > 0; timeout--)
484 __cs4231_readb(chip, CS4231P(chip, REGSEL));
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 /* end of cleanup sequence */
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700487 for (timeout = 500;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
489 timeout--)
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700490 udelay(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
493static void snd_cs4231_mce_up(cs4231_t *chip)
494{
495 unsigned long flags;
496 int timeout;
497
498 spin_lock_irqsave(&chip->lock, flags);
499 for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--)
500 udelay(100);
501#ifdef CONFIG_SND_DEBUG
502 if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700503 snd_printdd("mce_up - auto calibration time out (0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504#endif
505 chip->mce_bit |= CS4231_MCE;
506 timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
507 if (timeout == 0x80)
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700508 snd_printdd("mce_up [%p]: serious init problem - codec still busy\n", chip->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (!(timeout & CS4231_MCE))
510 __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
511 spin_unlock_irqrestore(&chip->lock, flags);
512}
513
514static void snd_cs4231_mce_down(cs4231_t *chip)
515{
516 unsigned long flags;
517 int timeout;
518
519 spin_lock_irqsave(&chip->lock, flags);
520 snd_cs4231_busy_wait(chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521#ifdef CONFIG_SND_DEBUG
522 if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700523 snd_printdd("mce_down [%p] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524#endif
525 chip->mce_bit &= ~CS4231_MCE;
526 timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
527 __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
528 if (timeout == 0x80)
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700529 snd_printdd("mce_down [%p]: serious init problem - codec still busy\n", chip->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if ((timeout & CS4231_MCE) == 0) {
531 spin_unlock_irqrestore(&chip->lock, flags);
532 return;
533 }
534 snd_cs4231_busy_wait(chip);
535
536 /* calibration process */
537
538 for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--)
539 udelay(100);
540 if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) {
541 snd_printd("cs4231_mce_down - auto calibration time out (1)\n");
542 spin_unlock_irqrestore(&chip->lock, flags);
543 return;
544 }
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 /* in 10ms increments, check condition, up to 250ms */
547 timeout = 25;
548 while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) {
549 spin_unlock_irqrestore(&chip->lock, flags);
550 if (--timeout < 0) {
551 snd_printk("mce_down - auto calibration time out (2)\n");
552 return;
553 }
554 msleep(10);
555 spin_lock_irqsave(&chip->lock, flags);
556 }
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700557
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 /* in 10ms increments, check condition, up to 100ms */
559 timeout = 10;
560 while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) {
561 spin_unlock_irqrestore(&chip->lock, flags);
562 if (--timeout < 0) {
563 snd_printk("mce_down - auto calibration time out (3)\n");
564 return;
565 }
566 msleep(10);
567 spin_lock_irqsave(&chip->lock, flags);
568 }
569 spin_unlock_irqrestore(&chip->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570}
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572#ifdef EBUS_SUPPORT
573static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent)
574{
575 snd_pcm_runtime_t *runtime = substream->runtime;
576
577 while (1) {
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700578 unsigned int period_size = snd_pcm_lib_period_bytes(substream);
579 unsigned int offset = period_size * (*periods_sent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700581 if (period_size >= (1 << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 BUG();
583
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700584 if (ebus_dma_request(p, runtime->dma_addr + offset, period_size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 (*periods_sent) = ((*periods_sent) + 1) % runtime->periods;
587 }
588}
589#endif
590
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700591#ifdef SBUS_SUPPORT
592static void snd_cs4231_sbus_advance_dma(snd_pcm_substream_t *substream, unsigned int *periods_sent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700594 cs4231_t *chip = snd_pcm_substream_chip(substream);
595 snd_pcm_runtime_t *runtime = substream->runtime;
596
597 unsigned int period_size = snd_pcm_lib_period_bytes(substream);
598 unsigned int offset = period_size * (*periods_sent % runtime->periods);
599
600 if (runtime->period_size > 0xffff + 1)
601 BUG();
602
603 switch (substream->stream) {
604 case SNDRV_PCM_STREAM_PLAYBACK:
605 sbus_writel(runtime->dma_addr + offset, chip->port + APCPNVA);
606 sbus_writel(period_size, chip->port + APCPNC);
607 break;
608 case SNDRV_PCM_STREAM_CAPTURE:
609 sbus_writel(runtime->dma_addr + offset, chip->port + APCCNVA);
610 sbus_writel(period_size, chip->port + APCCNC);
611 break;
612 }
613
614 (*periods_sent) = (*periods_sent + 1) % runtime->periods;
615}
616#endif
617
618static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what, int on)
619{
620 cs4231_t *chip = snd_pcm_substream_chip(substream);
621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622#ifdef EBUS_SUPPORT
623 if (chip->flags & CS4231_FLAG_EBUS) {
624 if (what & CS4231_PLAYBACK_ENABLE) {
625 if (on) {
626 ebus_dma_prepare(&chip->eb2p, 0);
627 ebus_dma_enable(&chip->eb2p, 1);
628 snd_cs4231_ebus_advance_dma(&chip->eb2p,
629 chip->playback_substream,
630 &chip->p_periods_sent);
631 } else {
632 ebus_dma_enable(&chip->eb2p, 0);
633 }
634 }
635 if (what & CS4231_RECORD_ENABLE) {
636 if (on) {
637 ebus_dma_prepare(&chip->eb2c, 1);
638 ebus_dma_enable(&chip->eb2c, 1);
639 snd_cs4231_ebus_advance_dma(&chip->eb2c,
640 chip->capture_substream,
641 &chip->c_periods_sent);
642 } else {
643 ebus_dma_enable(&chip->eb2c, 0);
644 }
645 }
646 } else {
647#endif
648#ifdef SBUS_SUPPORT
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700649 u32 csr = sbus_readl(chip->port + APCCSR);
650 /* I don't know why, but on sbus the period counter must
651 * only start counting after the first period is sent.
652 * Therefore this dummy thing.
653 */
654 unsigned int dummy = 0;
655
656 switch (what) {
657 case CS4231_PLAYBACK_ENABLE:
658 if (on) {
659 csr &= ~APC_XINT_PLAY;
660 sbus_writel(csr, chip->port + APCCSR);
661
662 csr &= ~APC_PPAUSE;
663 sbus_writel(csr, chip->port + APCCSR);
664
665 snd_cs4231_sbus_advance_dma(substream, &dummy);
666
667 csr |= APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
668 APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL |
669 APC_XINT_PENA | APC_PDMA_READY;
670 sbus_writel(csr, chip->port + APCCSR);
671 } else {
672 csr |= APC_PPAUSE;
673 sbus_writel(csr, chip->port + APCCSR);
674
675 csr &= ~APC_PDMA_READY;
676 sbus_writel(csr, chip->port + APCCSR);
677 }
678 break;
679 case CS4231_RECORD_ENABLE:
680 if (on) {
681 csr &= ~APC_XINT_CAPT;
682 sbus_writel(csr, chip->port + APCCSR);
683
684 csr &= ~APC_CPAUSE;
685 sbus_writel(csr, chip->port + APCCSR);
686
687 snd_cs4231_sbus_advance_dma(substream, &dummy);
688
689 csr |= APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
690 APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL |
691 APC_CDMA_READY;
692
693 sbus_writel(csr, chip->port + APCCSR);
694 } else {
695 csr |= APC_CPAUSE;
696 sbus_writel(csr, chip->port + APCCSR);
697
698 csr &= ~APC_CDMA_READY;
699 sbus_writel(csr, chip->port + APCCSR);
700 }
701 break;
702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703#endif
704#ifdef EBUS_SUPPORT
705 }
706#endif
707}
708
709static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
710{
711 cs4231_t *chip = snd_pcm_substream_chip(substream);
712 int result = 0;
713
714 switch (cmd) {
715 case SNDRV_PCM_TRIGGER_START:
716 case SNDRV_PCM_TRIGGER_STOP:
717 {
718 unsigned int what = 0;
719 snd_pcm_substream_t *s;
720 struct list_head *pos;
721 unsigned long flags;
722
723 snd_pcm_group_for_each(pos, substream) {
724 s = snd_pcm_group_substream_entry(pos);
725 if (s == chip->playback_substream) {
726 what |= CS4231_PLAYBACK_ENABLE;
727 snd_pcm_trigger_done(s, substream);
728 } else if (s == chip->capture_substream) {
729 what |= CS4231_RECORD_ENABLE;
730 snd_pcm_trigger_done(s, substream);
731 }
732 }
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 spin_lock_irqsave(&chip->lock, flags);
735 if (cmd == SNDRV_PCM_TRIGGER_START) {
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700736 cs4231_dma_trigger(substream, what, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 chip->image[CS4231_IFACE_CTRL] |= what;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 } else {
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700739 cs4231_dma_trigger(substream, what, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 chip->image[CS4231_IFACE_CTRL] &= ~what;
741 }
742 snd_cs4231_out(chip, CS4231_IFACE_CTRL,
743 chip->image[CS4231_IFACE_CTRL]);
744 spin_unlock_irqrestore(&chip->lock, flags);
745 break;
746 }
747 default:
748 result = -EINVAL;
749 break;
750 }
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return result;
753}
754
755/*
756 * CODEC I/O
757 */
758
759static unsigned char snd_cs4231_get_rate(unsigned int rate)
760{
761 int i;
762
763 for (i = 0; i < 14; i++)
764 if (rate == rates[i])
765 return freq_bits[i];
766 // snd_BUG();
767 return freq_bits[13];
768}
769
770static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int channels)
771{
772 unsigned char rformat;
773
774 rformat = CS4231_LINEAR_8;
775 switch (format) {
776 case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break;
777 case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break;
778 case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break;
779 case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break;
780 case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break;
781 }
782 if (channels > 1)
783 rformat |= CS4231_STEREO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return rformat;
785}
786
787static void snd_cs4231_calibrate_mute(cs4231_t *chip, int mute)
788{
789 unsigned long flags;
790
791 mute = mute ? 1 : 0;
792 spin_lock_irqsave(&chip->lock, flags);
793 if (chip->calibrate_mute == mute) {
794 spin_unlock_irqrestore(&chip->lock, flags);
795 return;
796 }
797 if (!mute) {
798 snd_cs4231_dout(chip, CS4231_LEFT_INPUT,
799 chip->image[CS4231_LEFT_INPUT]);
800 snd_cs4231_dout(chip, CS4231_RIGHT_INPUT,
801 chip->image[CS4231_RIGHT_INPUT]);
802 snd_cs4231_dout(chip, CS4231_LOOPBACK,
803 chip->image[CS4231_LOOPBACK]);
804 }
805 snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT,
806 mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);
807 snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT,
808 mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);
809 snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT,
810 mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);
811 snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT,
812 mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);
813 snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT,
814 mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);
815 snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT,
816 mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);
817 snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN,
818 mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);
819 snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN,
820 mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);
821 snd_cs4231_dout(chip, CS4231_MONO_CTRL,
822 mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
823 chip->calibrate_mute = mute;
824 spin_unlock_irqrestore(&chip->lock, flags);
825}
826
827static void snd_cs4231_playback_format(cs4231_t *chip, snd_pcm_hw_params_t *params,
828 unsigned char pdfr)
829{
830 unsigned long flags;
831
832 down(&chip->mce_mutex);
833 snd_cs4231_calibrate_mute(chip, 1);
834
835 snd_cs4231_mce_up(chip);
836
837 spin_lock_irqsave(&chip->lock, flags);
838 snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
839 (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?
840 (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :
841 pdfr);
842 spin_unlock_irqrestore(&chip->lock, flags);
843
844 snd_cs4231_mce_down(chip);
845
846 snd_cs4231_calibrate_mute(chip, 0);
847 up(&chip->mce_mutex);
848}
849
850static void snd_cs4231_capture_format(cs4231_t *chip, snd_pcm_hw_params_t *params,
851 unsigned char cdfr)
852{
853 unsigned long flags;
854
855 down(&chip->mce_mutex);
856 snd_cs4231_calibrate_mute(chip, 1);
857
858 snd_cs4231_mce_up(chip);
859
860 spin_lock_irqsave(&chip->lock, flags);
861 if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
862 snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
863 ((chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |
864 (cdfr & 0x0f));
865 spin_unlock_irqrestore(&chip->lock, flags);
866 snd_cs4231_mce_down(chip);
867 snd_cs4231_mce_up(chip);
868 spin_lock_irqsave(&chip->lock, flags);
869 }
870 snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);
871 spin_unlock_irqrestore(&chip->lock, flags);
872
873 snd_cs4231_mce_down(chip);
874
875 snd_cs4231_calibrate_mute(chip, 0);
876 up(&chip->mce_mutex);
877}
878
879/*
880 * Timer interface
881 */
882
883static unsigned long snd_cs4231_timer_resolution(snd_timer_t *timer)
884{
885 cs4231_t *chip = snd_timer_chip(timer);
886
887 return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
888}
889
890static int snd_cs4231_timer_start(snd_timer_t *timer)
891{
892 unsigned long flags;
893 unsigned int ticks;
894 cs4231_t *chip = snd_timer_chip(timer);
895
896 spin_lock_irqsave(&chip->lock, flags);
897 ticks = timer->sticks;
898 if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
899 (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
900 (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
901 snd_cs4231_out(chip, CS4231_TIMER_HIGH,
902 chip->image[CS4231_TIMER_HIGH] =
903 (unsigned char) (ticks >> 8));
904 snd_cs4231_out(chip, CS4231_TIMER_LOW,
905 chip->image[CS4231_TIMER_LOW] =
906 (unsigned char) ticks);
907 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,
908 chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE);
909 }
910 spin_unlock_irqrestore(&chip->lock, flags);
911
912 return 0;
913}
914
915static int snd_cs4231_timer_stop(snd_timer_t *timer)
916{
917 unsigned long flags;
918 cs4231_t *chip = snd_timer_chip(timer);
919
920 spin_lock_irqsave(&chip->lock, flags);
921 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,
922 chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE);
923 spin_unlock_irqrestore(&chip->lock, flags);
924
925 return 0;
926}
927
928static void snd_cs4231_init(cs4231_t *chip)
929{
930 unsigned long flags;
931
932 snd_cs4231_mce_down(chip);
933
934#ifdef SNDRV_DEBUG_MCE
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700935 snd_printdd("init: (1)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936#endif
937 snd_cs4231_mce_up(chip);
938 spin_lock_irqsave(&chip->lock, flags);
939 chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
940 CS4231_RECORD_ENABLE | CS4231_RECORD_PIO |
941 CS4231_CALIB_MODE);
942 chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
943 snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
944 spin_unlock_irqrestore(&chip->lock, flags);
945 snd_cs4231_mce_down(chip);
946
947#ifdef SNDRV_DEBUG_MCE
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700948 snd_printdd("init: (2)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949#endif
950
951 snd_cs4231_mce_up(chip);
952 spin_lock_irqsave(&chip->lock, flags);
953 snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
954 spin_unlock_irqrestore(&chip->lock, flags);
955 snd_cs4231_mce_down(chip);
956
957#ifdef SNDRV_DEBUG_MCE
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700958 snd_printdd("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959#endif
960
961 spin_lock_irqsave(&chip->lock, flags);
962 snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]);
963 spin_unlock_irqrestore(&chip->lock, flags);
964
965 snd_cs4231_mce_up(chip);
966 spin_lock_irqsave(&chip->lock, flags);
967 snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]);
968 spin_unlock_irqrestore(&chip->lock, flags);
969 snd_cs4231_mce_down(chip);
970
971#ifdef SNDRV_DEBUG_MCE
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700972 snd_printdd("init: (4)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973#endif
974
975 snd_cs4231_mce_up(chip);
976 spin_lock_irqsave(&chip->lock, flags);
977 snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);
978 spin_unlock_irqrestore(&chip->lock, flags);
979 snd_cs4231_mce_down(chip);
980
981#ifdef SNDRV_DEBUG_MCE
Christopher Zimmermanna1314302005-09-21 00:41:22 -0700982 snd_printdd("init: (5)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983#endif
984}
985
986static int snd_cs4231_open(cs4231_t *chip, unsigned int mode)
987{
988 unsigned long flags;
989
990 down(&chip->open_mutex);
991 if ((chip->mode & mode)) {
992 up(&chip->open_mutex);
993 return -EAGAIN;
994 }
995 if (chip->mode & CS4231_MODE_OPEN) {
996 chip->mode |= mode;
997 up(&chip->open_mutex);
998 return 0;
999 }
1000 /* ok. now enable and ack CODEC IRQ */
1001 spin_lock_irqsave(&chip->lock, flags);
1002 snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
1003 CS4231_RECORD_IRQ |
1004 CS4231_TIMER_IRQ);
1005 snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
1006 __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
1007 __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
1008
1009 snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
1010 CS4231_RECORD_IRQ |
1011 CS4231_TIMER_IRQ);
1012 snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 spin_unlock_irqrestore(&chip->lock, flags);
1015
1016 chip->mode = mode;
1017 up(&chip->open_mutex);
1018 return 0;
1019}
1020
1021static void snd_cs4231_close(cs4231_t *chip, unsigned int mode)
1022{
1023 unsigned long flags;
1024
1025 down(&chip->open_mutex);
1026 chip->mode &= ~mode;
1027 if (chip->mode & CS4231_MODE_OPEN) {
1028 up(&chip->open_mutex);
1029 return;
1030 }
1031 snd_cs4231_calibrate_mute(chip, 1);
1032
1033 /* disable IRQ */
1034 spin_lock_irqsave(&chip->lock, flags);
1035 snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
1036 __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
1037 __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
1038
1039 /* now disable record & playback */
1040
1041 if (chip->image[CS4231_IFACE_CTRL] &
1042 (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
1043 CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
1044 spin_unlock_irqrestore(&chip->lock, flags);
1045 snd_cs4231_mce_up(chip);
1046 spin_lock_irqsave(&chip->lock, flags);
1047 chip->image[CS4231_IFACE_CTRL] &=
1048 ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
1049 CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
1050 snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
1051 spin_unlock_irqrestore(&chip->lock, flags);
1052 snd_cs4231_mce_down(chip);
1053 spin_lock_irqsave(&chip->lock, flags);
1054 }
1055
1056 /* clear IRQ again */
1057 snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
1058 __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
1059 __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */
1060 spin_unlock_irqrestore(&chip->lock, flags);
1061
1062 snd_cs4231_calibrate_mute(chip, 0);
1063
1064 chip->mode = 0;
1065 up(&chip->open_mutex);
1066}
1067
1068/*
1069 * timer open/close
1070 */
1071
1072static int snd_cs4231_timer_open(snd_timer_t *timer)
1073{
1074 cs4231_t *chip = snd_timer_chip(timer);
1075 snd_cs4231_open(chip, CS4231_MODE_TIMER);
1076 return 0;
1077}
1078
1079static int snd_cs4231_timer_close(snd_timer_t * timer)
1080{
1081 cs4231_t *chip = snd_timer_chip(timer);
1082 snd_cs4231_close(chip, CS4231_MODE_TIMER);
1083 return 0;
1084}
1085
1086static struct _snd_timer_hardware snd_cs4231_timer_table =
1087{
1088 .flags = SNDRV_TIMER_HW_AUTO,
1089 .resolution = 9945,
1090 .ticks = 65535,
1091 .open = snd_cs4231_timer_open,
1092 .close = snd_cs4231_timer_close,
1093 .c_resolution = snd_cs4231_timer_resolution,
1094 .start = snd_cs4231_timer_start,
1095 .stop = snd_cs4231_timer_stop,
1096};
1097
1098/*
1099 * ok.. exported functions..
1100 */
1101
1102static int snd_cs4231_playback_hw_params(snd_pcm_substream_t *substream,
1103 snd_pcm_hw_params_t *hw_params)
1104{
1105 cs4231_t *chip = snd_pcm_substream_chip(substream);
1106 unsigned char new_pdfr;
1107 int err;
1108
1109 if ((err = snd_pcm_lib_malloc_pages(substream,
1110 params_buffer_bytes(hw_params))) < 0)
1111 return err;
1112 new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params),
1113 params_channels(hw_params)) |
1114 snd_cs4231_get_rate(params_rate(hw_params));
1115 snd_cs4231_playback_format(chip, hw_params, new_pdfr);
1116
1117 return 0;
1118}
1119
1120static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream)
1121{
1122 return snd_pcm_lib_free_pages(substream);
1123}
1124
1125static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream)
1126{
1127 cs4231_t *chip = snd_pcm_substream_chip(substream);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001128 snd_pcm_runtime_t *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 unsigned long flags;
1130
1131 spin_lock_irqsave(&chip->lock, flags);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
1134 CS4231_PLAYBACK_PIO);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001135
1136 if (runtime->period_size > 0xffff + 1)
1137 BUG();
1138
1139 snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
1140 snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
1141 chip->p_periods_sent = 0;
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 spin_unlock_irqrestore(&chip->lock, flags);
1144
1145 return 0;
1146}
1147
1148static int snd_cs4231_capture_hw_params(snd_pcm_substream_t *substream,
1149 snd_pcm_hw_params_t *hw_params)
1150{
1151 cs4231_t *chip = snd_pcm_substream_chip(substream);
1152 unsigned char new_cdfr;
1153 int err;
1154
1155 if ((err = snd_pcm_lib_malloc_pages(substream,
1156 params_buffer_bytes(hw_params))) < 0)
1157 return err;
1158 new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params),
1159 params_channels(hw_params)) |
1160 snd_cs4231_get_rate(params_rate(hw_params));
1161 snd_cs4231_capture_format(chip, hw_params, new_cdfr);
1162
1163 return 0;
1164}
1165
1166static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream)
1167{
1168 return snd_pcm_lib_free_pages(substream);
1169}
1170
1171static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
1172{
1173 cs4231_t *chip = snd_pcm_substream_chip(substream);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001174 snd_pcm_runtime_t *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 unsigned long flags;
1176
1177 spin_lock_irqsave(&chip->lock, flags);
1178 chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
1179 CS4231_RECORD_PIO);
1180
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001181 snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
1182 snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
1183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 spin_unlock_irqrestore(&chip->lock, flags);
1185
1186 return 0;
1187}
1188
1189static void snd_cs4231_overrange(cs4231_t *chip)
1190{
1191 unsigned long flags;
1192 unsigned char res;
1193
1194 spin_lock_irqsave(&chip->lock, flags);
1195 res = snd_cs4231_in(chip, CS4231_TEST_INIT);
1196 spin_unlock_irqrestore(&chip->lock, flags);
1197
1198 if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */
1199 chip->capture_substream->runtime->overrange++;
1200}
1201
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001202static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203{
1204 unsigned long flags;
1205 unsigned char status;
1206
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001207 /*This is IRQ is not raised by the cs4231*/
1208 if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
1209 return IRQ_NONE;
1210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 if (status & CS4231_TIMER_IRQ) {
1214 if (chip->timer)
1215 snd_timer_interrupt(chip->timer, chip->timer->sticks);
1216 }
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001217
1218 if (status & CS4231_RECORD_IRQ)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 snd_cs4231_overrange(chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 /* ACK the CS4231 interrupt. */
1222 spin_lock_irqsave(&chip->lock, flags);
1223 snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
1224 spin_unlock_irqrestore(&chip->lock, flags);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001225
1226 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227}
1228
1229#ifdef SBUS_SUPPORT
1230static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1231{
1232 cs4231_t *chip = dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234 /* ACK the APC interrupt. */
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001235 u32 csr = sbus_readl(chip->port + APCCSR);
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 sbus_writel(csr, chip->port + APCCSR);
1238
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001239 if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) &&
1240 (csr & APC_PLAY_INT) &&
1241 (csr & APC_XINT_PNVA) &&
1242 !(csr & APC_XINT_EMPT)) {
1243 snd_cs4231_sbus_advance_dma(chip->playback_substream,
1244 &chip->p_periods_sent);
1245 snd_pcm_period_elapsed(chip->playback_substream);
1246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001248 if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) &&
1249 (csr & APC_CAPT_INT) &&
1250 (csr & APC_XINT_CNVA)) {
1251 snd_cs4231_sbus_advance_dma(chip->capture_substream,
1252 &chip->c_periods_sent);
1253 snd_pcm_period_elapsed(chip->capture_substream);
1254 }
1255
1256 return snd_cs4231_generic_interrupt(chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257}
1258#endif
1259
1260#ifdef EBUS_SUPPORT
1261static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie)
1262{
1263 cs4231_t *chip = cookie;
1264
1265 if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) {
1266 snd_pcm_period_elapsed(chip->playback_substream);
1267 snd_cs4231_ebus_advance_dma(p, chip->playback_substream,
1268 &chip->p_periods_sent);
1269 }
1270}
1271
1272static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie)
1273{
1274 cs4231_t *chip = cookie;
1275
1276 if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) {
1277 snd_pcm_period_elapsed(chip->capture_substream);
1278 snd_cs4231_ebus_advance_dma(p, chip->capture_substream,
1279 &chip->c_periods_sent);
1280 }
1281}
1282#endif
1283
1284static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream)
1285{
1286 cs4231_t *chip = snd_pcm_substream_chip(substream);
1287 size_t ptr, residue, period_bytes;
1288
1289 if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
1290 return 0;
1291 period_bytes = snd_pcm_lib_period_bytes(substream);
1292 ptr = period_bytes * chip->p_periods_sent;
1293#ifdef EBUS_SUPPORT
1294 if (chip->flags & CS4231_FLAG_EBUS) {
1295 residue = ebus_dma_residue(&chip->eb2p);
1296 } else {
1297#endif
1298#ifdef SBUS_SUPPORT
1299 residue = sbus_readl(chip->port + APCPC);
1300#endif
1301#ifdef EBUS_SUPPORT
1302 }
1303#endif
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001304 ptr += period_bytes - residue;
1305
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 return bytes_to_frames(substream->runtime, ptr);
1307}
1308
1309static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream)
1310{
1311 cs4231_t *chip = snd_pcm_substream_chip(substream);
1312 size_t ptr, residue, period_bytes;
1313
1314 if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
1315 return 0;
1316 period_bytes = snd_pcm_lib_period_bytes(substream);
1317 ptr = period_bytes * chip->c_periods_sent;
1318#ifdef EBUS_SUPPORT
1319 if (chip->flags & CS4231_FLAG_EBUS) {
1320 residue = ebus_dma_residue(&chip->eb2c);
1321 } else {
1322#endif
1323#ifdef SBUS_SUPPORT
1324 residue = sbus_readl(chip->port + APCCC);
1325#endif
1326#ifdef EBUS_SUPPORT
1327 }
1328#endif
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001329 ptr += period_bytes - residue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 return bytes_to_frames(substream->runtime, ptr);
1331}
1332
1333/*
1334
1335 */
1336
1337static int snd_cs4231_probe(cs4231_t *chip)
1338{
1339 unsigned long flags;
1340 int i, id, vers;
1341 unsigned char *ptr;
1342
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 id = vers = 0;
1344 for (i = 0; i < 50; i++) {
1345 mb();
1346 if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
1347 udelay(2000);
1348 else {
1349 spin_lock_irqsave(&chip->lock, flags);
1350 snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
1351 id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;
1352 vers = snd_cs4231_in(chip, CS4231_VERSION);
1353 spin_unlock_irqrestore(&chip->lock, flags);
1354 if (id == 0x0a)
1355 break; /* this is valid value */
1356 }
1357 }
1358 snd_printdd("cs4231: port = %p, id = 0x%x\n", chip->port, id);
1359 if (id != 0x0a)
1360 return -ENODEV; /* no valid device found */
1361
1362 spin_lock_irqsave(&chip->lock, flags);
1363
1364
1365 /* Reset DMA engine. */
1366#ifdef EBUS_SUPPORT
1367 if (chip->flags & CS4231_FLAG_EBUS) {
1368 /* Done by ebus_dma_register */
1369 } else {
1370#endif
1371#ifdef SBUS_SUPPORT
1372 sbus_writel(APC_CHIP_RESET, chip->port + APCCSR);
1373 sbus_writel(0x00, chip->port + APCCSR);
1374 sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET,
1375 chip->port + APCCSR);
1376
1377 udelay(20);
1378
1379 sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET,
1380 chip->port + APCCSR);
1381 sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA |
1382 APC_XINT_PENA |
1383 APC_XINT_CENA),
1384 chip->port + APCCSR);
1385#endif
1386#ifdef EBUS_SUPPORT
1387 }
1388#endif
1389
1390 __cs4231_readb(chip, CS4231P(chip, STATUS)); /* clear any pendings IRQ */
1391 __cs4231_writeb(chip, 0, CS4231P(chip, STATUS));
1392 mb();
1393
1394 spin_unlock_irqrestore(&chip->lock, flags);
1395
1396 chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
1397 chip->image[CS4231_IFACE_CTRL] =
1398 chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA;
1399 chip->image[CS4231_ALT_FEATURE_1] = 0x80;
1400 chip->image[CS4231_ALT_FEATURE_2] = 0x01;
1401 if (vers & 0x20)
1402 chip->image[CS4231_ALT_FEATURE_2] |= 0x02;
1403
1404 ptr = (unsigned char *) &chip->image;
1405
1406 snd_cs4231_mce_down(chip);
1407
1408 spin_lock_irqsave(&chip->lock, flags);
1409
1410 for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */
1411 snd_cs4231_out(chip, i, *ptr++);
1412
1413 spin_unlock_irqrestore(&chip->lock, flags);
1414
1415 snd_cs4231_mce_up(chip);
1416
1417 snd_cs4231_mce_down(chip);
1418
1419 mdelay(2);
1420
1421 return 0; /* all things are ok.. */
1422}
1423
1424static snd_pcm_hardware_t snd_cs4231_playback =
1425{
1426 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
1427 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
1428 .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
1429 SNDRV_PCM_FMTBIT_IMA_ADPCM |
1430 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
1431 SNDRV_PCM_FMTBIT_S16_BE),
1432 .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
1433 .rate_min = 5510,
1434 .rate_max = 48000,
1435 .channels_min = 1,
1436 .channels_max = 2,
1437 .buffer_bytes_max = (32*1024),
1438 .period_bytes_min = 4096,
1439 .period_bytes_max = (32*1024),
1440 .periods_min = 1,
1441 .periods_max = 1024,
1442};
1443
1444static snd_pcm_hardware_t snd_cs4231_capture =
1445{
1446 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
1447 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
1448 .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
1449 SNDRV_PCM_FMTBIT_IMA_ADPCM |
1450 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
1451 SNDRV_PCM_FMTBIT_S16_BE),
1452 .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
1453 .rate_min = 5510,
1454 .rate_max = 48000,
1455 .channels_min = 1,
1456 .channels_max = 2,
1457 .buffer_bytes_max = (32*1024),
1458 .period_bytes_min = 4096,
1459 .period_bytes_max = (32*1024),
1460 .periods_min = 1,
1461 .periods_max = 1024,
1462};
1463
1464static int snd_cs4231_playback_open(snd_pcm_substream_t *substream)
1465{
1466 cs4231_t *chip = snd_pcm_substream_chip(substream);
1467 snd_pcm_runtime_t *runtime = substream->runtime;
1468 int err;
1469
1470 runtime->hw = snd_cs4231_playback;
1471
1472 if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {
1473 snd_free_pages(runtime->dma_area, runtime->dma_bytes);
1474 return err;
1475 }
1476 chip->playback_substream = substream;
1477 chip->p_periods_sent = 0;
1478 snd_pcm_set_sync(substream);
1479 snd_cs4231_xrate(runtime);
1480
1481 return 0;
1482}
1483
1484static int snd_cs4231_capture_open(snd_pcm_substream_t *substream)
1485{
1486 cs4231_t *chip = snd_pcm_substream_chip(substream);
1487 snd_pcm_runtime_t *runtime = substream->runtime;
1488 int err;
1489
1490 runtime->hw = snd_cs4231_capture;
1491
1492 if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {
1493 snd_free_pages(runtime->dma_area, runtime->dma_bytes);
1494 return err;
1495 }
1496 chip->capture_substream = substream;
1497 chip->c_periods_sent = 0;
1498 snd_pcm_set_sync(substream);
1499 snd_cs4231_xrate(runtime);
1500
1501 return 0;
1502}
1503
1504static int snd_cs4231_playback_close(snd_pcm_substream_t *substream)
1505{
1506 cs4231_t *chip = snd_pcm_substream_chip(substream);
1507
1508 chip->playback_substream = NULL;
1509 snd_cs4231_close(chip, CS4231_MODE_PLAY);
1510
1511 return 0;
1512}
1513
1514static int snd_cs4231_capture_close(snd_pcm_substream_t *substream)
1515{
1516 cs4231_t *chip = snd_pcm_substream_chip(substream);
1517
1518 chip->capture_substream = NULL;
1519 snd_cs4231_close(chip, CS4231_MODE_RECORD);
1520
1521 return 0;
1522}
1523
1524/* XXX We can do some power-management, in particular on EBUS using
1525 * XXX the audio AUXIO register...
1526 */
1527
1528static snd_pcm_ops_t snd_cs4231_playback_ops = {
1529 .open = snd_cs4231_playback_open,
1530 .close = snd_cs4231_playback_close,
1531 .ioctl = snd_pcm_lib_ioctl,
1532 .hw_params = snd_cs4231_playback_hw_params,
1533 .hw_free = snd_cs4231_playback_hw_free,
1534 .prepare = snd_cs4231_playback_prepare,
1535 .trigger = snd_cs4231_trigger,
1536 .pointer = snd_cs4231_playback_pointer,
1537};
1538
1539static snd_pcm_ops_t snd_cs4231_capture_ops = {
1540 .open = snd_cs4231_capture_open,
1541 .close = snd_cs4231_capture_close,
1542 .ioctl = snd_pcm_lib_ioctl,
1543 .hw_params = snd_cs4231_capture_hw_params,
1544 .hw_free = snd_cs4231_capture_hw_free,
1545 .prepare = snd_cs4231_capture_prepare,
1546 .trigger = snd_cs4231_trigger,
1547 .pointer = snd_cs4231_capture_pointer,
1548};
1549
1550static void snd_cs4231_pcm_free(snd_pcm_t *pcm)
1551{
1552 cs4231_t *chip = pcm->private_data;
1553 chip->pcm = NULL;
1554 snd_pcm_lib_preallocate_free_for_all(pcm);
1555}
1556
1557int snd_cs4231_pcm(cs4231_t *chip)
1558{
1559 snd_pcm_t *pcm;
1560 int err;
1561
1562 if ((err = snd_pcm_new(chip->card, "CS4231", 0, 1, 1, &pcm)) < 0)
1563 return err;
1564
1565 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);
1566 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);
1567
1568 /* global setup */
1569 pcm->private_data = chip;
1570 pcm->private_free = snd_cs4231_pcm_free;
1571 pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
1572 strcpy(pcm->name, "CS4231");
1573
1574#ifdef EBUS_SUPPORT
1575 if (chip->flags & CS4231_FLAG_EBUS) {
1576 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1577 snd_dma_pci_data(chip->dev_u.pdev),
1578 64*1024, 128*1024);
1579 } else {
1580#endif
1581#ifdef SBUS_SUPPORT
1582 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
1583 snd_dma_sbus_data(chip->dev_u.sdev),
1584 64*1024, 128*1024);
1585#endif
1586#ifdef EBUS_SUPPORT
1587 }
1588#endif
1589
1590 chip->pcm = pcm;
1591
1592 return 0;
1593}
1594
1595static void snd_cs4231_timer_free(snd_timer_t *timer)
1596{
1597 cs4231_t *chip = timer->private_data;
1598 chip->timer = NULL;
1599}
1600
1601int snd_cs4231_timer(cs4231_t *chip)
1602{
1603 snd_timer_t *timer;
1604 snd_timer_id_t tid;
1605 int err;
1606
1607 /* Timer initialization */
1608 tid.dev_class = SNDRV_TIMER_CLASS_CARD;
1609 tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
1610 tid.card = chip->card->number;
1611 tid.device = 0;
1612 tid.subdevice = 0;
1613 if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
1614 return err;
1615 strcpy(timer->name, "CS4231");
1616 timer->private_data = chip;
1617 timer->private_free = snd_cs4231_timer_free;
1618 timer->hw = snd_cs4231_timer_table;
1619 chip->timer = timer;
1620
1621 return 0;
1622}
1623
1624/*
1625 * MIXER part
1626 */
1627
1628static int snd_cs4231_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
1629{
1630 static char *texts[4] = {
1631 "Line", "CD", "Mic", "Mix"
1632 };
1633 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1634
1635 snd_assert(chip->card != NULL, return -EINVAL);
1636 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1637 uinfo->count = 2;
1638 uinfo->value.enumerated.items = 4;
1639 if (uinfo->value.enumerated.item > 3)
1640 uinfo->value.enumerated.item = 3;
1641 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1642
1643 return 0;
1644}
1645
1646static int snd_cs4231_get_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1647{
1648 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1649 unsigned long flags;
1650
1651 spin_lock_irqsave(&chip->lock, flags);
1652 ucontrol->value.enumerated.item[0] =
1653 (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
1654 ucontrol->value.enumerated.item[1] =
1655 (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
1656 spin_unlock_irqrestore(&chip->lock, flags);
1657
1658 return 0;
1659}
1660
1661static int snd_cs4231_put_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1662{
1663 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1664 unsigned long flags;
1665 unsigned short left, right;
1666 int change;
1667
1668 if (ucontrol->value.enumerated.item[0] > 3 ||
1669 ucontrol->value.enumerated.item[1] > 3)
1670 return -EINVAL;
1671 left = ucontrol->value.enumerated.item[0] << 6;
1672 right = ucontrol->value.enumerated.item[1] << 6;
1673
1674 spin_lock_irqsave(&chip->lock, flags);
1675
1676 left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
1677 right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
1678 change = left != chip->image[CS4231_LEFT_INPUT] ||
1679 right != chip->image[CS4231_RIGHT_INPUT];
1680 snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);
1681 snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);
1682
1683 spin_unlock_irqrestore(&chip->lock, flags);
1684
1685 return change;
1686}
1687
1688int snd_cs4231_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
1689{
1690 int mask = (kcontrol->private_value >> 16) & 0xff;
1691
1692 uinfo->type = (mask == 1) ?
1693 SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1694 uinfo->count = 1;
1695 uinfo->value.integer.min = 0;
1696 uinfo->value.integer.max = mask;
1697
1698 return 0;
1699}
1700
1701int snd_cs4231_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1702{
1703 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1704 unsigned long flags;
1705 int reg = kcontrol->private_value & 0xff;
1706 int shift = (kcontrol->private_value >> 8) & 0xff;
1707 int mask = (kcontrol->private_value >> 16) & 0xff;
1708 int invert = (kcontrol->private_value >> 24) & 0xff;
1709
1710 spin_lock_irqsave(&chip->lock, flags);
1711
1712 ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
1713
1714 spin_unlock_irqrestore(&chip->lock, flags);
1715
1716 if (invert)
1717 ucontrol->value.integer.value[0] =
1718 (mask - ucontrol->value.integer.value[0]);
1719
1720 return 0;
1721}
1722
1723int snd_cs4231_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1724{
1725 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1726 unsigned long flags;
1727 int reg = kcontrol->private_value & 0xff;
1728 int shift = (kcontrol->private_value >> 8) & 0xff;
1729 int mask = (kcontrol->private_value >> 16) & 0xff;
1730 int invert = (kcontrol->private_value >> 24) & 0xff;
1731 int change;
1732 unsigned short val;
1733
1734 val = (ucontrol->value.integer.value[0] & mask);
1735 if (invert)
1736 val = mask - val;
1737 val <<= shift;
1738
1739 spin_lock_irqsave(&chip->lock, flags);
1740
1741 val = (chip->image[reg] & ~(mask << shift)) | val;
1742 change = val != chip->image[reg];
1743 snd_cs4231_out(chip, reg, val);
1744
1745 spin_unlock_irqrestore(&chip->lock, flags);
1746
1747 return change;
1748}
1749
1750int snd_cs4231_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
1751{
1752 int mask = (kcontrol->private_value >> 24) & 0xff;
1753
1754 uinfo->type = mask == 1 ?
1755 SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1756 uinfo->count = 2;
1757 uinfo->value.integer.min = 0;
1758 uinfo->value.integer.max = mask;
1759
1760 return 0;
1761}
1762
1763int snd_cs4231_get_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1764{
1765 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1766 unsigned long flags;
1767 int left_reg = kcontrol->private_value & 0xff;
1768 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1769 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1770 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1771 int mask = (kcontrol->private_value >> 24) & 0xff;
1772 int invert = (kcontrol->private_value >> 22) & 1;
1773
1774 spin_lock_irqsave(&chip->lock, flags);
1775
1776 ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
1777 ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
1778
1779 spin_unlock_irqrestore(&chip->lock, flags);
1780
1781 if (invert) {
1782 ucontrol->value.integer.value[0] =
1783 (mask - ucontrol->value.integer.value[0]);
1784 ucontrol->value.integer.value[1] =
1785 (mask - ucontrol->value.integer.value[1]);
1786 }
1787
1788 return 0;
1789}
1790
1791int snd_cs4231_put_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1792{
1793 cs4231_t *chip = snd_kcontrol_chip(kcontrol);
1794 unsigned long flags;
1795 int left_reg = kcontrol->private_value & 0xff;
1796 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1797 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1798 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1799 int mask = (kcontrol->private_value >> 24) & 0xff;
1800 int invert = (kcontrol->private_value >> 22) & 1;
1801 int change;
1802 unsigned short val1, val2;
1803
1804 val1 = ucontrol->value.integer.value[0] & mask;
1805 val2 = ucontrol->value.integer.value[1] & mask;
1806 if (invert) {
1807 val1 = mask - val1;
1808 val2 = mask - val2;
1809 }
1810 val1 <<= shift_left;
1811 val2 <<= shift_right;
1812
1813 spin_lock_irqsave(&chip->lock, flags);
1814
1815 val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
1816 val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
1817 change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
1818 snd_cs4231_out(chip, left_reg, val1);
1819 snd_cs4231_out(chip, right_reg, val2);
1820
1821 spin_unlock_irqrestore(&chip->lock, flags);
1822
1823 return change;
1824}
1825
1826#define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \
1827{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
1828 .info = snd_cs4231_info_single, \
1829 .get = snd_cs4231_get_single, .put = snd_cs4231_put_single, \
1830 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
1831
1832#define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
1833{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
1834 .info = snd_cs4231_info_double, \
1835 .get = snd_cs4231_get_double, .put = snd_cs4231_put_double, \
1836 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
1837
1838static snd_kcontrol_new_t snd_cs4231_controls[] = {
1839CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
1840CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
1841CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
1842CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
1843CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
1844CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
1845CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
1846CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
1847CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),
1848CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
1849CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),
1850CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
1851CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
1852{
1853 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1854 .name = "Capture Source",
1855 .info = snd_cs4231_info_mux,
1856 .get = snd_cs4231_get_mux,
1857 .put = snd_cs4231_put_mux,
1858},
1859CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
1860CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
1861CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1),
1862/* SPARC specific uses of XCTL{0,1} general purpose outputs. */
1863CS4231_SINGLE("Line Out Switch", 0, CS4231_PIN_CTRL, 6, 1, 1),
1864CS4231_SINGLE("Headphone Out Switch", 0, CS4231_PIN_CTRL, 7, 1, 1)
1865};
1866
1867int snd_cs4231_mixer(cs4231_t *chip)
1868{
1869 snd_card_t *card;
1870 int err, idx;
1871
1872 snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
1873
1874 card = chip->card;
1875
1876 strcpy(card->mixername, chip->pcm->name);
1877
1878 for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {
1879 if ((err = snd_ctl_add(card,
1880 snd_ctl_new1(&snd_cs4231_controls[idx],
1881 chip))) < 0)
1882 return err;
1883 }
1884 return 0;
1885}
1886
1887static int dev;
1888
1889static int cs4231_attach_begin(snd_card_t **rcard)
1890{
1891 snd_card_t *card;
1892
1893 *rcard = NULL;
1894
1895 if (dev >= SNDRV_CARDS)
1896 return -ENODEV;
1897
1898 if (!enable[dev]) {
1899 dev++;
1900 return -ENOENT;
1901 }
1902
1903 card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
1904 if (card == NULL)
1905 return -ENOMEM;
1906
1907 strcpy(card->driver, "CS4231");
1908 strcpy(card->shortname, "Sun CS4231");
1909
1910 *rcard = card;
1911 return 0;
1912}
1913
1914static int cs4231_attach_finish(snd_card_t *card, cs4231_t *chip)
1915{
1916 int err;
1917
1918 if ((err = snd_cs4231_pcm(chip)) < 0)
1919 goto out_err;
1920
1921 if ((err = snd_cs4231_mixer(chip)) < 0)
1922 goto out_err;
1923
1924 if ((err = snd_cs4231_timer(chip)) < 0)
1925 goto out_err;
1926
Takashi Iwai16dab542005-09-05 17:17:58 +02001927 if ((err = snd_card_set_generic_dev(card)) < 0)
1928 goto out_err;
1929
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 if ((err = snd_card_register(card)) < 0)
1931 goto out_err;
1932
1933 chip->next = cs4231_list;
1934 cs4231_list = chip;
1935
1936 dev++;
1937 return 0;
1938
1939out_err:
1940 snd_card_free(card);
1941 return err;
1942}
1943
1944#ifdef SBUS_SUPPORT
1945static int snd_cs4231_sbus_free(cs4231_t *chip)
1946{
1947 if (chip->irq[0])
1948 free_irq(chip->irq[0], chip);
1949
1950 if (chip->port)
1951 sbus_iounmap(chip->port, chip->regs_size);
1952
1953 if (chip->timer)
1954 snd_device_free(chip->card, chip->timer);
1955
1956 kfree(chip);
1957
1958 return 0;
1959}
1960
1961static int snd_cs4231_sbus_dev_free(snd_device_t *device)
1962{
1963 cs4231_t *cp = device->device_data;
1964
1965 return snd_cs4231_sbus_free(cp);
1966}
1967
1968static snd_device_ops_t snd_cs4231_sbus_dev_ops = {
1969 .dev_free = snd_cs4231_sbus_dev_free,
1970};
1971
1972static int __init snd_cs4231_sbus_create(snd_card_t *card,
1973 struct sbus_dev *sdev,
1974 int dev,
1975 cs4231_t **rchip)
1976{
1977 cs4231_t *chip;
1978 int err;
1979
1980 *rchip = NULL;
Takashi Iwai561b2202005-09-09 14:22:34 +02001981 chip = kzalloc(sizeof(*chip), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 if (chip == NULL)
1983 return -ENOMEM;
1984
1985 spin_lock_init(&chip->lock);
1986 init_MUTEX(&chip->mce_mutex);
1987 init_MUTEX(&chip->open_mutex);
1988 chip->card = card;
1989 chip->dev_u.sdev = sdev;
1990 chip->regs_size = sdev->reg_addrs[0].reg_size;
1991 memcpy(&chip->image, &snd_cs4231_original_image,
1992 sizeof(snd_cs4231_original_image));
1993
1994 chip->port = sbus_ioremap(&sdev->resource[0], 0,
1995 chip->regs_size, "cs4231");
1996 if (!chip->port) {
Christopher Zimmermanna1314302005-09-21 00:41:22 -07001997 snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 return -EIO;
1999 }
2000
2001 if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
2002 SA_SHIRQ, "cs4231", chip)) {
Christopher Zimmermanna1314302005-09-21 00:41:22 -07002003 snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 dev,
2005 __irq_itoa(sdev->irqs[0]));
2006 snd_cs4231_sbus_free(chip);
2007 return -EBUSY;
2008 }
2009 chip->irq[0] = sdev->irqs[0];
2010
2011 if (snd_cs4231_probe(chip) < 0) {
2012 snd_cs4231_sbus_free(chip);
2013 return -ENODEV;
2014 }
2015 snd_cs4231_init(chip);
2016
2017 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
2018 chip, &snd_cs4231_sbus_dev_ops)) < 0) {
2019 snd_cs4231_sbus_free(chip);
2020 return err;
2021 }
2022
2023 *rchip = chip;
2024 return 0;
2025}
2026
2027static int cs4231_sbus_attach(struct sbus_dev *sdev)
2028{
2029 struct resource *rp = &sdev->resource[0];
2030 cs4231_t *cp;
2031 snd_card_t *card;
2032 int err;
2033
2034 err = cs4231_attach_begin(&card);
2035 if (err)
2036 return err;
2037
2038 sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s",
2039 card->shortname,
2040 rp->flags & 0xffL,
2041 rp->start,
2042 __irq_itoa(sdev->irqs[0]));
2043
2044 if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) {
2045 snd_card_free(card);
2046 return err;
2047 }
2048
2049 return cs4231_attach_finish(card, cp);
2050}
2051#endif
2052
2053#ifdef EBUS_SUPPORT
2054static int snd_cs4231_ebus_free(cs4231_t *chip)
2055{
2056 if (chip->eb2c.regs) {
2057 ebus_dma_unregister(&chip->eb2c);
2058 iounmap(chip->eb2c.regs);
2059 }
2060 if (chip->eb2p.regs) {
2061 ebus_dma_unregister(&chip->eb2p);
2062 iounmap(chip->eb2p.regs);
2063 }
2064
2065 if (chip->port)
2066 iounmap(chip->port);
2067 if (chip->timer)
2068 snd_device_free(chip->card, chip->timer);
2069
2070 kfree(chip);
2071
2072 return 0;
2073}
2074
2075static int snd_cs4231_ebus_dev_free(snd_device_t *device)
2076{
2077 cs4231_t *cp = device->device_data;
2078
2079 return snd_cs4231_ebus_free(cp);
2080}
2081
2082static snd_device_ops_t snd_cs4231_ebus_dev_ops = {
2083 .dev_free = snd_cs4231_ebus_dev_free,
2084};
2085
2086static int __init snd_cs4231_ebus_create(snd_card_t *card,
2087 struct linux_ebus_device *edev,
2088 int dev,
2089 cs4231_t **rchip)
2090{
2091 cs4231_t *chip;
2092 int err;
2093
2094 *rchip = NULL;
Takashi Iwai561b2202005-09-09 14:22:34 +02002095 chip = kzalloc(sizeof(*chip), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 if (chip == NULL)
2097 return -ENOMEM;
2098
2099 spin_lock_init(&chip->lock);
2100 spin_lock_init(&chip->eb2c.lock);
2101 spin_lock_init(&chip->eb2p.lock);
2102 init_MUTEX(&chip->mce_mutex);
2103 init_MUTEX(&chip->open_mutex);
2104 chip->flags |= CS4231_FLAG_EBUS;
2105 chip->card = card;
2106 chip->dev_u.pdev = edev->bus->self;
2107 memcpy(&chip->image, &snd_cs4231_original_image,
2108 sizeof(snd_cs4231_original_image));
2109 strcpy(chip->eb2c.name, "cs4231(capture)");
2110 chip->eb2c.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
2111 chip->eb2c.callback = snd_cs4231_ebus_capture_callback;
2112 chip->eb2c.client_cookie = chip;
2113 chip->eb2c.irq = edev->irqs[0];
2114 strcpy(chip->eb2p.name, "cs4231(play)");
2115 chip->eb2p.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
2116 chip->eb2p.callback = snd_cs4231_ebus_play_callback;
2117 chip->eb2p.client_cookie = chip;
2118 chip->eb2p.irq = edev->irqs[1];
2119
2120 chip->port = ioremap(edev->resource[0].start, 0x10);
2121 chip->eb2p.regs = ioremap(edev->resource[1].start, 0x10);
2122 chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10);
2123 if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) {
2124 snd_cs4231_ebus_free(chip);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07002125 snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 return -EIO;
2127 }
2128
2129 if (ebus_dma_register(&chip->eb2c)) {
2130 snd_cs4231_ebus_free(chip);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07002131 snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 return -EBUSY;
2133 }
2134 if (ebus_dma_irq_enable(&chip->eb2c, 1)) {
2135 snd_cs4231_ebus_free(chip);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07002136 snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 return -EBUSY;
2138 }
2139
2140 if (ebus_dma_register(&chip->eb2p)) {
2141 snd_cs4231_ebus_free(chip);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07002142 snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 return -EBUSY;
2144 }
2145 if (ebus_dma_irq_enable(&chip->eb2p, 1)) {
2146 snd_cs4231_ebus_free(chip);
Christopher Zimmermanna1314302005-09-21 00:41:22 -07002147 snd_printdd("cs4231-%d: Unable to enable EBUS play IRQ\n", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 return -EBUSY;
2149 }
2150
2151 if (snd_cs4231_probe(chip) < 0) {
2152 snd_cs4231_ebus_free(chip);
2153 return -ENODEV;
2154 }
2155 snd_cs4231_init(chip);
2156
2157 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
2158 chip, &snd_cs4231_ebus_dev_ops)) < 0) {
2159 snd_cs4231_ebus_free(chip);
2160 return err;
2161 }
2162
2163 *rchip = chip;
2164 return 0;
2165}
2166
2167static int cs4231_ebus_attach(struct linux_ebus_device *edev)
2168{
2169 snd_card_t *card;
2170 cs4231_t *chip;
2171 int err;
2172
2173 err = cs4231_attach_begin(&card);
2174 if (err)
2175 return err;
2176
2177 sprintf(card->longname, "%s at 0x%lx, irq %s",
2178 card->shortname,
2179 edev->resource[0].start,
2180 __irq_itoa(edev->irqs[0]));
2181
2182 if ((err = snd_cs4231_ebus_create(card, edev, dev, &chip)) < 0) {
2183 snd_card_free(card);
2184 return err;
2185 }
2186
2187 return cs4231_attach_finish(card, chip);
2188}
2189#endif
2190
2191static int __init cs4231_init(void)
2192{
2193#ifdef SBUS_SUPPORT
2194 struct sbus_bus *sbus;
2195 struct sbus_dev *sdev;
2196#endif
2197#ifdef EBUS_SUPPORT
2198 struct linux_ebus *ebus;
2199 struct linux_ebus_device *edev;
2200#endif
2201 int found;
2202
2203 found = 0;
2204
2205#ifdef SBUS_SUPPORT
2206 for_all_sbusdev(sdev, sbus) {
2207 if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
2208 if (cs4231_sbus_attach(sdev) == 0)
2209 found++;
2210 }
2211 }
2212#endif
2213#ifdef EBUS_SUPPORT
2214 for_each_ebus(ebus) {
2215 for_each_ebusdev(edev, ebus) {
2216 int match = 0;
2217
2218 if (!strcmp(edev->prom_name, "SUNW,CS4231")) {
2219 match = 1;
2220 } else if (!strcmp(edev->prom_name, "audio")) {
2221 char compat[16];
2222
2223 prom_getstring(edev->prom_node, "compatible",
2224 compat, sizeof(compat));
2225 compat[15] = '\0';
2226 if (!strcmp(compat, "SUNW,CS4231"))
2227 match = 1;
2228 }
2229
2230 if (match &&
2231 cs4231_ebus_attach(edev) == 0)
2232 found++;
2233 }
2234 }
2235#endif
2236
2237
2238 return (found > 0) ? 0 : -EIO;
2239}
2240
2241static void __exit cs4231_exit(void)
2242{
2243 cs4231_t *p = cs4231_list;
2244
2245 while (p != NULL) {
2246 cs4231_t *next = p->next;
2247
2248 snd_card_free(p->card);
2249
2250 p = next;
2251 }
2252
2253 cs4231_list = NULL;
2254}
2255
2256module_init(cs4231_init);
2257module_exit(cs4231_exit);