1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*****************************************************************************
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
5*4882a593Smuzhiyun * Jean-Christian Hassler <jhassler@free.fr>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This file is part of the Audiowerk2 ALSA driver
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun *****************************************************************************/
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define AW2_SAA7146_M
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/pci.h>
15*4882a593Smuzhiyun #include <linux/interrupt.h>
16*4882a593Smuzhiyun #include <linux/delay.h>
17*4882a593Smuzhiyun #include <linux/io.h>
18*4882a593Smuzhiyun #include <sound/core.h>
19*4882a593Smuzhiyun #include <sound/initval.h>
20*4882a593Smuzhiyun #include <sound/pcm.h>
21*4882a593Smuzhiyun #include <sound/pcm_params.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "saa7146.h"
24*4882a593Smuzhiyun #include "aw2-saa7146.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include "aw2-tsl.c"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #define WRITEREG(value, addr) writel((value), chip->base_addr + (addr))
29*4882a593Smuzhiyun #define READREG(addr) readl(chip->base_addr + (addr))
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun static struct snd_aw2_saa7146_cb_param
32*4882a593Smuzhiyun arr_substream_it_playback_cb[NB_STREAM_PLAYBACK];
33*4882a593Smuzhiyun static struct snd_aw2_saa7146_cb_param
34*4882a593Smuzhiyun arr_substream_it_capture_cb[NB_STREAM_CAPTURE];
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun static int snd_aw2_saa7146_get_limit(int size);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* chip-specific destructor */
snd_aw2_saa7146_free(struct snd_aw2_saa7146 * chip)39*4882a593Smuzhiyun int snd_aw2_saa7146_free(struct snd_aw2_saa7146 *chip)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun /* disable all irqs */
42*4882a593Smuzhiyun WRITEREG(0, IER);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /* reset saa7146 */
45*4882a593Smuzhiyun WRITEREG((MRST_N << 16), MC1);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* Unset base addr */
48*4882a593Smuzhiyun chip->base_addr = NULL;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun return 0;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
snd_aw2_saa7146_setup(struct snd_aw2_saa7146 * chip,void __iomem * pci_base_addr)53*4882a593Smuzhiyun void snd_aw2_saa7146_setup(struct snd_aw2_saa7146 *chip,
54*4882a593Smuzhiyun void __iomem *pci_base_addr)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun /* set PCI burst/threshold
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun Burst length definition
59*4882a593Smuzhiyun VALUE BURST LENGTH
60*4882a593Smuzhiyun 000 1 Dword
61*4882a593Smuzhiyun 001 2 Dwords
62*4882a593Smuzhiyun 010 4 Dwords
63*4882a593Smuzhiyun 011 8 Dwords
64*4882a593Smuzhiyun 100 16 Dwords
65*4882a593Smuzhiyun 101 32 Dwords
66*4882a593Smuzhiyun 110 64 Dwords
67*4882a593Smuzhiyun 111 128 Dwords
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun Threshold definition
70*4882a593Smuzhiyun VALUE WRITE MODE READ MODE
71*4882a593Smuzhiyun 00 1 Dword of valid data 1 empty Dword
72*4882a593Smuzhiyun 01 4 Dwords of valid data 4 empty Dwords
73*4882a593Smuzhiyun 10 8 Dwords of valid data 8 empty Dwords
74*4882a593Smuzhiyun 11 16 Dwords of valid data 16 empty Dwords */
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun unsigned int acon2;
77*4882a593Smuzhiyun unsigned int acon1 = 0;
78*4882a593Smuzhiyun int i;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* Set base addr */
81*4882a593Smuzhiyun chip->base_addr = pci_base_addr;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* disable all irqs */
84*4882a593Smuzhiyun WRITEREG(0, IER);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /* reset saa7146 */
87*4882a593Smuzhiyun WRITEREG((MRST_N << 16), MC1);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* enable audio interface */
90*4882a593Smuzhiyun #ifdef __BIG_ENDIAN
91*4882a593Smuzhiyun acon1 |= A1_SWAP;
92*4882a593Smuzhiyun acon1 |= A2_SWAP;
93*4882a593Smuzhiyun #endif
94*4882a593Smuzhiyun /* WS0_CTRL, WS0_SYNC: input TSL1, I2S */
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* At initialization WS1 and WS2 are disabled (configured as input) */
97*4882a593Smuzhiyun acon1 |= 0 * WS1_CTRL;
98*4882a593Smuzhiyun acon1 |= 0 * WS2_CTRL;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* WS4 is not used. So it must not restart A2.
101*4882a593Smuzhiyun This is why it is configured as output (force to low) */
102*4882a593Smuzhiyun acon1 |= 3 * WS4_CTRL;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* WS3_CTRL, WS3_SYNC: output TSL2, I2S */
105*4882a593Smuzhiyun acon1 |= 2 * WS3_CTRL;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /* A1 and A2 are active and asynchronous */
108*4882a593Smuzhiyun acon1 |= 3 * AUDIO_MODE;
109*4882a593Smuzhiyun WRITEREG(acon1, ACON1);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* The following comes from original windows driver.
112*4882a593Smuzhiyun It is needed to have a correct behavior of input and output
113*4882a593Smuzhiyun simultenously, but I don't know why ! */
114*4882a593Smuzhiyun WRITEREG(3 * (BurstA1_in) + 3 * (ThreshA1_in) +
115*4882a593Smuzhiyun 3 * (BurstA1_out) + 3 * (ThreshA1_out) +
116*4882a593Smuzhiyun 3 * (BurstA2_out) + 3 * (ThreshA2_out), PCI_BT_A);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun /* enable audio port pins */
119*4882a593Smuzhiyun WRITEREG((EAP << 16) | EAP, MC1);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* enable I2C */
122*4882a593Smuzhiyun WRITEREG((EI2C << 16) | EI2C, MC1);
123*4882a593Smuzhiyun /* enable interrupts */
124*4882a593Smuzhiyun WRITEREG(A1_out | A2_out | A1_in | IIC_S | IIC_E, IER);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /* audio configuration */
127*4882a593Smuzhiyun acon2 = A2_CLKSRC | BCLK1_OEN;
128*4882a593Smuzhiyun WRITEREG(acon2, ACON2);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* By default use analog input */
131*4882a593Smuzhiyun snd_aw2_saa7146_use_digital_input(chip, 0);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* TSL setup */
134*4882a593Smuzhiyun for (i = 0; i < 8; ++i) {
135*4882a593Smuzhiyun WRITEREG(tsl1[i], TSL1 + (i * 4));
136*4882a593Smuzhiyun WRITEREG(tsl2[i], TSL2 + (i * 4));
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 * chip,int stream_number,unsigned long dma_addr,unsigned long period_size,unsigned long buffer_size)141*4882a593Smuzhiyun void snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip,
142*4882a593Smuzhiyun int stream_number,
143*4882a593Smuzhiyun unsigned long dma_addr,
144*4882a593Smuzhiyun unsigned long period_size,
145*4882a593Smuzhiyun unsigned long buffer_size)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun unsigned long dw_page, dw_limit;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* Configure DMA for substream
150*4882a593Smuzhiyun Configuration informations: ALSA has allocated continuous memory
151*4882a593Smuzhiyun pages. So we don't need to use MMU of saa7146.
152*4882a593Smuzhiyun */
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /* No MMU -> nothing to do with PageA1, we only configure the limit of
155*4882a593Smuzhiyun PageAx_out register */
156*4882a593Smuzhiyun /* Disable MMU */
157*4882a593Smuzhiyun dw_page = (0L << 11);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun /* Configure Limit for DMA access.
160*4882a593Smuzhiyun The limit register defines an address limit, which generates
161*4882a593Smuzhiyun an interrupt if passed by the actual PCI address pointer.
162*4882a593Smuzhiyun '0001' means an interrupt will be generated if the lower
163*4882a593Smuzhiyun 6 bits (64 bytes) of the PCI address are zero. '0010'
164*4882a593Smuzhiyun defines a limit of 128 bytes, '0011' one of 256 bytes, and
165*4882a593Smuzhiyun so on up to 1 Mbyte defined by '1111'. This interrupt range
166*4882a593Smuzhiyun can be calculated as follows:
167*4882a593Smuzhiyun Range = 2^(5 + Limit) bytes.
168*4882a593Smuzhiyun */
169*4882a593Smuzhiyun dw_limit = snd_aw2_saa7146_get_limit(period_size);
170*4882a593Smuzhiyun dw_page |= (dw_limit << 4);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (stream_number == 0) {
173*4882a593Smuzhiyun WRITEREG(dw_page, PageA2_out);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /* Base address for DMA transfert. */
176*4882a593Smuzhiyun /* This address has been reserved by ALSA. */
177*4882a593Smuzhiyun /* This is a physical address */
178*4882a593Smuzhiyun WRITEREG(dma_addr, BaseA2_out);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* Define upper limit for DMA access */
181*4882a593Smuzhiyun WRITEREG(dma_addr + buffer_size, ProtA2_out);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun } else if (stream_number == 1) {
184*4882a593Smuzhiyun WRITEREG(dw_page, PageA1_out);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* Base address for DMA transfert. */
187*4882a593Smuzhiyun /* This address has been reserved by ALSA. */
188*4882a593Smuzhiyun /* This is a physical address */
189*4882a593Smuzhiyun WRITEREG(dma_addr, BaseA1_out);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /* Define upper limit for DMA access */
192*4882a593Smuzhiyun WRITEREG(dma_addr + buffer_size, ProtA1_out);
193*4882a593Smuzhiyun } else {
194*4882a593Smuzhiyun pr_err("aw2: snd_aw2_saa7146_pcm_init_playback: "
195*4882a593Smuzhiyun "Substream number is not 0 or 1 -> not managed\n");
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 * chip,int stream_number,unsigned long dma_addr,unsigned long period_size,unsigned long buffer_size)199*4882a593Smuzhiyun void snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip,
200*4882a593Smuzhiyun int stream_number, unsigned long dma_addr,
201*4882a593Smuzhiyun unsigned long period_size,
202*4882a593Smuzhiyun unsigned long buffer_size)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun unsigned long dw_page, dw_limit;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /* Configure DMA for substream
207*4882a593Smuzhiyun Configuration informations: ALSA has allocated continuous memory
208*4882a593Smuzhiyun pages. So we don't need to use MMU of saa7146.
209*4882a593Smuzhiyun */
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* No MMU -> nothing to do with PageA1, we only configure the limit of
212*4882a593Smuzhiyun PageAx_out register */
213*4882a593Smuzhiyun /* Disable MMU */
214*4882a593Smuzhiyun dw_page = (0L << 11);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /* Configure Limit for DMA access.
217*4882a593Smuzhiyun The limit register defines an address limit, which generates
218*4882a593Smuzhiyun an interrupt if passed by the actual PCI address pointer.
219*4882a593Smuzhiyun '0001' means an interrupt will be generated if the lower
220*4882a593Smuzhiyun 6 bits (64 bytes) of the PCI address are zero. '0010'
221*4882a593Smuzhiyun defines a limit of 128 bytes, '0011' one of 256 bytes, and
222*4882a593Smuzhiyun so on up to 1 Mbyte defined by '1111'. This interrupt range
223*4882a593Smuzhiyun can be calculated as follows:
224*4882a593Smuzhiyun Range = 2^(5 + Limit) bytes.
225*4882a593Smuzhiyun */
226*4882a593Smuzhiyun dw_limit = snd_aw2_saa7146_get_limit(period_size);
227*4882a593Smuzhiyun dw_page |= (dw_limit << 4);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun if (stream_number == 0) {
230*4882a593Smuzhiyun WRITEREG(dw_page, PageA1_in);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /* Base address for DMA transfert. */
233*4882a593Smuzhiyun /* This address has been reserved by ALSA. */
234*4882a593Smuzhiyun /* This is a physical address */
235*4882a593Smuzhiyun WRITEREG(dma_addr, BaseA1_in);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /* Define upper limit for DMA access */
238*4882a593Smuzhiyun WRITEREG(dma_addr + buffer_size, ProtA1_in);
239*4882a593Smuzhiyun } else {
240*4882a593Smuzhiyun pr_err("aw2: snd_aw2_saa7146_pcm_init_capture: "
241*4882a593Smuzhiyun "Substream number is not 0 -> not managed\n");
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number,snd_aw2_saa7146_it_cb p_it_callback,void * p_callback_param)245*4882a593Smuzhiyun void snd_aw2_saa7146_define_it_playback_callback(unsigned int stream_number,
246*4882a593Smuzhiyun snd_aw2_saa7146_it_cb
247*4882a593Smuzhiyun p_it_callback,
248*4882a593Smuzhiyun void *p_callback_param)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun if (stream_number < NB_STREAM_PLAYBACK) {
251*4882a593Smuzhiyun arr_substream_it_playback_cb[stream_number].p_it_callback =
252*4882a593Smuzhiyun (snd_aw2_saa7146_it_cb) p_it_callback;
253*4882a593Smuzhiyun arr_substream_it_playback_cb[stream_number].p_callback_param =
254*4882a593Smuzhiyun (void *)p_callback_param;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number,snd_aw2_saa7146_it_cb p_it_callback,void * p_callback_param)258*4882a593Smuzhiyun void snd_aw2_saa7146_define_it_capture_callback(unsigned int stream_number,
259*4882a593Smuzhiyun snd_aw2_saa7146_it_cb
260*4882a593Smuzhiyun p_it_callback,
261*4882a593Smuzhiyun void *p_callback_param)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun if (stream_number < NB_STREAM_CAPTURE) {
264*4882a593Smuzhiyun arr_substream_it_capture_cb[stream_number].p_it_callback =
265*4882a593Smuzhiyun (snd_aw2_saa7146_it_cb) p_it_callback;
266*4882a593Smuzhiyun arr_substream_it_capture_cb[stream_number].p_callback_param =
267*4882a593Smuzhiyun (void *)p_callback_param;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
snd_aw2_saa7146_pcm_trigger_start_playback(struct snd_aw2_saa7146 * chip,int stream_number)271*4882a593Smuzhiyun void snd_aw2_saa7146_pcm_trigger_start_playback(struct snd_aw2_saa7146 *chip,
272*4882a593Smuzhiyun int stream_number)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun unsigned int acon1 = 0;
275*4882a593Smuzhiyun /* In aw8 driver, dma transfert is always active. It is
276*4882a593Smuzhiyun started and stopped in a larger "space" */
277*4882a593Smuzhiyun acon1 = READREG(ACON1);
278*4882a593Smuzhiyun if (stream_number == 0) {
279*4882a593Smuzhiyun WRITEREG((TR_E_A2_OUT << 16) | TR_E_A2_OUT, MC1);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun /* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
282*4882a593Smuzhiyun acon1 |= 2 * WS2_CTRL;
283*4882a593Smuzhiyun WRITEREG(acon1, ACON1);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun } else if (stream_number == 1) {
286*4882a593Smuzhiyun WRITEREG((TR_E_A1_OUT << 16) | TR_E_A1_OUT, MC1);
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
289*4882a593Smuzhiyun acon1 |= 1 * WS1_CTRL;
290*4882a593Smuzhiyun WRITEREG(acon1, ACON1);
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
snd_aw2_saa7146_pcm_trigger_stop_playback(struct snd_aw2_saa7146 * chip,int stream_number)294*4882a593Smuzhiyun void snd_aw2_saa7146_pcm_trigger_stop_playback(struct snd_aw2_saa7146 *chip,
295*4882a593Smuzhiyun int stream_number)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun unsigned int acon1 = 0;
298*4882a593Smuzhiyun acon1 = READREG(ACON1);
299*4882a593Smuzhiyun if (stream_number == 0) {
300*4882a593Smuzhiyun /* WS2_CTRL, WS2_SYNC: output TSL2, I2S */
301*4882a593Smuzhiyun acon1 &= ~(3 * WS2_CTRL);
302*4882a593Smuzhiyun WRITEREG(acon1, ACON1);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun WRITEREG((TR_E_A2_OUT << 16), MC1);
305*4882a593Smuzhiyun } else if (stream_number == 1) {
306*4882a593Smuzhiyun /* WS1_CTRL, WS1_SYNC: output TSL1, I2S */
307*4882a593Smuzhiyun acon1 &= ~(3 * WS1_CTRL);
308*4882a593Smuzhiyun WRITEREG(acon1, ACON1);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun WRITEREG((TR_E_A1_OUT << 16), MC1);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
snd_aw2_saa7146_pcm_trigger_start_capture(struct snd_aw2_saa7146 * chip,int stream_number)314*4882a593Smuzhiyun void snd_aw2_saa7146_pcm_trigger_start_capture(struct snd_aw2_saa7146 *chip,
315*4882a593Smuzhiyun int stream_number)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun /* In aw8 driver, dma transfert is always active. It is
318*4882a593Smuzhiyun started and stopped in a larger "space" */
319*4882a593Smuzhiyun if (stream_number == 0)
320*4882a593Smuzhiyun WRITEREG((TR_E_A1_IN << 16) | TR_E_A1_IN, MC1);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
snd_aw2_saa7146_pcm_trigger_stop_capture(struct snd_aw2_saa7146 * chip,int stream_number)323*4882a593Smuzhiyun void snd_aw2_saa7146_pcm_trigger_stop_capture(struct snd_aw2_saa7146 *chip,
324*4882a593Smuzhiyun int stream_number)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun if (stream_number == 0)
327*4882a593Smuzhiyun WRITEREG((TR_E_A1_IN << 16), MC1);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
snd_aw2_saa7146_interrupt(int irq,void * dev_id)330*4882a593Smuzhiyun irqreturn_t snd_aw2_saa7146_interrupt(int irq, void *dev_id)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun unsigned int isr;
333*4882a593Smuzhiyun __always_unused unsigned int iicsta;
334*4882a593Smuzhiyun struct snd_aw2_saa7146 *chip = dev_id;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun isr = READREG(ISR);
337*4882a593Smuzhiyun if (!isr)
338*4882a593Smuzhiyun return IRQ_NONE;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun WRITEREG(isr, ISR);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (isr & (IIC_S | IIC_E)) {
343*4882a593Smuzhiyun iicsta = READREG(IICSTA);
344*4882a593Smuzhiyun WRITEREG(0x100, IICSTA);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (isr & A1_out) {
348*4882a593Smuzhiyun if (arr_substream_it_playback_cb[1].p_it_callback != NULL) {
349*4882a593Smuzhiyun arr_substream_it_playback_cb[1].
350*4882a593Smuzhiyun p_it_callback(arr_substream_it_playback_cb[1].
351*4882a593Smuzhiyun p_callback_param);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun if (isr & A2_out) {
355*4882a593Smuzhiyun if (arr_substream_it_playback_cb[0].p_it_callback != NULL) {
356*4882a593Smuzhiyun arr_substream_it_playback_cb[0].
357*4882a593Smuzhiyun p_it_callback(arr_substream_it_playback_cb[0].
358*4882a593Smuzhiyun p_callback_param);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun if (isr & A1_in) {
363*4882a593Smuzhiyun if (arr_substream_it_capture_cb[0].p_it_callback != NULL) {
364*4882a593Smuzhiyun arr_substream_it_capture_cb[0].
365*4882a593Smuzhiyun p_it_callback(arr_substream_it_capture_cb[0].
366*4882a593Smuzhiyun p_callback_param);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun return IRQ_HANDLED;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
snd_aw2_saa7146_get_hw_ptr_playback(struct snd_aw2_saa7146 * chip,int stream_number,unsigned char * start_addr,unsigned int buffer_size)372*4882a593Smuzhiyun unsigned int snd_aw2_saa7146_get_hw_ptr_playback(struct snd_aw2_saa7146 *chip,
373*4882a593Smuzhiyun int stream_number,
374*4882a593Smuzhiyun unsigned char *start_addr,
375*4882a593Smuzhiyun unsigned int buffer_size)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun long pci_adp = 0;
378*4882a593Smuzhiyun size_t ptr = 0;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun if (stream_number == 0) {
381*4882a593Smuzhiyun pci_adp = READREG(PCI_ADP3);
382*4882a593Smuzhiyun ptr = pci_adp - (long)start_addr;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun if (ptr == buffer_size)
385*4882a593Smuzhiyun ptr = 0;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun if (stream_number == 1) {
388*4882a593Smuzhiyun pci_adp = READREG(PCI_ADP1);
389*4882a593Smuzhiyun ptr = pci_adp - (size_t) start_addr;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun if (ptr == buffer_size)
392*4882a593Smuzhiyun ptr = 0;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun return ptr;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
snd_aw2_saa7146_get_hw_ptr_capture(struct snd_aw2_saa7146 * chip,int stream_number,unsigned char * start_addr,unsigned int buffer_size)397*4882a593Smuzhiyun unsigned int snd_aw2_saa7146_get_hw_ptr_capture(struct snd_aw2_saa7146 *chip,
398*4882a593Smuzhiyun int stream_number,
399*4882a593Smuzhiyun unsigned char *start_addr,
400*4882a593Smuzhiyun unsigned int buffer_size)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun size_t pci_adp = 0;
403*4882a593Smuzhiyun size_t ptr = 0;
404*4882a593Smuzhiyun if (stream_number == 0) {
405*4882a593Smuzhiyun pci_adp = READREG(PCI_ADP2);
406*4882a593Smuzhiyun ptr = pci_adp - (size_t) start_addr;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun if (ptr == buffer_size)
409*4882a593Smuzhiyun ptr = 0;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun return ptr;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
snd_aw2_saa7146_use_digital_input(struct snd_aw2_saa7146 * chip,int use_digital)414*4882a593Smuzhiyun void snd_aw2_saa7146_use_digital_input(struct snd_aw2_saa7146 *chip,
415*4882a593Smuzhiyun int use_digital)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun /* FIXME: switch between analog and digital input does not always work.
418*4882a593Smuzhiyun It can produce a kind of white noise. It seams that received data
419*4882a593Smuzhiyun are inverted sometime (endian inversion). Why ? I don't know, maybe
420*4882a593Smuzhiyun a problem of synchronization... However for the time being I have
421*4882a593Smuzhiyun not found the problem. Workaround: switch again (and again) between
422*4882a593Smuzhiyun digital and analog input until it works. */
423*4882a593Smuzhiyun if (use_digital)
424*4882a593Smuzhiyun WRITEREG(0x40, GPIO_CTRL);
425*4882a593Smuzhiyun else
426*4882a593Smuzhiyun WRITEREG(0x50, GPIO_CTRL);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
snd_aw2_saa7146_is_using_digital_input(struct snd_aw2_saa7146 * chip)429*4882a593Smuzhiyun int snd_aw2_saa7146_is_using_digital_input(struct snd_aw2_saa7146 *chip)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun unsigned int reg_val = READREG(GPIO_CTRL);
432*4882a593Smuzhiyun if ((reg_val & 0xFF) == 0x40)
433*4882a593Smuzhiyun return 1;
434*4882a593Smuzhiyun else
435*4882a593Smuzhiyun return 0;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun
snd_aw2_saa7146_get_limit(int size)439*4882a593Smuzhiyun static int snd_aw2_saa7146_get_limit(int size)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun int limitsize = 32;
442*4882a593Smuzhiyun int limit = 0;
443*4882a593Smuzhiyun while (limitsize < size) {
444*4882a593Smuzhiyun limitsize *= 2;
445*4882a593Smuzhiyun limit++;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun return limit;
448*4882a593Smuzhiyun }
449