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