Blame view

sound/sparc/cs4231.c 55.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * Driver for CS4231 sound chips found on Sparcs.
ae251031a   David S. Miller   cs4231: Convert S...
3
   * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
   *
   * Based entirely upon drivers/sbus/audio/cs4231.c which is:
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
6
   * Copyright (C) 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   * and also sound/isa/cs423x/cs4231_lib.c which is:
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
8
   * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
  #include <linux/module.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
  #include <linux/delay.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/moduleparam.h>
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
16
17
  #include <linux/irq.h>
  #include <linux/io.h>
ae251031a   David S. Miller   cs4231: Convert S...
18
19
  #include <linux/of.h>
  #include <linux/of_device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/info.h>
  #include <sound/control.h>
  #include <sound/timer.h>
  #include <sound/initval.h>
  #include <sound/pcm_params.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  #ifdef CONFIG_SBUS
  #define SBUS_SUPPORT
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
  #endif
  
  #if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
  #define EBUS_SUPPORT
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <linux/pci.h>
aae7fb87e   David S. Miller   sparc: Move EBUS ...
35
  #include <asm/ebus_dma.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
  #endif
  
  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
40
  /* Enable this card */
a67ff6a54   Rusty Russell   ALSA: module_para...
41
  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
51
52
  
  module_param_array(index, int, NULL, 0444);
  MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard.");
  module_param_array(id, charp, NULL, 0444);
  MODULE_PARM_DESC(id, "ID string for Sun CS4231 soundcard.");
  module_param_array(enable, bool, NULL, 0444);
  MODULE_PARM_DESC(enable, "Enable Sun CS4231 soundcard.");
  MODULE_AUTHOR("Jaroslav Kysela, Derrick J. Brashear and David S. Miller");
  MODULE_DESCRIPTION("Sun CS4231");
  MODULE_LICENSE("GPL");
  MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}");
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
53
  #ifdef SBUS_SUPPORT
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
54
  struct sbus_dma_info {
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
55
56
57
         spinlock_t	lock;	/* DMA access lock */
         int		dir;
         void __iomem	*regs;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
58
  };
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
59
  #endif
4f3f2f6f3   David S. Miller   [SOUND]: sparc/cs...
60
  struct snd_cs4231;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
61
  struct cs4231_dma_control {
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
62
63
64
65
66
67
  	void		(*prepare)(struct cs4231_dma_control *dma_cont,
  				   int dir);
  	void		(*enable)(struct cs4231_dma_control *dma_cont, int on);
  	int		(*request)(struct cs4231_dma_control *dma_cont,
  				   dma_addr_t bus_addr, size_t len);
  	unsigned int	(*address)(struct cs4231_dma_control *dma_cont);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  #ifdef EBUS_SUPPORT
b128254fd   Georg Chini   [SPARC]: More abs...
69
  	struct		ebus_dma_info	ebus_info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  #endif
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
71
  #ifdef SBUS_SUPPORT
b128254fd   Georg Chini   [SPARC]: More abs...
72
  	struct		sbus_dma_info	sbus_info;
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
73
  #endif
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
74
  };
b128254fd   Georg Chini   [SPARC]: More abs...
75
76
  
  struct snd_cs4231 {
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
77
  	spinlock_t		lock;	/* registers access lock */
b128254fd   Georg Chini   [SPARC]: More abs...
78
  	void __iomem		*port;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
79
80
  	struct cs4231_dma_control	p_dma;
  	struct cs4231_dma_control	c_dma;
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
81

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
  	u32			flags;
  #define CS4231_FLAG_EBUS	0x00000001
  #define CS4231_FLAG_PLAYBACK	0x00000002
  #define CS4231_FLAG_CAPTURE	0x00000004
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
86
87
88
  	struct snd_card		*card;
  	struct snd_pcm		*pcm;
  	struct snd_pcm_substream	*playback_substream;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  	unsigned int		p_periods_sent;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
90
  	struct snd_pcm_substream	*capture_substream;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  	unsigned int		c_periods_sent;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
92
  	struct snd_timer	*timer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
98
  
  	unsigned short mode;
  #define CS4231_MODE_NONE	0x0000
  #define CS4231_MODE_PLAY	0x0001
  #define CS4231_MODE_RECORD	0x0002
  #define CS4231_MODE_TIMER	0x0004
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
99
100
  #define CS4231_MODE_OPEN	(CS4231_MODE_PLAY | CS4231_MODE_RECORD | \
  				 CS4231_MODE_TIMER)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
  
  	unsigned char		image[32];	/* registers image */
  	int			mce_bit;
  	int			calibrate_mute;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
105
106
  	struct mutex		mce_mutex;	/* mutex for mce register */
  	struct mutex		open_mutex;	/* mutex for ALSA open/close */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107

2dc115813   Grant Likely   of/device: Replac...
108
  	struct platform_device	*op;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
  	unsigned int		irq[2];
  	unsigned int		regs_size;
  	struct snd_cs4231	*next;
b128254fd   Georg Chini   [SPARC]: More abs...
112
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
  /* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for
   * now....  -DaveM
   */
  
  /* IO ports */
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
119
  #include <sound/cs4231-regs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
  
  /* XXX offsets are different than PC ISA chips... */
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
122
  #define CS4231U(chip, x)	((chip)->port + ((c_d_c_CS4231##x) << 2))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
127
128
129
130
131
132
133
134
  
  /* SBUS DMA register defines.  */
  
  #define APCCSR	0x10UL	/* APC DMA CSR */
  #define APCCVA	0x20UL	/* APC Capture DMA Address */
  #define APCCC	0x24UL	/* APC Capture Count */
  #define APCCNVA	0x28UL	/* APC Capture DMA Next Address */
  #define APCCNC	0x2cUL	/* APC Capture Next Count */
  #define APCPVA	0x30UL	/* APC Play DMA Address */
  #define APCPC	0x34UL	/* APC Play Count */
  #define APCPNVA	0x38UL	/* APC Play DMA Next Address */
  #define APCPNC	0x3cUL	/* APC Play Next Count */
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
135
136
137
138
139
140
141
142
  /* Defines for SBUS DMA-routines */
  
  #define APCVA  0x0UL	/* APC DMA Address */
  #define APCC   0x4UL	/* APC Count */
  #define APCNVA 0x8UL	/* APC DMA Next Address */
  #define APCNC  0xcUL	/* APC Next Count */
  #define APC_PLAY 0x30UL	/* Play registers start at 0x30 */
  #define APC_RECORD 0x20UL /* Record registers start at 0x20 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  /* APCCSR bits */
  
  #define APC_INT_PENDING 0x800000 /* Interrupt Pending */
  #define APC_PLAY_INT    0x400000 /* Playback interrupt */
  #define APC_CAPT_INT    0x200000 /* Capture interrupt */
  #define APC_GENL_INT    0x100000 /* General interrupt */
  #define APC_XINT_ENA    0x80000  /* General ext int. enable */
  #define APC_XINT_PLAY   0x40000  /* Playback ext intr */
  #define APC_XINT_CAPT   0x20000  /* Capture ext intr */
  #define APC_XINT_GENL   0x10000  /* Error ext intr */
  #define APC_XINT_EMPT   0x8000   /* Pipe empty interrupt (0 write to pva) */
  #define APC_XINT_PEMP   0x4000   /* Play pipe empty (pva and pnva not set) */
  #define APC_XINT_PNVA   0x2000   /* Playback NVA dirty */
  #define APC_XINT_PENA   0x1000   /* play pipe empty Int enable */
  #define APC_XINT_COVF   0x800    /* Cap data dropped on floor */
  #define APC_XINT_CNVA   0x400    /* Capture NVA dirty */
  #define APC_XINT_CEMP   0x200    /* Capture pipe empty (cva and cnva not set) */
  #define APC_XINT_CENA   0x100    /* Cap. pipe empty int enable */
  #define APC_PPAUSE      0x80     /* Pause the play DMA */
  #define APC_CPAUSE      0x40     /* Pause the capture DMA */
  #define APC_CDC_RESET   0x20     /* CODEC RESET */
  #define APC_PDMA_READY  0x08     /* Play DMA Go */
  #define APC_CDMA_READY  0x04     /* Capture DMA Go */
  #define APC_CHIP_RESET  0x01     /* Reset the chip */
  
  /* EBUS DMA register offsets  */
  
  #define EBDMA_CSR	0x00UL	/* Control/Status */
  #define EBDMA_ADDR	0x04UL	/* DMA Address */
  #define EBDMA_COUNT	0x08UL	/* DMA Count */
  
  /*
   *  Some variables
   */
  
  static unsigned char freq_bits[14] = {
  	/* 5510 */	0x00 | CS4231_XTAL2,
  	/* 6620 */	0x0E | CS4231_XTAL2,
  	/* 8000 */	0x00 | CS4231_XTAL1,
  	/* 9600 */	0x0E | CS4231_XTAL1,
  	/* 11025 */	0x02 | CS4231_XTAL2,
  	/* 16000 */	0x02 | CS4231_XTAL1,
  	/* 18900 */	0x04 | CS4231_XTAL2,
  	/* 22050 */	0x06 | CS4231_XTAL2,
  	/* 27042 */	0x04 | CS4231_XTAL1,
  	/* 32000 */	0x06 | CS4231_XTAL1,
  	/* 33075 */	0x0C | CS4231_XTAL2,
  	/* 37800 */	0x08 | CS4231_XTAL2,
  	/* 44100 */	0x0A | CS4231_XTAL2,
  	/* 48000 */	0x0C | CS4231_XTAL1
  };
4e4b7eaa6   Takashi Iwai   ALSA: sparc: Cons...
194
  static const unsigned int rates[14] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
  	5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
  	27042, 32000, 33075, 37800, 44100, 48000
  };
4e4b7eaa6   Takashi Iwai   ALSA: sparc: Cons...
198
  static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
199
  	.count	= ARRAY_SIZE(rates),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
  	.list	= rates,
  };
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
202
  static int snd_cs4231_xrate(struct snd_pcm_runtime *runtime)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  {
  	return snd_pcm_hw_constraint_list(runtime, 0,
  					  SNDRV_PCM_HW_PARAM_RATE,
  					  &hw_constraints_rates);
  }
  
  static unsigned char snd_cs4231_original_image[32] =
  {
  	0x00,			/* 00/00 - lic */
  	0x00,			/* 01/01 - ric */
  	0x9f,			/* 02/02 - la1ic */
  	0x9f,			/* 03/03 - ra1ic */
  	0x9f,			/* 04/04 - la2ic */
  	0x9f,			/* 05/05 - ra2ic */
  	0xbf,			/* 06/06 - loc */
  	0xbf,			/* 07/07 - roc */
  	0x20,			/* 08/08 - pdfr */
  	CS4231_AUTOCALIB,	/* 09/09 - ic */
  	0x00,			/* 0a/10 - pc */
  	0x00,			/* 0b/11 - ti */
  	CS4231_MODE2,		/* 0c/12 - mi */
  	0x00,			/* 0d/13 - lbc */
  	0x00,			/* 0e/14 - pbru */
  	0x00,			/* 0f/15 - pbrl */
  	0x80,			/* 10/16 - afei */
  	0x01,			/* 11/17 - afeii */
  	0x9f,			/* 12/18 - llic */
  	0x9f,			/* 13/19 - rlic */
  	0x00,			/* 14/20 - tlb */
  	0x00,			/* 15/21 - thb */
  	0x00,			/* 16/22 - la3mic/reserved */
  	0x00,			/* 17/23 - ra3mic/reserved */
  	0x00,			/* 18/24 - afs */
  	0x00,			/* 19/25 - lamoc/version */
  	0x00,			/* 1a/26 - mioc */
  	0x00,			/* 1b/27 - ramoc/reserved */
  	0x20,			/* 1c/28 - cdfr */
  	0x00,			/* 1d/29 - res4 */
  	0x00,			/* 1e/30 - cbru */
  	0x00,			/* 1f/31 - cbrl */
  };
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
244
  static u8 __cs4231_readb(struct snd_cs4231 *cp, void __iomem *reg_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
246
  	if (cp->flags & CS4231_FLAG_EBUS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  		return readb(reg_addr);
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
248
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  		return sbus_readb(reg_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
251
252
  static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val,
  			    void __iomem *reg_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
254
  	if (cp->flags & CS4231_FLAG_EBUS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  		return writeb(val, reg_addr);
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
256
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  		return sbus_writeb(val, reg_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
262
  }
  
  /*
   *  Basic I/O functions
   */
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
263
  static void snd_cs4231_ready(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
  {
  	int timeout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
267
268
269
270
271
272
  	for (timeout = 250; timeout > 0; timeout--) {
  		int val = __cs4231_readb(chip, CS4231U(chip, REGSEL));
  		if ((val & CS4231_INIT) == 0)
  			break;
  		udelay(100);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
274
275
  static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg,
  			    unsigned char value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
277
  	snd_cs4231_ready(chip);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
278
  #ifdef CONFIG_SND_DEBUG
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
279
  	if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT)
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
280
281
282
283
  		snd_printdd("out: auto calibration time out - reg = 0x%x, "
  			    "value = 0x%x
  ",
  			    reg, value);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
284
  #endif
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
285
  	__cs4231_writeb(chip, chip->mce_bit | reg, CS4231U(chip, REGSEL));
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
286
  	wmb();
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
287
  	__cs4231_writeb(chip, value, CS4231U(chip, REG));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
  	mb();
  }
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
290
291
  static inline void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg,
  		     unsigned char mask, unsigned char value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
293
  	unsigned char tmp = (chip->image[reg] & mask) | value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294

c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
295
296
297
298
299
300
301
302
303
  	chip->image[reg] = tmp;
  	if (!chip->calibrate_mute)
  		snd_cs4231_dout(chip, reg, tmp);
  }
  
  static void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg,
  			   unsigned char value)
  {
  	snd_cs4231_dout(chip, reg, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
  	chip->image[reg] = value;
  	mb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
307
  static unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
309
  	snd_cs4231_ready(chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  #ifdef CONFIG_SND_DEBUG
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
311
  	if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT)
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
312
313
314
  		snd_printdd("in: auto calibration time out - reg = 0x%x
  ",
  			    reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  #endif
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
316
  	__cs4231_writeb(chip, chip->mce_bit | reg, CS4231U(chip, REGSEL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  	mb();
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
318
  	return __cs4231_readb(chip, CS4231U(chip, REG));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
322
  /*
   *  CS4231 detection / MCE routines
   */
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
323
  static void snd_cs4231_busy_wait(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
  {
  	int timeout;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
326
  	/* looks like this sequence is proper for CS4231A chip (GUS MAX) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  	for (timeout = 5; timeout > 0; timeout--)
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
328
  		__cs4231_readb(chip, CS4231U(chip, REGSEL));
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
329

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  	/* end of cleanup sequence */
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
331
332
333
334
  	for (timeout = 500; timeout > 0; timeout--) {
  		int val = __cs4231_readb(chip, CS4231U(chip, REGSEL));
  		if ((val & CS4231_INIT) == 0)
  			break;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
335
  		msleep(1);
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
336
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
338
  static void snd_cs4231_mce_up(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
  {
  	unsigned long flags;
  	int timeout;
  
  	spin_lock_irqsave(&chip->lock, flags);
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
344
  	snd_cs4231_ready(chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  #ifdef CONFIG_SND_DEBUG
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
346
  	if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT)
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
347
348
  		snd_printdd("mce_up - auto calibration time out (0)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  #endif
  	chip->mce_bit |= CS4231_MCE;
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
351
  	timeout = __cs4231_readb(chip, CS4231U(chip, REGSEL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  	if (timeout == 0x80)
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
353
354
355
356
  		snd_printdd("mce_up [%p]: serious init problem - "
  			    "codec still busy
  ",
  			    chip->port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  	if (!(timeout & CS4231_MCE))
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
358
359
  		__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f),
  				CS4231U(chip, REGSEL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
  	spin_unlock_irqrestore(&chip->lock, flags);
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
362
  static void snd_cs4231_mce_down(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  {
9823adf63   Krzysztof Helt   [ALSA] This simpl...
364
365
  	unsigned long flags, timeout;
  	int reg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  	snd_cs4231_busy_wait(chip);
9823adf63   Krzysztof Helt   [ALSA] This simpl...
368
  	spin_lock_irqsave(&chip->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  #ifdef CONFIG_SND_DEBUG
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
370
371
372
373
  	if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT)
  		snd_printdd("mce_down [%p] - auto calibration time out (0)
  ",
  			    CS4231U(chip, REGSEL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
  #endif
  	chip->mce_bit &= ~CS4231_MCE;
9823adf63   Krzysztof Helt   [ALSA] This simpl...
376
377
  	reg = __cs4231_readb(chip, CS4231U(chip, REGSEL));
  	__cs4231_writeb(chip, chip->mce_bit | (reg & 0x1f),
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
378
  			CS4231U(chip, REGSEL));
9823adf63   Krzysztof Helt   [ALSA] This simpl...
379
380
381
382
383
  	if (reg == 0x80)
  		snd_printdd("mce_down [%p]: serious init problem "
  			    "- codec still busy
  ", chip->port);
  	if ((reg & CS4231_MCE) == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
  		spin_unlock_irqrestore(&chip->lock, flags);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

56f91585b   Krzysztof Helt   [ALSA] sun-cs4231...
388
  	/*
9823adf63   Krzysztof Helt   [ALSA] This simpl...
389
  	 * Wait for auto-calibration (AC) process to finish, i.e. ACI to go low.
56f91585b   Krzysztof Helt   [ALSA] sun-cs4231...
390
  	 */
9823adf63   Krzysztof Helt   [ALSA] This simpl...
391
392
  	timeout = jiffies + msecs_to_jiffies(250);
  	do {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  		spin_unlock_irqrestore(&chip->lock, flags);
b875d6505   Takashi Iwai   [ALSA] Fix thinko...
394
  		msleep(1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
  		spin_lock_irqsave(&chip->lock, flags);
9823adf63   Krzysztof Helt   [ALSA] This simpl...
396
397
398
  		reg = snd_cs4231_in(chip, CS4231_TEST_INIT);
  		reg &= CS4231_CALIB_IN_PROGRESS;
  	} while (reg && time_before(jiffies, timeout));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
  	spin_unlock_irqrestore(&chip->lock, flags);
9823adf63   Krzysztof Helt   [ALSA] This simpl...
400
401
402
403
404
  
  	if (reg)
  		snd_printk(KERN_ERR
  			   "mce_down - auto calibration time out (2)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
406
407
408
  static void snd_cs4231_advance_dma(struct cs4231_dma_control *dma_cont,
  				   struct snd_pcm_substream *substream,
  				   unsigned int *periods_sent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
410
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
  
  	while (1) {
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
413
414
  		unsigned int period_size = snd_pcm_lib_period_bytes(substream);
  		unsigned int offset = period_size * (*periods_sent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415

5a19b178d   Takashi Iwai   ALSA: sparc/cs423...
416
417
  		if (WARN_ON(period_size >= (1 << 24)))
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418

9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
419
420
  		if (dma_cont->request(dma_cont,
  				      runtime->dma_addr + offset, period_size))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
  		(*periods_sent) = ((*periods_sent) + 1) % runtime->periods;
  	}
  }
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
425

be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
426
427
  static void cs4231_dma_trigger(struct snd_pcm_substream *substream,
  			       unsigned int what, int on)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
429
430
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
  	struct cs4231_dma_control *dma_cont;
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
431

5a820fa7e   Georg Chini   [SPARC]: Make SBU...
432
  	if (what & CS4231_PLAYBACK_ENABLE) {
b128254fd   Georg Chini   [SPARC]: More abs...
433
  		dma_cont = &chip->p_dma;
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
434
  		if (on) {
b128254fd   Georg Chini   [SPARC]: More abs...
435
436
437
  			dma_cont->prepare(dma_cont, 0);
  			dma_cont->enable(dma_cont, 1);
  			snd_cs4231_advance_dma(dma_cont,
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
438
439
  				chip->playback_substream,
  				&chip->p_periods_sent);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
440
  		} else {
b128254fd   Georg Chini   [SPARC]: More abs...
441
  			dma_cont->enable(dma_cont, 0);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
442
  		}
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
443
444
  	}
  	if (what & CS4231_RECORD_ENABLE) {
b128254fd   Georg Chini   [SPARC]: More abs...
445
  		dma_cont = &chip->c_dma;
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
446
  		if (on) {
b128254fd   Georg Chini   [SPARC]: More abs...
447
448
449
  			dma_cont->prepare(dma_cont, 1);
  			dma_cont->enable(dma_cont, 1);
  			snd_cs4231_advance_dma(dma_cont,
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
450
451
  				chip->capture_substream,
  				&chip->c_periods_sent);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
452
  		} else {
b128254fd   Georg Chini   [SPARC]: More abs...
453
  			dma_cont->enable(dma_cont, 0);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
454
  		}
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
455
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
457
  static int snd_cs4231_trigger(struct snd_pcm_substream *substream, int cmd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
459
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
462
463
464
465
466
  	int result = 0;
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  	case SNDRV_PCM_TRIGGER_STOP:
  	{
  		unsigned int what = 0;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
467
  		struct snd_pcm_substream *s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  		unsigned long flags;
ef991b95a   Takashi Iwai   [ALSA] Add snd_pc...
469
  		snd_pcm_group_for_each_entry(s, substream) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
475
476
477
  			if (s == chip->playback_substream) {
  				what |= CS4231_PLAYBACK_ENABLE;
  				snd_pcm_trigger_done(s, substream);
  			} else if (s == chip->capture_substream) {
  				what |= CS4231_RECORD_ENABLE;
  				snd_pcm_trigger_done(s, substream);
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
  		spin_lock_irqsave(&chip->lock, flags);
  		if (cmd == SNDRV_PCM_TRIGGER_START) {
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
480
  			cs4231_dma_trigger(substream, what, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  			chip->image[CS4231_IFACE_CTRL] |= what;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  		} else {
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
483
  			cs4231_dma_trigger(substream, what, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
488
489
490
491
492
493
494
  			chip->image[CS4231_IFACE_CTRL] &= ~what;
  		}
  		snd_cs4231_out(chip, CS4231_IFACE_CTRL,
  			       chip->image[CS4231_IFACE_CTRL]);
  		spin_unlock_irqrestore(&chip->lock, flags);
  		break;
  	}
  	default:
  		result = -EINVAL;
  		break;
  	}
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
495

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  	return result;
  }
  
  /*
   *  CODEC I/O
   */
  
  static unsigned char snd_cs4231_get_rate(unsigned int rate)
  {
  	int i;
  
  	for (i = 0; i < 14; i++)
  		if (rate == rates[i])
  			return freq_bits[i];
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
510

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
  	return freq_bits[13];
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
513
514
  static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, int format,
  					   int channels)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
  {
  	unsigned char rformat;
  
  	rformat = CS4231_LINEAR_8;
  	switch (format) {
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
  	case SNDRV_PCM_FORMAT_MU_LAW:
  		rformat = CS4231_ULAW_8;
  		break;
  	case SNDRV_PCM_FORMAT_A_LAW:
  		rformat = CS4231_ALAW_8;
  		break;
  	case SNDRV_PCM_FORMAT_S16_LE:
  		rformat = CS4231_LINEAR_16;
  		break;
  	case SNDRV_PCM_FORMAT_S16_BE:
  		rformat = CS4231_LINEAR_16_BIG;
  		break;
  	case SNDRV_PCM_FORMAT_IMA_ADPCM:
  		rformat = CS4231_ADPCM_16;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
  	}
  	if (channels > 1)
  		rformat |= CS4231_STEREO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
  	return rformat;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
540
  static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  {
  	unsigned long flags;
  
  	mute = mute ? 1 : 0;
  	spin_lock_irqsave(&chip->lock, flags);
  	if (chip->calibrate_mute == mute) {
  		spin_unlock_irqrestore(&chip->lock, flags);
  		return;
  	}
  	if (!mute) {
  		snd_cs4231_dout(chip, CS4231_LEFT_INPUT,
  				chip->image[CS4231_LEFT_INPUT]);
  		snd_cs4231_dout(chip, CS4231_RIGHT_INPUT,
  				chip->image[CS4231_RIGHT_INPUT]);
  		snd_cs4231_dout(chip, CS4231_LOOPBACK,
  				chip->image[CS4231_LOOPBACK]);
  	}
  	snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT,
  			mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);
  	snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT,
  			mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);
  	snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT,
  			mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);
  	snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT,
  			mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);
  	snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT,
  			mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);
  	snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT,
  			mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);
  	snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN,
  			mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);
  	snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN,
  			mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);
  	snd_cs4231_dout(chip, CS4231_MONO_CTRL,
  			mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
  	chip->calibrate_mute = mute;
  	spin_unlock_irqrestore(&chip->lock, flags);
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
579
580
  static void snd_cs4231_playback_format(struct snd_cs4231 *chip,
  				       struct snd_pcm_hw_params *params,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
583
  				       unsigned char pdfr)
  {
  	unsigned long flags;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
584
  	mutex_lock(&chip->mce_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
594
595
596
597
598
  	snd_cs4231_calibrate_mute(chip, 1);
  
  	snd_cs4231_mce_up(chip);
  
  	spin_lock_irqsave(&chip->lock, flags);
  	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
  		       (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?
  		       (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :
  		       pdfr);
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	snd_cs4231_mce_down(chip);
  
  	snd_cs4231_calibrate_mute(chip, 0);
12aa75790   Ingo Molnar   [ALSA] semaphore ...
599
  	mutex_unlock(&chip->mce_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
601
602
603
  static void snd_cs4231_capture_format(struct snd_cs4231 *chip,
  				      struct snd_pcm_hw_params *params,
  				      unsigned char cdfr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
  {
  	unsigned long flags;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
606
  	mutex_lock(&chip->mce_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  	snd_cs4231_calibrate_mute(chip, 1);
  
  	snd_cs4231_mce_up(chip);
  
  	spin_lock_irqsave(&chip->lock, flags);
  	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
  		snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
  			       ((chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |
  			       (cdfr & 0x0f));
  		spin_unlock_irqrestore(&chip->lock, flags);
  		snd_cs4231_mce_down(chip);
  		snd_cs4231_mce_up(chip);
  		spin_lock_irqsave(&chip->lock, flags);
  	}
  	snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	snd_cs4231_mce_down(chip);
  
  	snd_cs4231_calibrate_mute(chip, 0);
12aa75790   Ingo Molnar   [ALSA] semaphore ...
627
  	mutex_unlock(&chip->mce_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
632
  }
  
  /*
   *  Timer interface
   */
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
633
  static unsigned long snd_cs4231_timer_resolution(struct snd_timer *timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
635
  	struct snd_cs4231 *chip = snd_timer_chip(timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
  
  	return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
639
  static int snd_cs4231_timer_start(struct snd_timer *timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
  {
  	unsigned long flags;
  	unsigned int ticks;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
643
  	struct snd_cs4231 *chip = snd_timer_chip(timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
647
648
649
650
651
652
653
654
655
656
  
  	spin_lock_irqsave(&chip->lock, flags);
  	ticks = timer->sticks;
  	if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
  	    (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
  	    (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
  		snd_cs4231_out(chip, CS4231_TIMER_HIGH,
  			       chip->image[CS4231_TIMER_HIGH] =
  			       (unsigned char) (ticks >> 8));
  		snd_cs4231_out(chip, CS4231_TIMER_LOW,
  			       chip->image[CS4231_TIMER_LOW] =
  			       (unsigned char) ticks);
  		snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
657
658
  			       chip->image[CS4231_ALT_FEATURE_1] |
  					CS4231_TIMER_ENABLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
  	}
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
664
  static int snd_cs4231_timer_stop(struct snd_timer *timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
  {
  	unsigned long flags;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
667
  	struct snd_cs4231 *chip = snd_timer_chip(timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  
  	spin_lock_irqsave(&chip->lock, flags);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
670
  	chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
672
  		       chip->image[CS4231_ALT_FEATURE_1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
675
676
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	return 0;
  }
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
677
  static void snd_cs4231_init(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
683
  {
  	unsigned long flags;
  
  	snd_cs4231_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
684
685
  	snd_printdd("init: (1)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
  #endif
  	snd_cs4231_mce_up(chip);
  	spin_lock_irqsave(&chip->lock, flags);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
689
690
691
692
  	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
  					    CS4231_PLAYBACK_PIO |
  					    CS4231_RECORD_ENABLE |
  					    CS4231_RECORD_PIO |
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
696
697
698
699
  					    CS4231_CALIB_MODE);
  	chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
  	snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
  	spin_unlock_irqrestore(&chip->lock, flags);
  	snd_cs4231_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
700
701
  	snd_printdd("init: (2)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
705
  #endif
  
  	snd_cs4231_mce_up(chip);
  	spin_lock_irqsave(&chip->lock, flags);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
706
707
  	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,
  			chip->image[CS4231_ALT_FEATURE_1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
  	spin_unlock_irqrestore(&chip->lock, flags);
  	snd_cs4231_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
712
713
714
  	snd_printdd("init: (3) - afei = 0x%x
  ",
  		    chip->image[CS4231_ALT_FEATURE_1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
  #endif
  
  	spin_lock_irqsave(&chip->lock, flags);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
718
719
  	snd_cs4231_out(chip, CS4231_ALT_FEATURE_2,
  			chip->image[CS4231_ALT_FEATURE_2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	snd_cs4231_mce_up(chip);
  	spin_lock_irqsave(&chip->lock, flags);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
724
725
  	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
  			chip->image[CS4231_PLAYBK_FORMAT]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
728
729
  	spin_unlock_irqrestore(&chip->lock, flags);
  	snd_cs4231_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
730
731
  	snd_printdd("init: (4)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
736
737
738
739
740
  #endif
  
  	snd_cs4231_mce_up(chip);
  	spin_lock_irqsave(&chip->lock, flags);
  	snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);
  	spin_unlock_irqrestore(&chip->lock, flags);
  	snd_cs4231_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
741
742
  	snd_printdd("init: (5)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
  #endif
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
745
  static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
  {
  	unsigned long flags;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
748
  	mutex_lock(&chip->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
  	if ((chip->mode & mode)) {
12aa75790   Ingo Molnar   [ALSA] semaphore ...
750
  		mutex_unlock(&chip->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
  		return -EAGAIN;
  	}
  	if (chip->mode & CS4231_MODE_OPEN) {
  		chip->mode |= mode;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
755
  		mutex_unlock(&chip->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
758
759
760
761
762
763
  		return 0;
  	}
  	/* ok. now enable and ack CODEC IRQ */
  	spin_lock_irqsave(&chip->lock, flags);
  	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
  		       CS4231_RECORD_IRQ |
  		       CS4231_TIMER_IRQ);
  	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
764
765
  	__cs4231_writeb(chip, 0, CS4231U(chip, STATUS));	/* clear IRQ */
  	__cs4231_writeb(chip, 0, CS4231U(chip, STATUS));	/* clear IRQ */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
769
770
  
  	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
  		       CS4231_RECORD_IRQ |
  		       CS4231_TIMER_IRQ);
  	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
771

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	chip->mode = mode;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
775
  	mutex_unlock(&chip->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
778
  static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
  {
  	unsigned long flags;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
781
  	mutex_lock(&chip->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
  	chip->mode &= ~mode;
  	if (chip->mode & CS4231_MODE_OPEN) {
12aa75790   Ingo Molnar   [ALSA] semaphore ...
784
  		mutex_unlock(&chip->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
790
791
  		return;
  	}
  	snd_cs4231_calibrate_mute(chip, 1);
  
  	/* disable IRQ */
  	spin_lock_irqsave(&chip->lock, flags);
  	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
792
793
  	__cs4231_writeb(chip, 0, CS4231U(chip, STATUS));	/* clear IRQ */
  	__cs4231_writeb(chip, 0, CS4231U(chip, STATUS));	/* clear IRQ */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
797
798
799
800
801
802
803
804
805
  
  	/* now disable record & playback */
  
  	if (chip->image[CS4231_IFACE_CTRL] &
  	    (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
  	     CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
  		spin_unlock_irqrestore(&chip->lock, flags);
  		snd_cs4231_mce_up(chip);
  		spin_lock_irqsave(&chip->lock, flags);
  		chip->image[CS4231_IFACE_CTRL] &=
  			~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
  			  CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
806
807
  		snd_cs4231_out(chip, CS4231_IFACE_CTRL,
  				chip->image[CS4231_IFACE_CTRL]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
813
814
  		spin_unlock_irqrestore(&chip->lock, flags);
  		snd_cs4231_mce_down(chip);
  		spin_lock_irqsave(&chip->lock, flags);
  	}
  
  	/* clear IRQ again */
  	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
815
816
  	__cs4231_writeb(chip, 0, CS4231U(chip, STATUS));	/* clear IRQ */
  	__cs4231_writeb(chip, 0, CS4231U(chip, STATUS));	/* clear IRQ */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
819
820
821
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	snd_cs4231_calibrate_mute(chip, 0);
  
  	chip->mode = 0;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
822
  	mutex_unlock(&chip->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
824
825
826
827
  }
  
  /*
   *  timer open/close
   */
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
828
  static int snd_cs4231_timer_open(struct snd_timer *timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
830
  	struct snd_cs4231 *chip = snd_timer_chip(timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
  	snd_cs4231_open(chip, CS4231_MODE_TIMER);
  	return 0;
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
834
  static int snd_cs4231_timer_close(struct snd_timer *timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
836
  	struct snd_cs4231 *chip = snd_timer_chip(timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
  	snd_cs4231_close(chip, CS4231_MODE_TIMER);
  	return 0;
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
840
  static struct snd_timer_hardware snd_cs4231_timer_table = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
843
844
845
846
847
848
849
850
851
852
853
  	.flags		=	SNDRV_TIMER_HW_AUTO,
  	.resolution	=	9945,
  	.ticks		=	65535,
  	.open		=	snd_cs4231_timer_open,
  	.close		=	snd_cs4231_timer_close,
  	.c_resolution	=	snd_cs4231_timer_resolution,
  	.start		=	snd_cs4231_timer_start,
  	.stop		=	snd_cs4231_timer_stop,
  };
  
  /*
   *  ok.. exported functions..
   */
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
854
855
  static int snd_cs4231_playback_hw_params(struct snd_pcm_substream *substream,
  					 struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
857
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
  	unsigned char new_pdfr;
  	int err;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
860
861
862
  	err = snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
865
866
867
868
869
870
  		return err;
  	new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params),
  					 params_channels(hw_params)) |
  		snd_cs4231_get_rate(params_rate(hw_params));
  	snd_cs4231_playback_format(chip, hw_params, new_pdfr);
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
871
  static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
873
874
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  	unsigned long flags;
a522409e9   Wei Yongjun   ALSA: sparc: fix ...
876
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
  
  	spin_lock_irqsave(&chip->lock, flags);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
879

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
  	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
  					    CS4231_PLAYBACK_PIO);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
882

a522409e9   Wei Yongjun   ALSA: sparc: fix ...
883
884
885
886
  	if (WARN_ON(runtime->period_size > 0xffff + 1)) {
  		ret = -EINVAL;
  		goto out;
  	}
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
887

a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
888
  	chip->p_periods_sent = 0;
a522409e9   Wei Yongjun   ALSA: sparc: fix ...
889
890
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
  	spin_unlock_irqrestore(&chip->lock, flags);
a522409e9   Wei Yongjun   ALSA: sparc: fix ...
892
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
894
895
  static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream,
  					struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
897
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
  	unsigned char new_cdfr;
  	int err;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
900
901
902
  	err = snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
906
907
908
909
910
  		return err;
  	new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params),
  					 params_channels(hw_params)) |
  		snd_cs4231_get_rate(params_rate(hw_params));
  	snd_cs4231_capture_format(chip, hw_params, new_cdfr);
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
911
  static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
913
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
918
  	unsigned long flags;
  
  	spin_lock_irqsave(&chip->lock, flags);
  	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
  					    CS4231_RECORD_PIO);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
919

5a820fa7e   Georg Chini   [SPARC]: Make SBU...
920
  	chip->c_periods_sent = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
924
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
925
  static void snd_cs4231_overrange(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
927
928
929
930
931
932
  {
  	unsigned long flags;
  	unsigned char res;
  
  	spin_lock_irqsave(&chip->lock, flags);
  	res = snd_cs4231_in(chip, CS4231_TEST_INIT);
  	spin_unlock_irqrestore(&chip->lock, flags);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
933
934
  	/* detect overrange only above 0dB; may be user selectable? */
  	if (res & (0x08 | 0x02))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
  		chip->capture_substream->runtime->overrange++;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
937
  static void snd_cs4231_play_callback(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
  	if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) {
  		snd_pcm_period_elapsed(chip->playback_substream);
b128254fd   Georg Chini   [SPARC]: More abs...
941
  		snd_cs4231_advance_dma(&chip->p_dma, chip->playback_substream,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
943
944
  					    &chip->p_periods_sent);
  	}
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
945
  static void snd_cs4231_capture_callback(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
  	if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) {
  		snd_pcm_period_elapsed(chip->capture_substream);
b128254fd   Georg Chini   [SPARC]: More abs...
949
  		snd_cs4231_advance_dma(&chip->c_dma, chip->capture_substream,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
  					    &chip->c_periods_sent);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953

9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
954
955
  static snd_pcm_uframes_t snd_cs4231_playback_pointer(
  					struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
957
958
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
  	struct cs4231_dma_control *dma_cont = &chip->p_dma;
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
959
  	size_t ptr;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
960

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
  	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
  		return 0;
b128254fd   Georg Chini   [SPARC]: More abs...
963
964
965
  	ptr = dma_cont->address(dma_cont);
  	if (ptr != 0)
  		ptr -= substream->runtime->dma_addr;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
966

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
  	return bytes_to_frames(substream->runtime, ptr);
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
969
970
  static snd_pcm_uframes_t snd_cs4231_capture_pointer(
  					struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
972
973
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
  	struct cs4231_dma_control *dma_cont = &chip->c_dma;
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
974
  	size_t ptr;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
975

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
  	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
  		return 0;
b128254fd   Georg Chini   [SPARC]: More abs...
978
979
980
  	ptr = dma_cont->address(dma_cont);
  	if (ptr != 0)
  		ptr -= substream->runtime->dma_addr;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
981

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
  	return bytes_to_frames(substream->runtime, ptr);
  }
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
984
  static int snd_cs4231_probe(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
  {
  	unsigned long flags;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
987
988
989
  	int i;
  	int id = 0;
  	int vers = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  	unsigned char *ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
  	for (i = 0; i < 50; i++) {
  		mb();
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
993
  		if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT)
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
994
  			msleep(2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
  		else {
  			spin_lock_irqsave(&chip->lock, flags);
  			snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
  			id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;
  			vers = snd_cs4231_in(chip, CS4231_VERSION);
  			spin_unlock_irqrestore(&chip->lock, flags);
  			if (id == 0x0a)
  				break;	/* this is valid value */
  		}
  	}
  	snd_printdd("cs4231: port = %p, id = 0x%x
  ", chip->port, id);
  	if (id != 0x0a)
  		return -ENODEV;	/* no valid device found */
  
  	spin_lock_irqsave(&chip->lock, flags);
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
1011
1012
1013
  	/* clear any pendings IRQ */
  	__cs4231_readb(chip, CS4231U(chip, STATUS));
  	__cs4231_writeb(chip, 0, CS4231U(chip, STATUS));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  	mb();
  
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
  	chip->image[CS4231_IFACE_CTRL] =
  		chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA;
  	chip->image[CS4231_ALT_FEATURE_1] = 0x80;
  	chip->image[CS4231_ALT_FEATURE_2] = 0x01;
  	if (vers & 0x20)
  		chip->image[CS4231_ALT_FEATURE_2] |= 0x02;
  
  	ptr = (unsigned char *) &chip->image;
  
  	snd_cs4231_mce_down(chip);
  
  	spin_lock_irqsave(&chip->lock, flags);
  
  	for (i = 0; i < 32; i++)	/* ok.. fill all CS4231 registers */
  		snd_cs4231_out(chip, i, *ptr++);
  
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	snd_cs4231_mce_up(chip);
  
  	snd_cs4231_mce_down(chip);
  
  	mdelay(2);
  
  	return 0;		/* all things are ok.. */
  }
688ed206e   Bhumika Goyal   ALSA: sparc: make...
1045
  static const struct snd_pcm_hardware snd_cs4231_playback = {
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
  	.info			= SNDRV_PCM_INFO_MMAP |
  				  SNDRV_PCM_INFO_INTERLEAVED |
  				  SNDRV_PCM_INFO_MMAP_VALID |
  				  SNDRV_PCM_INFO_SYNC_START,
  	.formats		= SNDRV_PCM_FMTBIT_MU_LAW |
  				  SNDRV_PCM_FMTBIT_A_LAW |
  				  SNDRV_PCM_FMTBIT_IMA_ADPCM |
  				  SNDRV_PCM_FMTBIT_U8 |
  				  SNDRV_PCM_FMTBIT_S16_LE |
  				  SNDRV_PCM_FMTBIT_S16_BE,
  	.rates			= SNDRV_PCM_RATE_KNOT |
  				  SNDRV_PCM_RATE_8000_48000,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
1059
1060
1061
  	.rate_min		= 5510,
  	.rate_max		= 48000,
  	.channels_min		= 1,
  	.channels_max		= 2,
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1062
  	.buffer_bytes_max	= 32 * 1024,
f9af1d9de   David S. Miller   [SOUND] Sparc CS4...
1063
  	.period_bytes_min	= 64,
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1064
  	.period_bytes_max	= 32 * 1024,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
1067
  	.periods_min		= 1,
  	.periods_max		= 1024,
  };
688ed206e   Bhumika Goyal   ALSA: sparc: make...
1068
  static const struct snd_pcm_hardware snd_cs4231_capture = {
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
  	.info			= SNDRV_PCM_INFO_MMAP |
  				  SNDRV_PCM_INFO_INTERLEAVED |
  				  SNDRV_PCM_INFO_MMAP_VALID |
  				  SNDRV_PCM_INFO_SYNC_START,
  	.formats		= SNDRV_PCM_FMTBIT_MU_LAW |
  				  SNDRV_PCM_FMTBIT_A_LAW |
  				  SNDRV_PCM_FMTBIT_IMA_ADPCM |
  				  SNDRV_PCM_FMTBIT_U8 |
  				  SNDRV_PCM_FMTBIT_S16_LE |
  				  SNDRV_PCM_FMTBIT_S16_BE,
  	.rates			= SNDRV_PCM_RATE_KNOT |
  				  SNDRV_PCM_RATE_8000_48000,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
  	.rate_min		= 5510,
  	.rate_max		= 48000,
  	.channels_min		= 1,
  	.channels_max		= 2,
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1085
  	.buffer_bytes_max	= 32 * 1024,
f9af1d9de   David S. Miller   [SOUND] Sparc CS4...
1086
  	.period_bytes_min	= 64,
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1087
  	.period_bytes_max	= 32 * 1024,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
  	.periods_min		= 1,
  	.periods_max		= 1024,
  };
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1091
  static int snd_cs4231_playback_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1093
1094
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
1097
  	int err;
  
  	runtime->hw = snd_cs4231_playback;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1098
  	err = snd_cs4231_open(chip, CS4231_MODE_PLAY);
46663071a   Takashi Iwai   ALSA: sparc: Fix ...
1099
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
1104
1105
1106
1107
  	chip->playback_substream = substream;
  	chip->p_periods_sent = 0;
  	snd_pcm_set_sync(substream);
  	snd_cs4231_xrate(runtime);
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1108
  static int snd_cs4231_capture_open(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1110
1111
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
1114
  	int err;
  
  	runtime->hw = snd_cs4231_capture;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1115
  	err = snd_cs4231_open(chip, CS4231_MODE_RECORD);
46663071a   Takashi Iwai   ALSA: sparc: Fix ...
1116
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
1122
1123
1124
  	chip->capture_substream = substream;
  	chip->c_periods_sent = 0;
  	snd_pcm_set_sync(substream);
  	snd_cs4231_xrate(runtime);
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1125
  static int snd_cs4231_playback_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1127
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
  	snd_cs4231_close(chip, CS4231_MODE_PLAY);
b128254fd   Georg Chini   [SPARC]: More abs...
1130
  	chip->playback_substream = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
1132
1133
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1134
  static int snd_cs4231_capture_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1136
  	struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
  	snd_cs4231_close(chip, CS4231_MODE_RECORD);
b128254fd   Georg Chini   [SPARC]: More abs...
1139
  	chip->capture_substream = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
1143
1144
1145
1146
  
  	return 0;
  }
  
  /* XXX We can do some power-management, in particular on EBUS using
   * XXX the audio AUXIO register...
   */
544d6272c   Arvind Yadav   ALSA: sparc: cons...
1147
  static const struct snd_pcm_ops snd_cs4231_playback_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
1149
1150
1151
  	.open		=	snd_cs4231_playback_open,
  	.close		=	snd_cs4231_playback_close,
  	.ioctl		=	snd_pcm_lib_ioctl,
  	.hw_params	=	snd_cs4231_playback_hw_params,
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1152
  	.hw_free	=	snd_pcm_lib_free_pages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
1155
1156
  	.prepare	=	snd_cs4231_playback_prepare,
  	.trigger	=	snd_cs4231_trigger,
  	.pointer	=	snd_cs4231_playback_pointer,
  };
544d6272c   Arvind Yadav   ALSA: sparc: cons...
1157
  static const struct snd_pcm_ops snd_cs4231_capture_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
1161
  	.open		=	snd_cs4231_capture_open,
  	.close		=	snd_cs4231_capture_close,
  	.ioctl		=	snd_pcm_lib_ioctl,
  	.hw_params	=	snd_cs4231_capture_hw_params,
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1162
  	.hw_free	=	snd_pcm_lib_free_pages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
1164
1165
1166
  	.prepare	=	snd_cs4231_capture_prepare,
  	.trigger	=	snd_cs4231_trigger,
  	.pointer	=	snd_cs4231_capture_pointer,
  };
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1167
  static int snd_cs4231_pcm(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1169
  	struct snd_cs4231 *chip = card->private_data;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1170
  	struct snd_pcm *pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
  	int err;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1172
1173
  	err = snd_pcm_new(card, "CS4231", 0, 1, 1, &pcm);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
  		return err;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1175
1176
1177
1178
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  			&snd_cs4231_playback_ops);
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
  			&snd_cs4231_capture_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
1180
  	/* global setup */
  	pcm->private_data = chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
  	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
  	strcpy(pcm->name, "CS4231");
afc88ad6b   David S. Miller   cs4231: Convert t...
1183
1184
1185
  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
  					      &chip->op->dev,
  					      64 * 1024, 128 * 1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
1187
1188
1189
1190
  
  	chip->pcm = pcm;
  
  	return 0;
  }
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1191
  static int snd_cs4231_timer(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1193
  	struct snd_cs4231 *chip = card->private_data;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1194
1195
  	struct snd_timer *timer;
  	struct snd_timer_id tid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
1198
1199
1200
  	int err;
  
  	/* Timer initialization */
  	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
  	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1201
  	tid.card = card->number;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1202
1203
  	tid.device = 0;
  	tid.subdevice = 0;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1204
1205
  	err = snd_timer_new(card, "CS4231", &tid, &timer);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1206
1207
1208
  		return err;
  	strcpy(timer->name, "CS4231");
  	timer->private_data = chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
1210
1211
1212
1213
  	timer->hw = snd_cs4231_timer_table;
  	chip->timer = timer;
  
  	return 0;
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1214

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215
1216
1217
  /*
   *  MIXER part
   */
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1218
1219
  static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol,
  			       struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
  {
5fe0b0e3e   Takashi Iwai   ALSA: sparc: Use ...
1221
  	static const char * const texts[4] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
  		"Line", "CD", "Mic", "Mix"
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224

5fe0b0e3e   Takashi Iwai   ALSA: sparc: Use ...
1225
  	return snd_ctl_enum_info(uinfo, 2, 4, texts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1227
1228
  static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol,
  			      struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1230
  	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
  	unsigned long flags;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1232

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
1235
1236
1237
1238
1239
1240
1241
  	spin_lock_irqsave(&chip->lock, flags);
  	ucontrol->value.enumerated.item[0] =
  		(chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
  	ucontrol->value.enumerated.item[1] =
  		(chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1242
1243
  static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol,
  			      struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1245
  	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246
1247
1248
  	unsigned long flags;
  	unsigned short left, right;
  	int change;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1249

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
  	if (ucontrol->value.enumerated.item[0] > 3 ||
  	    ucontrol->value.enumerated.item[1] > 3)
  		return -EINVAL;
  	left = ucontrol->value.enumerated.item[0] << 6;
  	right = ucontrol->value.enumerated.item[1] << 6;
  
  	spin_lock_irqsave(&chip->lock, flags);
  
  	left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
  	right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
  	change = left != chip->image[CS4231_LEFT_INPUT] ||
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1261
  		 right != chip->image[CS4231_RIGHT_INPUT];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
1263
1264
1265
1266
1267
1268
  	snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);
  	snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);
  
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	return change;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1269
1270
  static int snd_cs4231_info_single(struct snd_kcontrol *kcontrol,
  				  struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
  {
  	int mask = (kcontrol->private_value >> 16) & 0xff;
  
  	uinfo->type = (mask == 1) ?
  		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = mask;
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1282
1283
  static int snd_cs4231_get_single(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1285
  	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1286
1287
1288
1289
1290
  	unsigned long flags;
  	int reg = kcontrol->private_value & 0xff;
  	int shift = (kcontrol->private_value >> 8) & 0xff;
  	int mask = (kcontrol->private_value >> 16) & 0xff;
  	int invert = (kcontrol->private_value >> 24) & 0xff;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1291

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
  	spin_lock_irqsave(&chip->lock, flags);
  
  	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
  
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	if (invert)
  		ucontrol->value.integer.value[0] =
  			(mask - ucontrol->value.integer.value[0]);
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1304
1305
  static int snd_cs4231_put_single(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1307
  	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
1310
1311
1312
1313
1314
  	unsigned long flags;
  	int reg = kcontrol->private_value & 0xff;
  	int shift = (kcontrol->private_value >> 8) & 0xff;
  	int mask = (kcontrol->private_value >> 16) & 0xff;
  	int invert = (kcontrol->private_value >> 24) & 0xff;
  	int change;
  	unsigned short val;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1315

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
  	val = (ucontrol->value.integer.value[0] & mask);
  	if (invert)
  		val = mask - val;
  	val <<= shift;
  
  	spin_lock_irqsave(&chip->lock, flags);
  
  	val = (chip->image[reg] & ~(mask << shift)) | val;
  	change = val != chip->image[reg];
  	snd_cs4231_out(chip, reg, val);
  
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	return change;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1331
1332
  static int snd_cs4231_info_double(struct snd_kcontrol *kcontrol,
  				  struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
  {
  	int mask = (kcontrol->private_value >> 24) & 0xff;
  
  	uinfo->type = mask == 1 ?
  		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = mask;
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1344
1345
  static int snd_cs4231_get_double(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1347
  	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
1349
1350
1351
1352
1353
1354
  	unsigned long flags;
  	int left_reg = kcontrol->private_value & 0xff;
  	int right_reg = (kcontrol->private_value >> 8) & 0xff;
  	int shift_left = (kcontrol->private_value >> 16) & 0x07;
  	int shift_right = (kcontrol->private_value >> 19) & 0x07;
  	int mask = (kcontrol->private_value >> 24) & 0xff;
  	int invert = (kcontrol->private_value >> 22) & 1;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1355

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
  	spin_lock_irqsave(&chip->lock, flags);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1357
1358
1359
1360
  	ucontrol->value.integer.value[0] =
  		(chip->image[left_reg] >> shift_left) & mask;
  	ucontrol->value.integer.value[1] =
  		(chip->image[right_reg] >> shift_right) & mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
  
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	if (invert) {
  		ucontrol->value.integer.value[0] =
  			(mask - ucontrol->value.integer.value[0]);
  		ucontrol->value.integer.value[1] =
  			(mask - ucontrol->value.integer.value[1]);
  	}
  
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1373
1374
  static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1376
  	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1377
1378
1379
1380
1381
1382
1383
1384
1385
  	unsigned long flags;
  	int left_reg = kcontrol->private_value & 0xff;
  	int right_reg = (kcontrol->private_value >> 8) & 0xff;
  	int shift_left = (kcontrol->private_value >> 16) & 0x07;
  	int shift_right = (kcontrol->private_value >> 19) & 0x07;
  	int mask = (kcontrol->private_value >> 24) & 0xff;
  	int invert = (kcontrol->private_value >> 22) & 1;
  	int change;
  	unsigned short val1, val2;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1386

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
  	val1 = ucontrol->value.integer.value[0] & mask;
  	val2 = ucontrol->value.integer.value[1] & mask;
  	if (invert) {
  		val1 = mask - val1;
  		val2 = mask - val2;
  	}
  	val1 <<= shift_left;
  	val2 <<= shift_right;
  
  	spin_lock_irqsave(&chip->lock, flags);
  
  	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
  	val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1400
1401
  	change = val1 != chip->image[left_reg];
  	change |= val2 != chip->image[right_reg];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402
1403
1404
1405
1406
1407
1408
1409
1410
  	snd_cs4231_out(chip, left_reg, val1);
  	snd_cs4231_out(chip, right_reg, val2);
  
  	spin_unlock_irqrestore(&chip->lock, flags);
  
  	return change;
  }
  
  #define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
  { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .index = (xindex), \
    .info = snd_cs4231_info_single,	\
    .get = snd_cs4231_get_single, .put = snd_cs4231_put_single,	\
    .private_value = (reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24) }
  
  #define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, \
  			shift_right, mask, invert) \
  { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .index = (xindex), \
    .info = snd_cs4231_info_double,	\
    .get = snd_cs4231_get_double, .put = snd_cs4231_put_double,	\
    .private_value = (left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | \
  		   ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22) }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1423

32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1424
  static struct snd_kcontrol_new snd_cs4231_controls[] = {
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT,
  		CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
  CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT,
  		CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
  CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN,
  		CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
  CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN,
  		CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
  CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT,
  		CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
  CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT,
  		CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
  CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT,
  		CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
  CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT,
  		CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
1442
1443
1444
  CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),
  CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
  CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),
  CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1445
1446
  CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0,
  		15, 0),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1447
1448
1449
1450
1451
1452
1453
  {
  	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name	= "Capture Source",
  	.info	= snd_cs4231_info_mux,
  	.get	= snd_cs4231_get_mux,
  	.put	= snd_cs4231_put_mux,
  },
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1454
1455
  CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5,
  		1, 0),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
1457
1458
1459
1460
1461
  CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
  CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1),
  /* SPARC specific uses of XCTL{0,1} general purpose outputs.  */
  CS4231_SINGLE("Line Out Switch", 0, CS4231_PIN_CTRL, 6, 1, 1),
  CS4231_SINGLE("Headphone Out Switch", 0, CS4231_PIN_CTRL, 7, 1, 1)
  };
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1462

32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1463
  static int snd_cs4231_mixer(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1465
  	struct snd_cs4231 *chip = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
  	int err, idx;
5e246b850   Takashi Iwai   ALSA: Kill snd_as...
1467
1468
  	if (snd_BUG_ON(!chip || !chip->pcm))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
1471
1472
  	strcpy(card->mixername, chip->pcm->name);
  
  	for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1473
1474
1475
  		err = snd_ctl_add(card,
  				 snd_ctl_new1(&snd_cs4231_controls[idx], chip));
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
1477
1478
1479
1480
1481
  			return err;
  	}
  	return 0;
  }
  
  static int dev;
a2fefc35a   Takashi Iwai   ALSA: sparc: Conv...
1482
1483
  static int cs4231_attach_begin(struct platform_device *op,
  			       struct snd_card **rcard)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1484
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1485
  	struct snd_card *card;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1486
  	struct snd_cs4231 *chip;
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
1487
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
  
  	*rcard = NULL;
  
  	if (dev >= SNDRV_CARDS)
  		return -ENODEV;
  
  	if (!enable[dev]) {
  		dev++;
  		return -ENOENT;
  	}
a2fefc35a   Takashi Iwai   ALSA: sparc: Conv...
1498
1499
  	err = snd_card_new(&op->dev, index[dev], id[dev], THIS_MODULE,
  			   sizeof(struct snd_cs4231), &card);
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
1500
1501
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1502
1503
1504
  
  	strcpy(card->driver, "CS4231");
  	strcpy(card->shortname, "Sun CS4231");
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1505
1506
  	chip = card->private_data;
  	chip->card = card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
1508
1509
  	*rcard = card;
  	return 0;
  }
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1510
  static int cs4231_attach_finish(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1511
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1512
  	struct snd_cs4231 *chip = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1513
  	int err;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1514
1515
  	err = snd_cs4231_pcm(card);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1516
  		goto out_err;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1517
1518
  	err = snd_cs4231_mixer(card);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
  		goto out_err;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1520
1521
  	err = snd_cs4231_timer(card);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
  		goto out_err;
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1523
1524
  	err = snd_card_register(card);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
  		goto out_err;
afc88ad6b   David S. Miller   cs4231: Convert t...
1526
  	dev_set_drvdata(&chip->op->dev, chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
  
  	dev++;
  	return 0;
  
  out_err:
  	snd_card_free(card);
  	return err;
  }
  
  #ifdef SBUS_SUPPORT
b128254fd   Georg Chini   [SPARC]: More abs...
1537

7d12e780e   David Howells   IRQ: Maintain reg...
1538
  static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id)
b128254fd   Georg Chini   [SPARC]: More abs...
1539
1540
1541
1542
  {
  	unsigned long flags;
  	unsigned char status;
  	u32 csr;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1543
  	struct snd_cs4231 *chip = dev_id;
b128254fd   Georg Chini   [SPARC]: More abs...
1544
1545
  
  	/*This is IRQ is not raised by the cs4231*/
7e52f3dac   Krzysztof Helt   [ALSA] sun-cs4231...
1546
  	if (!(__cs4231_readb(chip, CS4231U(chip, STATUS)) & CS4231_GLOBALIRQ))
b128254fd   Georg Chini   [SPARC]: More abs...
1547
1548
1549
1550
1551
1552
  		return IRQ_NONE;
  
  	/* ACK the APC interrupt. */
  	csr = sbus_readl(chip->port + APCCSR);
  
  	sbus_writel(csr, chip->port + APCCSR);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1553
1554
  	if ((csr & APC_PDMA_READY) &&
  	    (csr & APC_PLAY_INT) &&
b128254fd   Georg Chini   [SPARC]: More abs...
1555
1556
1557
  	    (csr & APC_XINT_PNVA) &&
  	    !(csr & APC_XINT_EMPT))
  			snd_cs4231_play_callback(chip);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1558
1559
  	if ((csr & APC_CDMA_READY) &&
  	    (csr & APC_CAPT_INT) &&
b128254fd   Georg Chini   [SPARC]: More abs...
1560
1561
1562
  	    (csr & APC_XINT_CNVA) &&
  	    !(csr & APC_XINT_EMPT))
  			snd_cs4231_capture_callback(chip);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1563

b128254fd   Georg Chini   [SPARC]: More abs...
1564
1565
1566
1567
1568
  	status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
  
  	if (status & CS4231_TIMER_IRQ) {
  		if (chip->timer)
  			snd_timer_interrupt(chip->timer, chip->timer->sticks);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1569
  	}
b128254fd   Georg Chini   [SPARC]: More abs...
1570
1571
1572
1573
1574
1575
1576
1577
  
  	if ((status & CS4231_RECORD_IRQ) && (csr & APC_CDMA_READY))
  		snd_cs4231_overrange(chip);
  
  	/* ACK the CS4231 interrupt. */
  	spin_lock_irqsave(&chip->lock, flags);
  	snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
  	spin_unlock_irqrestore(&chip->lock, flags);
d35a1b9e1   Georg Chini   [SOUND] Sparc CS4...
1578
  	return IRQ_HANDLED;
b128254fd   Georg Chini   [SPARC]: More abs...
1579
1580
1581
1582
1583
  }
  
  /*
   * SBUS DMA routines
   */
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1584
1585
  static int sbus_dma_request(struct cs4231_dma_control *dma_cont,
  			    dma_addr_t bus_addr, size_t len)
b128254fd   Georg Chini   [SPARC]: More abs...
1586
1587
1588
1589
  {
  	unsigned long flags;
  	u32 test, csr;
  	int err;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1590
  	struct sbus_dma_info *base = &dma_cont->sbus_info;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1591

b128254fd   Georg Chini   [SPARC]: More abs...
1592
1593
1594
1595
1596
1597
  	if (len >= (1 << 24))
  		return -EINVAL;
  	spin_lock_irqsave(&base->lock, flags);
  	csr = sbus_readl(base->regs + APCCSR);
  	err = -EINVAL;
  	test = APC_CDMA_READY;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1598
  	if (base->dir == APC_PLAY)
b128254fd   Georg Chini   [SPARC]: More abs...
1599
1600
1601
1602
  		test = APC_PDMA_READY;
  	if (!(csr & test))
  		goto out;
  	err = -EBUSY;
b128254fd   Georg Chini   [SPARC]: More abs...
1603
  	test = APC_XINT_CNVA;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1604
  	if (base->dir == APC_PLAY)
b128254fd   Georg Chini   [SPARC]: More abs...
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
  		test = APC_XINT_PNVA;
  	if (!(csr & test))
  		goto out;
  	err = 0;
  	sbus_writel(bus_addr, base->regs + base->dir + APCNVA);
  	sbus_writel(len, base->regs + base->dir + APCNC);
  out:
  	spin_unlock_irqrestore(&base->lock, flags);
  	return err;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1615
  static void sbus_dma_prepare(struct cs4231_dma_control *dma_cont, int d)
b128254fd   Georg Chini   [SPARC]: More abs...
1616
1617
1618
  {
  	unsigned long flags;
  	u32 csr, test;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1619
  	struct sbus_dma_info *base = &dma_cont->sbus_info;
b128254fd   Georg Chini   [SPARC]: More abs...
1620
1621
1622
1623
1624
1625
  
  	spin_lock_irqsave(&base->lock, flags);
  	csr = sbus_readl(base->regs + APCCSR);
  	test =  APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
  		APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL |
  		 APC_XINT_PENA;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1626
  	if (base->dir == APC_RECORD)
b128254fd   Georg Chini   [SPARC]: More abs...
1627
1628
1629
1630
1631
1632
  		test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
  			APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL;
  	csr |= test;
  	sbus_writel(csr, base->regs + APCCSR);
  	spin_unlock_irqrestore(&base->lock, flags);
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1633
  static void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on)
b128254fd   Georg Chini   [SPARC]: More abs...
1634
1635
1636
  {
  	unsigned long flags;
  	u32 csr, shift;
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1637
  	struct sbus_dma_info *base = &dma_cont->sbus_info;
b128254fd   Georg Chini   [SPARC]: More abs...
1638
1639
1640
  
  	spin_lock_irqsave(&base->lock, flags);
  	if (!on) {
d35a1b9e1   Georg Chini   [SOUND] Sparc CS4...
1641
1642
  		sbus_writel(0, base->regs + base->dir + APCNC);
  		sbus_writel(0, base->regs + base->dir + APCNVA);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1643
  		if (base->dir == APC_PLAY) {
3daadf330   Georg Chini   [SOUND] CS4231 SB...
1644
1645
1646
  			sbus_writel(0, base->regs + base->dir + APCC);
  			sbus_writel(0, base->regs + base->dir + APCVA);
  		}
d35a1b9e1   Georg Chini   [SOUND] Sparc CS4...
1647

3daadf330   Georg Chini   [SOUND] CS4231 SB...
1648
  		udelay(1200);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1649
  	}
b128254fd   Georg Chini   [SPARC]: More abs...
1650
1651
  	csr = sbus_readl(base->regs + APCCSR);
  	shift = 0;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1652
  	if (base->dir == APC_PLAY)
b128254fd   Georg Chini   [SPARC]: More abs...
1653
1654
1655
1656
  		shift = 1;
  	if (on)
  		csr &= ~(APC_CPAUSE << shift);
  	else
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1657
  		csr |= (APC_CPAUSE << shift);
b128254fd   Georg Chini   [SPARC]: More abs...
1658
1659
1660
1661
1662
1663
  	sbus_writel(csr, base->regs + APCCSR);
  	if (on)
  		csr |= (APC_CDMA_READY << shift);
  	else
  		csr &= ~(APC_CDMA_READY << shift);
  	sbus_writel(csr, base->regs + APCCSR);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1664

b128254fd   Georg Chini   [SPARC]: More abs...
1665
1666
  	spin_unlock_irqrestore(&base->lock, flags);
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1667
  static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont)
b128254fd   Georg Chini   [SPARC]: More abs...
1668
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1669
  	struct sbus_dma_info *base = &dma_cont->sbus_info;
b128254fd   Georg Chini   [SPARC]: More abs...
1670

9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1671
  	return sbus_readl(base->regs + base->dir + APCVA);
b128254fd   Georg Chini   [SPARC]: More abs...
1672
  }
b128254fd   Georg Chini   [SPARC]: More abs...
1673
1674
1675
  /*
   * Init and exit routines
   */
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1676
  static int snd_cs4231_sbus_free(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
  {
2dc115813   Grant Likely   of/device: Replac...
1678
  	struct platform_device *op = chip->op;
ae251031a   David S. Miller   cs4231: Convert S...
1679

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1680
1681
1682
1683
  	if (chip->irq[0])
  		free_irq(chip->irq[0], chip);
  
  	if (chip->port)
ae251031a   David S. Miller   cs4231: Convert S...
1684
  		of_iounmap(&op->resource[0], chip->port, chip->regs_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1685

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686
1687
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1688
  static int snd_cs4231_sbus_dev_free(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1689
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1690
  	struct snd_cs4231 *cp = device->device_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1691
1692
1693
  
  	return snd_cs4231_sbus_free(cp);
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1694
  static struct snd_device_ops snd_cs4231_sbus_dev_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1695
1696
  	.dev_free	=	snd_cs4231_sbus_dev_free,
  };
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1697
1698
1699
  static int snd_cs4231_sbus_create(struct snd_card *card,
  				  struct platform_device *op,
  				  int dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1700
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1701
  	struct snd_cs4231 *chip = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1702
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1703
  	spin_lock_init(&chip->lock);
b128254fd   Georg Chini   [SPARC]: More abs...
1704
1705
  	spin_lock_init(&chip->c_dma.sbus_info.lock);
  	spin_lock_init(&chip->p_dma.sbus_info.lock);
12aa75790   Ingo Molnar   [ALSA] semaphore ...
1706
1707
  	mutex_init(&chip->mce_mutex);
  	mutex_init(&chip->open_mutex);
afc88ad6b   David S. Miller   cs4231: Convert t...
1708
  	chip->op = op;
ae251031a   David S. Miller   cs4231: Convert S...
1709
  	chip->regs_size = resource_size(&op->resource[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1710
1711
  	memcpy(&chip->image, &snd_cs4231_original_image,
  	       sizeof(snd_cs4231_original_image));
ae251031a   David S. Miller   cs4231: Convert S...
1712
1713
  	chip->port = of_ioremap(&op->resource[0], 0,
  				chip->regs_size, "cs4231");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1714
  	if (!chip->port) {
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
1715
1716
  		snd_printdd("cs4231-%d: Unable to map chip registers.
  ", dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1717
1718
  		return -EIO;
  	}
b128254fd   Georg Chini   [SPARC]: More abs...
1719
1720
1721
1722
1723
1724
1725
1726
1727
  	chip->c_dma.sbus_info.regs = chip->port;
  	chip->p_dma.sbus_info.regs = chip->port;
  	chip->c_dma.sbus_info.dir = APC_RECORD;
  	chip->p_dma.sbus_info.dir = APC_PLAY;
  
  	chip->p_dma.prepare = sbus_dma_prepare;
  	chip->p_dma.enable = sbus_dma_enable;
  	chip->p_dma.request = sbus_dma_request;
  	chip->p_dma.address = sbus_dma_addr;
b128254fd   Georg Chini   [SPARC]: More abs...
1728
1729
1730
1731
1732
  
  	chip->c_dma.prepare = sbus_dma_prepare;
  	chip->c_dma.enable = sbus_dma_enable;
  	chip->c_dma.request = sbus_dma_request;
  	chip->c_dma.address = sbus_dma_addr;
5a820fa7e   Georg Chini   [SPARC]: Make SBU...
1733

1636f8ac2   Grant Likely   sparc/of: Move of...
1734
  	if (request_irq(op->archdata.irqs[0], snd_cs4231_sbus_interrupt,
65ca68b30   Thomas Gleixner   [PATCH] irq-flags...
1735
  			IRQF_SHARED, "cs4231", chip)) {
c6387a48c   David S. Miller   [SPARC]: Kill __i...
1736
1737
  		snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d
  ",
1636f8ac2   Grant Likely   sparc/of: Move of...
1738
  			    dev, op->archdata.irqs[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1739
1740
1741
  		snd_cs4231_sbus_free(chip);
  		return -EBUSY;
  	}
1636f8ac2   Grant Likely   sparc/of: Move of...
1742
  	chip->irq[0] = op->archdata.irqs[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
  
  	if (snd_cs4231_probe(chip) < 0) {
  		snd_cs4231_sbus_free(chip);
  		return -ENODEV;
  	}
  	snd_cs4231_init(chip);
  
  	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
  				  chip, &snd_cs4231_sbus_dev_ops)) < 0) {
  		snd_cs4231_sbus_free(chip);
  		return err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1755
1756
  	return 0;
  }
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1757
  static int cs4231_sbus_probe(struct platform_device *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1758
  {
ae251031a   David S. Miller   cs4231: Convert S...
1759
  	struct resource *rp = &op->resource[0];
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1760
  	struct snd_card *card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1761
  	int err;
a2fefc35a   Takashi Iwai   ALSA: sparc: Conv...
1762
  	err = cs4231_attach_begin(op, &card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1763
1764
  	if (err)
  		return err;
5863aa651   Andrew Morton   [PATCH] sparc: re...
1765
  	sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
1767
  		card->shortname,
  		rp->flags & 0xffL,
aa0a2ddc5   Greg Kroah-Hartman   [PATCH] 64bit res...
1768
  		(unsigned long long)rp->start,
1636f8ac2   Grant Likely   sparc/of: Move of...
1769
  		op->archdata.irqs[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770

ae251031a   David S. Miller   cs4231: Convert S...
1771
  	err = snd_cs4231_sbus_create(card, op, dev);
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1772
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1773
1774
1775
  		snd_card_free(card);
  		return err;
  	}
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1776
  	return cs4231_attach_finish(card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
1778
1779
1780
  }
  #endif
  
  #ifdef EBUS_SUPPORT
b128254fd   Georg Chini   [SPARC]: More abs...
1781

9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1782
1783
  static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event,
  					  void *cookie)
b128254fd   Georg Chini   [SPARC]: More abs...
1784
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1785
  	struct snd_cs4231 *chip = cookie;
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1786

b128254fd   Georg Chini   [SPARC]: More abs...
1787
1788
  	snd_cs4231_play_callback(chip);
  }
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1789
1790
  static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p,
  					     int event, void *cookie)
b128254fd   Georg Chini   [SPARC]: More abs...
1791
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1792
  	struct snd_cs4231 *chip = cookie;
b128254fd   Georg Chini   [SPARC]: More abs...
1793
1794
1795
1796
1797
1798
1799
  
  	snd_cs4231_capture_callback(chip);
  }
  
  /*
   * EBUS DMA wrappers
   */
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1800
1801
  static int _ebus_dma_request(struct cs4231_dma_control *dma_cont,
  			     dma_addr_t bus_addr, size_t len)
b128254fd   Georg Chini   [SPARC]: More abs...
1802
1803
1804
  {
  	return ebus_dma_request(&dma_cont->ebus_info, bus_addr, len);
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1805
  static void _ebus_dma_enable(struct cs4231_dma_control *dma_cont, int on)
b128254fd   Georg Chini   [SPARC]: More abs...
1806
1807
1808
  {
  	ebus_dma_enable(&dma_cont->ebus_info, on);
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1809
  static void _ebus_dma_prepare(struct cs4231_dma_control *dma_cont, int dir)
b128254fd   Georg Chini   [SPARC]: More abs...
1810
1811
1812
  {
  	ebus_dma_prepare(&dma_cont->ebus_info, dir);
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1813
  static unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont)
b128254fd   Georg Chini   [SPARC]: More abs...
1814
1815
1816
  {
  	return ebus_dma_addr(&dma_cont->ebus_info);
  }
b128254fd   Georg Chini   [SPARC]: More abs...
1817
1818
1819
  /*
   * Init and exit routines
   */
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1820
  static int snd_cs4231_ebus_free(struct snd_cs4231 *chip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1821
  {
2dc115813   Grant Likely   of/device: Replac...
1822
  	struct platform_device *op = chip->op;
afc88ad6b   David S. Miller   cs4231: Convert t...
1823

b128254fd   Georg Chini   [SPARC]: More abs...
1824
1825
  	if (chip->c_dma.ebus_info.regs) {
  		ebus_dma_unregister(&chip->c_dma.ebus_info);
afc88ad6b   David S. Miller   cs4231: Convert t...
1826
  		of_iounmap(&op->resource[2], chip->c_dma.ebus_info.regs, 0x10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1827
  	}
b128254fd   Georg Chini   [SPARC]: More abs...
1828
1829
  	if (chip->p_dma.ebus_info.regs) {
  		ebus_dma_unregister(&chip->p_dma.ebus_info);
afc88ad6b   David S. Miller   cs4231: Convert t...
1830
  		of_iounmap(&op->resource[1], chip->p_dma.ebus_info.regs, 0x10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1831
1832
1833
  	}
  
  	if (chip->port)
afc88ad6b   David S. Miller   cs4231: Convert t...
1834
  		of_iounmap(&op->resource[0], chip->port, 0x10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1835

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1836
1837
  	return 0;
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1838
  static int snd_cs4231_ebus_dev_free(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1839
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1840
  	struct snd_cs4231 *cp = device->device_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1841
1842
1843
  
  	return snd_cs4231_ebus_free(cp);
  }
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1844
  static struct snd_device_ops snd_cs4231_ebus_dev_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1845
1846
  	.dev_free	=	snd_cs4231_ebus_dev_free,
  };
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1847
1848
1849
  static int snd_cs4231_ebus_create(struct snd_card *card,
  				  struct platform_device *op,
  				  int dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
  {
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1851
  	struct snd_cs4231 *chip = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1852
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1853
  	spin_lock_init(&chip->lock);
b128254fd   Georg Chini   [SPARC]: More abs...
1854
1855
  	spin_lock_init(&chip->c_dma.ebus_info.lock);
  	spin_lock_init(&chip->p_dma.ebus_info.lock);
12aa75790   Ingo Molnar   [ALSA] semaphore ...
1856
1857
  	mutex_init(&chip->mce_mutex);
  	mutex_init(&chip->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1858
  	chip->flags |= CS4231_FLAG_EBUS;
afc88ad6b   David S. Miller   cs4231: Convert t...
1859
  	chip->op = op;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1860
1861
  	memcpy(&chip->image, &snd_cs4231_original_image,
  	       sizeof(snd_cs4231_original_image));
b128254fd   Georg Chini   [SPARC]: More abs...
1862
1863
1864
1865
  	strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)");
  	chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
  	chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback;
  	chip->c_dma.ebus_info.client_cookie = chip;
1636f8ac2   Grant Likely   sparc/of: Move of...
1866
  	chip->c_dma.ebus_info.irq = op->archdata.irqs[0];
b128254fd   Georg Chini   [SPARC]: More abs...
1867
1868
1869
1870
  	strcpy(chip->p_dma.ebus_info.name, "cs4231(play)");
  	chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
  	chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback;
  	chip->p_dma.ebus_info.client_cookie = chip;
1636f8ac2   Grant Likely   sparc/of: Move of...
1871
  	chip->p_dma.ebus_info.irq = op->archdata.irqs[1];
b128254fd   Georg Chini   [SPARC]: More abs...
1872
1873
1874
1875
1876
  
  	chip->p_dma.prepare = _ebus_dma_prepare;
  	chip->p_dma.enable = _ebus_dma_enable;
  	chip->p_dma.request = _ebus_dma_request;
  	chip->p_dma.address = _ebus_dma_addr;
b128254fd   Georg Chini   [SPARC]: More abs...
1877
1878
1879
1880
1881
  
  	chip->c_dma.prepare = _ebus_dma_prepare;
  	chip->c_dma.enable = _ebus_dma_enable;
  	chip->c_dma.request = _ebus_dma_request;
  	chip->c_dma.address = _ebus_dma_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1882

afc88ad6b   David S. Miller   cs4231: Convert t...
1883
1884
1885
1886
1887
  	chip->port = of_ioremap(&op->resource[0], 0, 0x10, "cs4231");
  	chip->p_dma.ebus_info.regs =
  		of_ioremap(&op->resource[1], 0, 0x10, "cs4231_pdma");
  	chip->c_dma.ebus_info.regs =
  		of_ioremap(&op->resource[2], 0, 0x10, "cs4231_cdma");
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1888
1889
  	if (!chip->port || !chip->p_dma.ebus_info.regs ||
  	    !chip->c_dma.ebus_info.regs) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1890
  		snd_cs4231_ebus_free(chip);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
1891
1892
  		snd_printdd("cs4231-%d: Unable to map chip registers.
  ", dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1893
1894
  		return -EIO;
  	}
b128254fd   Georg Chini   [SPARC]: More abs...
1895
  	if (ebus_dma_register(&chip->c_dma.ebus_info)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1896
  		snd_cs4231_ebus_free(chip);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1897
1898
1899
  		snd_printdd("cs4231-%d: Unable to register EBUS capture DMA
  ",
  			    dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1900
1901
  		return -EBUSY;
  	}
b128254fd   Georg Chini   [SPARC]: More abs...
1902
  	if (ebus_dma_irq_enable(&chip->c_dma.ebus_info, 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1903
  		snd_cs4231_ebus_free(chip);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1904
1905
1906
  		snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ
  ",
  			    dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1907
1908
  		return -EBUSY;
  	}
b128254fd   Georg Chini   [SPARC]: More abs...
1909
  	if (ebus_dma_register(&chip->p_dma.ebus_info)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1910
  		snd_cs4231_ebus_free(chip);
9e9abb4f1   Krzysztof Helt   [ALSA] sun-cs4231...
1911
1912
1913
  		snd_printdd("cs4231-%d: Unable to register EBUS play DMA
  ",
  			    dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1914
1915
  		return -EBUSY;
  	}
b128254fd   Georg Chini   [SPARC]: More abs...
1916
  	if (ebus_dma_irq_enable(&chip->p_dma.ebus_info, 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1917
  		snd_cs4231_ebus_free(chip);
a131430c2   Christopher Zimmermann   [SPARC] cs4231: F...
1918
1919
  		snd_printdd("cs4231-%d: Unable to enable EBUS play IRQ
  ", dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
  		return -EBUSY;
  	}
  
  	if (snd_cs4231_probe(chip) < 0) {
  		snd_cs4231_ebus_free(chip);
  		return -ENODEV;
  	}
  	snd_cs4231_init(chip);
  
  	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
  				  chip, &snd_cs4231_ebus_dev_ops)) < 0) {
  		snd_cs4231_ebus_free(chip);
  		return err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1934
1935
  	return 0;
  }
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1936
  static int cs4231_ebus_probe(struct platform_device *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
  {
be9b7e8c0   Takashi Iwai   [ALSA] Remove xxx...
1938
  	struct snd_card *card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
  	int err;
a2fefc35a   Takashi Iwai   ALSA: sparc: Conv...
1940
  	err = cs4231_attach_begin(op, &card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1941
1942
  	if (err)
  		return err;
3f4528d6e   Sam Ravnborg   sparc64: Fix unsi...
1943
  	sprintf(card->longname, "%s at 0x%llx, irq %d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1944
  		card->shortname,
afc88ad6b   David S. Miller   cs4231: Convert t...
1945
  		op->resource[0].start,
1636f8ac2   Grant Likely   sparc/of: Move of...
1946
  		op->archdata.irqs[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947

afc88ad6b   David S. Miller   cs4231: Convert t...
1948
  	err = snd_cs4231_ebus_create(card, op, dev);
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1949
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1950
1951
1952
  		snd_card_free(card);
  		return err;
  	}
c6c2d57b8   Krzysztof Helt   [ALSA] sun-cs4231...
1953
  	return cs4231_attach_finish(card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1954
1955
  }
  #endif
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1956
  static int cs4231_probe(struct platform_device *op)
afc88ad6b   David S. Miller   cs4231: Convert t...
1957
1958
  {
  #ifdef EBUS_SUPPORT
61c7a080a   Grant Likely   of: Always use 's...
1959
  	if (!strcmp(op->dev.of_node->parent->name, "ebus"))
f07eb223a   Grant Likely   dt/sound: Elimina...
1960
  		return cs4231_ebus_probe(op);
afc88ad6b   David S. Miller   cs4231: Convert t...
1961
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
  #ifdef SBUS_SUPPORT
61c7a080a   Grant Likely   of: Always use 's...
1963
1964
  	if (!strcmp(op->dev.of_node->parent->name, "sbus") ||
  	    !strcmp(op->dev.of_node->parent->name, "sbi"))
f07eb223a   Grant Likely   dt/sound: Elimina...
1965
  		return cs4231_sbus_probe(op);
afc88ad6b   David S. Miller   cs4231: Convert t...
1966
1967
1968
  #endif
  	return -ENODEV;
  }
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1969
  static int cs4231_remove(struct platform_device *op)
afc88ad6b   David S. Miller   cs4231: Convert t...
1970
1971
1972
1973
1974
1975
1976
  {
  	struct snd_cs4231 *chip = dev_get_drvdata(&op->dev);
  
  	snd_card_free(chip->card);
  
  	return 0;
  }
fd098316e   David S. Miller   sparc: Annotate o...
1977
  static const struct of_device_id cs4231_match[] = {
ae251031a   David S. Miller   cs4231: Convert S...
1978
1979
1980
  	{
  		.name = "SUNW,CS4231",
  	},
afc88ad6b   David S. Miller   cs4231: Convert t...
1981
1982
1983
1984
  	{
  		.name = "audio",
  		.compatible = "SUNW,CS4231",
  	},
ae251031a   David S. Miller   cs4231: Convert S...
1985
1986
1987
1988
  	{},
  };
  
  MODULE_DEVICE_TABLE(of, cs4231_match);
f07eb223a   Grant Likely   dt/sound: Elimina...
1989
  static struct platform_driver cs4231_driver = {
4018294b5   Grant Likely   of: Remove duplic...
1990
1991
  	.driver = {
  		.name = "audio",
4018294b5   Grant Likely   of: Remove duplic...
1992
1993
  		.of_match_table = cs4231_match,
  	},
ae251031a   David S. Miller   cs4231: Convert S...
1994
  	.probe		= cs4231_probe,
32e02a7b6   Bill Pemberton   ALSA: sparc: remo...
1995
  	.remove		= cs4231_remove,
ae251031a   David S. Miller   cs4231: Convert S...
1996
  };
ae251031a   David S. Miller   cs4231: Convert S...
1997

a09452eeb   Axel Lin   ALSA: convert sou...
1998
  module_platform_driver(cs4231_driver);