ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / media / video / cx88 / cx88-tvaudio.c
1 /*
2     cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
3
4      (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version]
5      (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
6      (c) 2003 Gerd Knorr <kraxel@bytesex.org>
7
8     -----------------------------------------------------------------------
9
10     Lot of voodoo here.  Even the data sheet doesn't help to
11     understand what is going on here, the documentation for the audio
12     part of the cx2388x chip is *very* bad.
13
14     Some of this comes from party done linux driver sources I got from
15     [undocumented].
16
17     Some comes from the dscaler sources, one of the dscaler driver guy works
18     for Conexant ...
19     
20     -----------------------------------------------------------------------
21     
22     This program is free software; you can redistribute it and/or modify
23     it under the terms of the GNU General Public License as published by
24     the Free Software Foundation; either version 2 of the License, or
25     (at your option) any later version.
26
27     This program is distributed in the hope that it will be useful,
28     but WITHOUT ANY WARRANTY; without even the implied warranty of
29     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30     GNU General Public License for more details.
31
32     You should have received a copy of the GNU General Public License
33     along with this program; if not, write to the Free Software
34     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 */
36
37 #include <linux/module.h>
38 #include <linux/errno.h>
39 #include <linux/kernel.h>
40 #include <linux/slab.h>
41 #include <linux/mm.h>
42 #include <linux/poll.h>
43 #include <linux/pci.h>
44 #include <linux/signal.h>
45 #include <linux/ioport.h>
46 #include <linux/sched.h>
47 #include <linux/types.h>
48 #include <linux/interrupt.h>
49 #include <linux/vmalloc.h>
50 #include <linux/init.h>
51
52 #include "cx88.h"
53
54 static unsigned int audio_debug = 1;
55 MODULE_PARM(audio_debug,"i");
56 MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
57
58 #define dprintk(fmt, arg...)    if (audio_debug) \
59         printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
60
61 /* ----------------------------------------------------------- */
62
63 struct rlist {
64         u32 reg;
65         u32 val;
66 };
67
68 static void set_audio_registers(struct cx8800_dev *dev,
69                                 const struct rlist *l)
70 {
71         int i;
72
73         for (i = 0; l[i].reg; i++) {
74                 switch (l[i].reg) {
75                 case AUD_PDF_DDS_CNST_BYTE2:
76                 case AUD_PDF_DDS_CNST_BYTE1:
77                 case AUD_PDF_DDS_CNST_BYTE0:
78                 case AUD_QAM_MODE:
79                 case AUD_PHACC_FREQ_8MSB:
80                 case AUD_PHACC_FREQ_8LSB:
81                         cx_writeb(l[i].reg, l[i].val);
82                         break;
83                 default:
84                         cx_write(l[i].reg, l[i].val);
85                         break;
86                 }
87         }
88 }
89
90 static void set_audio_start(struct cx8800_dev *dev,
91                             u32 mode, u32 ctl)
92 {
93         // mute
94         cx_write(AUD_VOL_CTL,       (1 << 6));
95
96         //  increase level of input by 12dB
97         cx_write(AUD_AFE_12DB_EN,   0x0001);
98
99         // start programming
100         cx_write(AUD_CTL,           0x0000);
101         cx_write(AUD_INIT,          mode);
102         cx_write(AUD_INIT_LD,       0x0001);
103         cx_write(AUD_SOFT_RESET,    0x0001);
104
105         cx_write(AUD_CTL,           ctl);
106 }
107
108 static void set_audio_finish(struct cx8800_dev *dev)
109 {
110         u32 volume;
111
112         // finish programming
113         cx_write(AUD_SOFT_RESET, 0x0000);
114
115         // start audio processing
116         cx_set(AUD_CTL, EN_DAC_ENABLE);
117
118         // unmute
119         volume = cx_sread(SHADOW_AUD_VOL_CTL);
120         cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume);
121 }
122
123 /* ----------------------------------------------------------- */
124
125 static void set_audio_standard_BTSC(struct cx8800_dev *dev, unsigned int sap)
126 {
127         static const struct rlist btsc[] = {
128                 /* Magic stuff from leadtek driver + datasheet.*/
129                 { AUD_DBX_IN_GAIN,   0x4734 },
130                 { AUD_DBX_WBE_GAIN,  0x4640 },
131                 { AUD_DBX_SE_GAIN,   0x8D31 },
132                 { AUD_DEEMPH0_G0,    0x1604 },
133                 { AUD_PHASE_FIX_CTL, 0x0020 },
134
135                 { /* end of list */ },
136         };
137
138         dprintk("%s (status: unknown)\n",__FUNCTION__);
139         set_audio_start(dev, 0x0001,
140                         EN_BTSC_AUTO_STEREO);
141         set_audio_registers(dev, btsc);
142         set_audio_finish(dev);
143 }
144
145 static void set_audio_standard_NICAM(struct cx8800_dev *dev)
146 {
147         static const struct rlist nicam[] = {
148                 { AUD_RATE_ADJ1,           0x00000010 },
149                 { AUD_RATE_ADJ2,           0x00000040 },
150                 { AUD_RATE_ADJ3,           0x00000100 },
151                 { AUD_RATE_ADJ4,           0x00000400 },
152                 { AUD_RATE_ADJ5,           0x00001000 },
153     //          { AUD_DMD_RA_DDS,          0x00c0d5ce },
154
155                 // setup QAM registers
156                 { AUD_PDF_DDS_CNST_BYTE2,  0x06 },
157                 { AUD_PDF_DDS_CNST_BYTE1,  0x82 },
158                 { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
159                 { AUD_QAM_MODE,            0x05 },
160                 { AUD_PHACC_FREQ_8MSB,     0x34 },
161                 { AUD_PHACC_FREQ_8LSB,     0x4c },
162
163                 { /* end of list */ },
164         };
165
166         dprintk("%s (status: unknown)\n",__FUNCTION__);
167         set_audio_start(dev, 0x0010,
168                         EN_DMTRX_LR | EN_NICAM_FORCE_STEREO);
169         set_audio_registers(dev, nicam);
170         set_audio_finish(dev);
171 }
172
173 static void set_audio_standard_NICAM_L(struct cx8800_dev *dev)
174 {
175         /* This is officially wierd.. register dumps indicate windows
176          * uses audio mode 4.. A2. Let's operate and find out. */
177
178         static const struct rlist nicam_l[] = {
179                 // setup QAM registers
180                 { AUD_PDF_DDS_CNST_BYTE2,          0x48 },
181                 { AUD_PDF_DDS_CNST_BYTE1,          0x3d },
182                 { AUD_PDF_DDS_CNST_BYTE0,          0xf5 },
183                 { AUD_QAM_MODE,                    0x00 },
184                 { AUD_PHACC_FREQ_8MSB,             0x3a },
185                 { AUD_PHACC_FREQ_8LSB,             0x4a },
186
187                 { AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
188                 { AUD_IIR1_0_SEL,                  0x00000000 },
189                 { AUD_IIR1_1_SEL,                  0x00000002 },
190                 { AUD_IIR1_2_SEL,                  0x00000023 },
191                 { AUD_IIR1_3_SEL,                  0x00000004 },
192                 { AUD_IIR1_4_SEL,                  0x00000005 },
193                 { AUD_IIR1_5_SEL,                  0x00000007 },
194                 { AUD_IIR1_0_SHIFT,                0x00000007 },
195                 { AUD_IIR1_1_SHIFT,                0x00000000 },
196                 { AUD_IIR1_2_SHIFT,                0x00000000 },
197                 { AUD_IIR1_3_SHIFT,                0x00000007 },
198                 { AUD_IIR1_4_SHIFT,                0x00000007 },
199                 { AUD_IIR1_5_SHIFT,                0x00000007 },
200                 { AUD_IIR2_0_SEL,                  0x00000002 },
201                 { AUD_IIR2_1_SEL,                  0x00000003 },
202                 { AUD_IIR2_2_SEL,                  0x00000004 },
203                 { AUD_IIR2_3_SEL,                  0x00000005 },
204                 { AUD_IIR3_0_SEL,                  0x00000007 },
205                 { AUD_IIR3_1_SEL,                  0x00000023 },
206                 { AUD_IIR3_2_SEL,                  0x00000016 },
207                 { AUD_IIR4_0_SHIFT,                0x00000000 },
208                 { AUD_IIR4_1_SHIFT,                0x00000000 },
209                 { AUD_IIR3_2_SHIFT,                0x00000002 },
210                 { AUD_IIR4_0_SEL,                  0x0000001d },
211                 { AUD_IIR4_1_SEL,                  0x00000019 },
212                 { AUD_IIR4_2_SEL,                  0x00000008 },
213                 { AUD_IIR4_0_SHIFT,                0x00000000 },
214                 { AUD_IIR4_1_SHIFT,                0x00000007 },
215                 { AUD_IIR4_2_SHIFT,                0x00000007 },
216                 { AUD_IIR4_0_CA0,                  0x0003e57e },
217                 { AUD_IIR4_0_CA1,                  0x00005e11 },
218                 { AUD_IIR4_0_CA2,                  0x0003a7cf },
219                 { AUD_IIR4_0_CB0,                  0x00002368 },
220                 { AUD_IIR4_0_CB1,                  0x0003bf1b },
221                 { AUD_IIR4_1_CA0,                  0x00006349 },
222                 { AUD_IIR4_1_CA1,                  0x00006f27 },
223                 { AUD_IIR4_1_CA2,                  0x0000e7a3 },
224                 { AUD_IIR4_1_CB0,                  0x00005653 },
225                 { AUD_IIR4_1_CB1,                  0x0000cf97 },
226                 { AUD_IIR4_2_CA0,                  0x00006349 },
227                 { AUD_IIR4_2_CA1,                  0x00006f27 },
228                 { AUD_IIR4_2_CA2,                  0x0000e7a3 },
229                 { AUD_IIR4_2_CB0,                  0x00005653 },
230                 { AUD_IIR4_2_CB1,                  0x0000cf97 },
231                 { AUD_HP_MD_IIR4_1,                0x00000001 },
232                 { AUD_HP_PROG_IIR4_1,              0x0000001a },
233                 { AUD_DN0_FREQ,                    0x00000000 },
234                 { AUD_DN1_FREQ,                    0x00003318 },
235                 { AUD_DN1_SRC_SEL,                 0x00000017 },
236                 { AUD_DN1_SHFT,                    0x00000007 },
237                 { AUD_DN1_AFC,                     0x00000000 },
238                 { AUD_DN1_FREQ_SHIFT,              0x00000000 },
239                 { AUD_DN2_FREQ,                    0x00003551 },
240                 { AUD_DN2_SRC_SEL,                 0x00000001 },
241                 { AUD_DN2_SHFT,                    0x00000000 },
242                 { AUD_DN2_AFC,                     0x00000002 },
243                 { AUD_DN2_FREQ_SHIFT,              0x00000000 },
244                 { AUD_PDET_SRC,                    0x00000014 },
245                 { AUD_PDET_SHIFT,                  0x00000000 },
246                 { AUD_DEEMPH0_SRC_SEL,             0x00000011 },
247                 { AUD_DEEMPH1_SRC_SEL,             0x00000011 },
248                 { AUD_DEEMPH0_SHIFT,               0x00000000 },
249                 { AUD_DEEMPH1_SHIFT,               0x00000000 },
250                 { AUD_DEEMPH0_G0,                  0x00007000 },
251                 { AUD_DEEMPH0_A0,                  0x00000000 },
252                 { AUD_DEEMPH0_B0,                  0x00000000 },
253                 { AUD_DEEMPH0_A1,                  0x00000000 },
254                 { AUD_DEEMPH0_B1,                  0x00000000 },
255                 { AUD_DEEMPH1_G0,                  0x00007000 },
256                 { AUD_DEEMPH1_A0,                  0x00000000 },
257                 { AUD_DEEMPH1_B0,                  0x00000000 },
258                 { AUD_DEEMPH1_A1,                  0x00000000 },
259                 { AUD_DEEMPH1_B1,                  0x00000000 },
260                 { AUD_DMD_RA_DDS,                  0x00f5c285 },
261                 { AUD_RATE_ADJ1,                   0x00000100 },
262                 { AUD_RATE_ADJ2,                   0x00000200 },
263                 { AUD_RATE_ADJ3,                   0x00000300 },
264                 { AUD_RATE_ADJ4,                   0x00000400 },
265                 { AUD_RATE_ADJ5,                   0x00000500 },
266                 { AUD_C2_UP_THR,                   0x00005400 },
267                 { AUD_C2_LO_THR,                   0x00003000 },
268                 { AUD_C1_UP_THR,                   0x00007000 },
269                 { AUD_C2_LO_THR,                   0x00005400 },
270                 { AUD_CTL,                         0x0000100c },
271                 { AUD_DCOC_0_SRC,                  0x00000021 },
272                 { AUD_DCOC_1_SRC,                  0x00000003 },
273                 { AUD_DCOC1_SHIFT,                 0x00000000 },
274                 { AUD_DCOC_1_SHIFT_IN0,            0x0000000a },
275                 { AUD_DCOC_1_SHIFT_IN1,            0x00000008 },
276                 { AUD_DCOC_PASS_IN,                0x00000000 },
277                 { AUD_DCOC_2_SRC,                  0x0000001b },
278                 { AUD_IIR4_0_SEL,                  0x0000001d },
279                 { AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
280                 { AUD_PHASE_FIX_CTL,               0x00000000 },
281                 { AUD_CORDIC_SHIFT_1,              0x00000007 },
282                 { AUD_PLL_EN,                      0x00000000 },
283                 { AUD_PLL_PRESCALE,                0x00000002 },
284                 { AUD_PLL_INT,                     0x0000001e },
285                 { AUD_OUT1_SHIFT,                  0x00000000 },
286
287                 { /* end of list */ },
288         };
289
290         dprintk("%s (status: unknown)\n",__FUNCTION__);
291         set_audio_start(dev, 0x0004,
292                         0 /* FIXME */);
293         set_audio_registers(dev, nicam_l);
294         set_audio_finish(dev);
295 }
296
297 static void set_audio_standard_A2(struct cx8800_dev *dev)
298 {
299         /* from dscaler cvs */
300         static const struct rlist a2[] = {
301                 { AUD_PDF_DDS_CNST_BYTE2,     0x06 },
302                 { AUD_PDF_DDS_CNST_BYTE1,     0x82 },
303                 { AUD_PDF_DDS_CNST_BYTE0,     0x12 },
304                 { AUD_QAM_MODE,               0x05 },
305                 { AUD_PHACC_FREQ_8MSB,        0x34 },
306                 { AUD_PHACC_FREQ_8LSB,        0x4c },
307
308                 { AUD_RATE_ADJ1,        0x00001000 },
309                 { AUD_RATE_ADJ2,        0x00002000 },
310                 { AUD_RATE_ADJ3,        0x00003000 },
311                 { AUD_RATE_ADJ4,        0x00004000 },
312                 { AUD_RATE_ADJ5,        0x00005000 },
313                 { AUD_THR_FR,           0x00000000 },
314                 { AAGC_HYST,            0x0000001a },
315                 { AUD_PILOT_BQD_1_K0,   0x0000755b },
316                 { AUD_PILOT_BQD_1_K1,   0x00551340 },
317                 { AUD_PILOT_BQD_1_K2,   0x006d30be },
318                 { AUD_PILOT_BQD_1_K3,   0xffd394af },
319                 { AUD_PILOT_BQD_1_K4,   0x00400000 },
320                 { AUD_PILOT_BQD_2_K0,   0x00040000 },
321                 { AUD_PILOT_BQD_2_K1,   0x002a4841 },
322                 { AUD_PILOT_BQD_2_K2,   0x00400000 },
323                 { AUD_PILOT_BQD_2_K3,   0x00000000 },
324                 { AUD_PILOT_BQD_2_K4,   0x00000000 },
325                 { AUD_MODE_CHG_TIMER,   0x00000040 },
326                 { AUD_START_TIMER,      0x00000200 },
327                 { AUD_AFE_12DB_EN,      0x00000000 },
328                 { AUD_CORDIC_SHIFT_0,   0x00000007 },
329                 { AUD_CORDIC_SHIFT_1,   0x00000007 },
330                 { AUD_DEEMPH0_G0,       0x00000380 },
331                 { AUD_DEEMPH1_G0,       0x00000380 },
332                 { AUD_DCOC_0_SRC,       0x0000001a },
333                 { AUD_DCOC0_SHIFT,      0x00000000 },
334                 { AUD_DCOC_0_SHIFT_IN0, 0x0000000a },
335                 { AUD_DCOC_0_SHIFT_IN1, 0x00000008 },
336                 { AUD_DCOC_PASS_IN,     0x00000003 },
337                 { AUD_IIR3_0_SEL,       0x00000021 },
338                 { AUD_DN2_AFC,          0x00000002 },
339                 { AUD_DCOC_1_SRC,       0x0000001b },
340                 { AUD_DCOC1_SHIFT,      0x00000000 },
341                 { AUD_DCOC_1_SHIFT_IN0, 0x0000000a },
342                 { AUD_DCOC_1_SHIFT_IN1, 0x00000008 },
343                 { AUD_IIR3_1_SEL,       0x00000023 },
344                 { AUD_RDSI_SEL,         0x00000017 },
345                 { AUD_RDSI_SHIFT,       0x00000000 },
346                 { AUD_RDSQ_SEL,         0x00000017 },
347                 { AUD_RDSQ_SHIFT,       0x00000000 },
348                 { AUD_POLYPH80SCALEFAC, 0x00000001 },
349
350                 // Table 1
351                 { AUD_DMD_RA_DDS,       0x002a73bd },
352                 { AUD_C1_UP_THR,        0x00007000 },
353                 { AUD_C1_LO_THR,        0x00005400 },
354                 { AUD_C2_UP_THR,        0x00005400 },
355                 { AUD_C2_LO_THR,        0x00003000 },
356
357 #if 0
358                 // found this in WDM-driver for A2, must country spec.
359                 // Table 2
360                 { AUD_DMD_RA_DDS,       0x002a73bd },
361                 { AUD_C1_UP_THR,        0x00007000 },
362                 { AUD_C1_LO_THR,        0x00005400 },
363                 { AUD_C2_UP_THR,        0x00005400 },
364                 { AUD_C2_LO_THR,        0x00003000 },
365                 { AUD_DN0_FREQ,         0x00003a1c },
366                 { AUD_DN2_FREQ,         0x0000d2e0 },
367
368                 // Table 3
369                 { AUD_DMD_RA_DDS,       0x002a2873 },
370                 { AUD_C1_UP_THR,        0x00003c00 },
371                 { AUD_C1_LO_THR,        0x00003000 },
372                 { AUD_C2_UP_THR,        0x00006000 },
373                 { AUD_C2_LO_THR,        0x00003c00 },
374                 { AUD_DN0_FREQ,         0x00002836 },
375                 { AUD_DN1_FREQ,         0x00003418 },
376                 { AUD_DN2_FREQ,         0x000029c7 },
377                 { AUD_POLY0_DDS_CONSTANT, 0x000a7540 },
378 #endif
379
380                 { /* end of list */ },
381         };
382
383         static const struct rlist a2_old[] = {
384                 { AUD_DN0_FREQ,            0x0000312b },
385                 { AUD_POLY0_DDS_CONSTANT,  0x000a62b4 },
386                 { AUD_IIR1_0_SEL,          0x00000000 },
387                 { AUD_IIR1_1_SEL,          0x00000001 },
388                 { AUD_IIR1_2_SEL,          0x0000001f },
389                 { AUD_IIR1_3_SEL,          0x00000020 },
390                 { AUD_IIR1_4_SEL,          0x00000023 },
391                 { AUD_IIR1_5_SEL,          0x00000007 },
392                 { AUD_IIR1_0_SHIFT,        0x00000000 },
393                 { AUD_IIR1_1_SHIFT,        0x00000000 },
394                 { AUD_IIR1_2_SHIFT,        0x00000007 },
395                 { AUD_IIR1_3_SHIFT,        0x00000007 },
396                 { AUD_IIR1_4_SHIFT,        0x00000007 },
397                 { AUD_IIR1_5_SHIFT,        0x00000000 },
398                 { AUD_IIR2_0_SEL,          0x00000002 },
399                 { AUD_IIR2_1_SEL,          0x00000003 },
400                 { AUD_IIR2_2_SEL,          0x00000004 },
401                 { AUD_IIR2_3_SEL,          0x00000005 },
402                 { AUD_IIR3_0_SEL,          0x00000021 },
403                 { AUD_IIR3_1_SEL,          0x00000023 },
404                 { AUD_IIR3_2_SEL,          0x00000016 },
405                 { AUD_IIR3_0_SHIFT,        0x00000000 },
406                 { AUD_IIR3_1_SHIFT,        0x00000000 },
407                 { AUD_IIR3_2_SHIFT,        0x00000000 },
408                 { AUD_IIR4_0_SEL,          0x0000001d },
409                 { AUD_IIR4_1_SEL,          0x00000019 },
410                 { AUD_IIR4_2_SEL,          0x00000008 },
411                 { AUD_IIR4_0_SHIFT,        0x00000000 },
412                 { AUD_IIR4_1_SHIFT,        0x00000000 },
413                 { AUD_IIR4_2_SHIFT,        0x00000001 },
414                 { AUD_IIR4_0_CA0,          0x0003e57e },
415                 { AUD_IIR4_0_CA1,          0x00005e11 },
416                 { AUD_IIR4_0_CA2,          0x0003a7cf },
417                 { AUD_IIR4_0_CB0,          0x00002368 },
418                 { AUD_IIR4_0_CB1,          0x0003bf1b },
419                 { AUD_IIR4_1_CA0,          0x00006349 },
420                 { AUD_IIR4_1_CA1,          0x00006f27 },
421                 { AUD_IIR4_1_CA2,          0x0000e7a3 },
422                 { AUD_IIR4_1_CB0,          0x00005653 },
423                 { AUD_IIR4_1_CB1,          0x0000cf97 },
424                 { AUD_IIR4_2_CA0,          0x00006349 },
425                 { AUD_IIR4_2_CA1,          0x00006f27 },
426                 { AUD_IIR4_2_CA2,          0x0000e7a3 },
427                 { AUD_IIR4_2_CB0,          0x00005653 },
428                 { AUD_IIR4_2_CB1,          0x0000cf97 },
429                 { AUD_HP_MD_IIR4_1,        0x00000001 },
430                 { AUD_HP_PROG_IIR4_1,      0x00000017 },
431                 { AUD_DN1_FREQ,            0x00003618 },
432                 { AUD_DN1_SRC_SEL,         0x00000017 },
433                 { AUD_DN1_SHFT,            0x00000007 },
434                 { AUD_DN1_AFC,             0x00000000 },
435                 { AUD_DN1_FREQ_SHIFT,      0x00000000 },
436                 { AUD_DN2_SRC_SEL,         0x00000040 },
437                 { AUD_DN2_SHFT,            0x00000000 },
438                 { AUD_DN2_AFC,             0x00000002 },
439                 { AUD_DN2_FREQ,            0x0000caaf },
440                 { AUD_DN2_FREQ_SHIFT,      0x00000000 },
441                 { AUD_PDET_SRC,            0x00000014 },
442                 { AUD_PDET_SHIFT,          0x00000000 },
443                 { AUD_DEEMPH0_SRC_SEL,     0x00000011 },
444                 { AUD_DEEMPH1_SRC_SEL,     0x00000013 },
445                 { AUD_DEEMPH0_SHIFT,       0x00000000 },
446                 { AUD_DEEMPH1_SHIFT,       0x00000000 },
447                 { AUD_DEEMPH0_G0,          0x000004da },
448                 { AUD_DEEMPH0_A0,          0x0000777a },
449                 { AUD_DEEMPH0_B0,          0x00000000 },
450                 { AUD_DEEMPH0_A1,          0x0003f062 },
451                 { AUD_DEEMPH0_B1,          0x00000000 },
452                 { AUD_DEEMPH1_G0,          0x000004da },
453                 { AUD_DEEMPH1_A0,          0x0000777a },
454                 { AUD_DEEMPH1_B0,          0x00000000 },
455                 { AUD_DEEMPH1_A1,          0x0003f062 },
456                 { AUD_DEEMPH1_B1,          0x00000000 },
457                 { AUD_PLL_EN,              0x00000000 },
458                 { AUD_DMD_RA_DDS,          0x002a4efb },
459                 { AUD_RATE_ADJ1,           0x00001000 },
460                 { AUD_RATE_ADJ2,           0x00002000 },
461                 { AUD_RATE_ADJ3,           0x00003000 },
462                 { AUD_RATE_ADJ4,           0x00004000 },
463                 { AUD_RATE_ADJ5,           0x00005000 },
464                 { AUD_C2_UP_THR,           0x0000ffff },
465                 { AUD_C2_LO_THR,           0x0000e800 },
466                 { AUD_C1_UP_THR,           0x00008c00 },
467                 { AUD_C1_LO_THR,           0x00006c00 },
468
469                 //   ; Completely ditch AFC feedback
470                 { AUD_DCOC_0_SRC,          0x00000021 },
471                 { AUD_DCOC_1_SRC,          0x0000001a },
472                 { AUD_DCOC1_SHIFT,         0x00000000 },
473                 { AUD_DCOC_1_SHIFT_IN0,    0x0000000a },
474                 { AUD_DCOC_1_SHIFT_IN1,    0x00000008 },
475                 { AUD_DCOC_PASS_IN,        0x00000000 },
476                 { AUD_IIR4_0_SEL,          0x00000023 },
477
478                 //  ; Completely ditc FM-2 AFC feedback
479                 { AUD_DN1_AFC,             0x00000000 },
480                 { AUD_DCOC_2_SRC,          0x0000001b },
481                 { AUD_IIR4_1_SEL,          0x00000025 },
482
483                 // ; WARNING!!! THIS CHANGE WAS NOT EXPECTED!!!
484                 // ; Swap I & Q inputs into second rotator
485                 // ; to reverse frequency and therefor invert
486                 // ; phase from the cordic FM demodulator
487                 // ; (frequency rotation must also be reversed
488                 { AUD_DN2_SRC_SEL,         0x00000001 },
489                 { AUD_DN2_FREQ,            0x00003551 },
490
491                 //  setup Audio PLL
492                 { AUD_PLL_PRESCALE,        0x00000002 },
493                 { AUD_PLL_INT,             0x0000001f },
494
495                 { /* end of list */ },
496         };
497
498
499         dprintk("%s (status: WorksForMe[tm])\n",__FUNCTION__);
500
501         if (0) {
502                 /* old code */
503                 set_audio_start(dev, 0x0004, EN_DMTRX_SUMR | EN_A2_AUTO_STEREO);
504                 set_audio_registers(dev, a2_old);
505                 set_audio_finish(dev);
506         } else {
507                 /* new code */
508                 set_audio_start(dev, 0x0004, EN_DMTRX_LR | EN_A2_AUTO_STEREO);
509                 set_audio_registers(dev, a2);
510                 set_audio_finish(dev);
511         }
512 }
513
514 static void set_audio_standard_EIAJ(struct cx8800_dev *dev)
515 {
516         static const struct rlist eiaj[] = {
517                 /* TODO: eiaj register settings are not there yet ... */
518
519                 { /* end of list */ },
520         };
521         dprintk("%s (status: unknown)\n",__FUNCTION__);
522
523         set_audio_start(dev, 0x0002, EN_EIAJ_AUTO_STEREO);
524         set_audio_registers(dev, eiaj);
525         set_audio_finish(dev);
526 }
527
528 static void set_audio_standard_FM(struct cx8800_dev *dev)
529 {
530 #if 0 /* FIXME */
531         switch (dev->audio_properties.FM_deemphasis)
532         {
533                 case WW_FM_DEEMPH_50:
534                         //Set De-emphasis filter coefficients for 50 usec
535                         cx_write(AUD_DEEMPH0_G0, 0x0C45);
536                         cx_write(AUD_DEEMPH0_A0, 0x6262);
537                         cx_write(AUD_DEEMPH0_B0, 0x1C29);
538                         cx_write(AUD_DEEMPH0_A1, 0x3FC66);
539                         cx_write(AUD_DEEMPH0_B1, 0x399A);
540
541                         cx_write(AUD_DEEMPH1_G0, 0x0D80);
542                         cx_write(AUD_DEEMPH1_A0, 0x6262);
543                         cx_write(AUD_DEEMPH1_B0, 0x1C29);
544                         cx_write(AUD_DEEMPH1_A1, 0x3FC66);
545                         cx_write(AUD_DEEMPH1_B1, 0x399A);
546                         
547                         break;
548
549                 case WW_FM_DEEMPH_75:
550                         //Set De-emphasis filter coefficients for 75 usec
551                         cx_write(AUD_DEEMPH0_G0, 0x91B );
552                         cx_write(AUD_DEEMPH0_A0, 0x6B68);
553                         cx_write(AUD_DEEMPH0_B0, 0x11EC);
554                         cx_write(AUD_DEEMPH0_A1, 0x3FC66);
555                         cx_write(AUD_DEEMPH0_B1, 0x399A);
556
557                         cx_write(AUD_DEEMPH1_G0, 0xAA0 );
558                         cx_write(AUD_DEEMPH1_A0, 0x6B68);
559                         cx_write(AUD_DEEMPH1_B0, 0x11EC);
560                         cx_write(AUD_DEEMPH1_A1, 0x3FC66);
561                         cx_write(AUD_DEEMPH1_B1, 0x399A);
562
563                         break;
564         }
565 #endif
566
567         dprintk("%s (status: unknown)\n",__FUNCTION__);
568         set_audio_start(dev, 0x0020, EN_FMRADIO_AUTO_STEREO);
569
570         // AB: 10/2/01: this register is not being reset appropriately on occasion.
571         cx_write(AUD_POLYPH80SCALEFAC,3);
572
573         set_audio_finish(dev);
574 }
575
576 /* ----------------------------------------------------------- */
577
578 void cx88_set_tvaudio(struct cx8800_dev *dev)
579 {
580         switch (dev->tvaudio) {
581         case WW_BTSC:
582                 set_audio_standard_BTSC(dev,0);
583                 break;
584         case WW_NICAM_I:
585         case WW_NICAM_BGDKL:
586                 set_audio_standard_NICAM(dev);
587                 break;
588         case WW_A2_BG:
589         case WW_A2_DK:
590         case WW_A2_M:
591                 set_audio_standard_A2(dev);
592                 break;
593         case WW_EIAJ:
594                 set_audio_standard_EIAJ(dev);
595                 break;
596         case WW_FM:
597                 set_audio_standard_FM(dev);
598                 break;
599         case WW_SYSTEM_L_AM:
600                 set_audio_standard_NICAM_L(dev);
601                 break;
602         case WW_NONE:
603         default:
604                 printk("%s: unknown tv audio mode [%d]\n",
605                        dev->name, dev->tvaudio);
606                 break;
607         }
608         return;
609 }
610
611 void cx88_get_stereo(struct cx8800_dev *dev, struct v4l2_tuner *t)
612 {
613         static char *m[] = {"stereo", "dual mono", "mono", "sap"};
614         static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
615         u32 reg,mode,pilot;
616
617         reg   = cx_read(AUD_STATUS);
618         mode  = reg & 0x03;
619         pilot = (reg >> 2) & 0x03;
620         dprintk("AUD_STATUS: %s / %s [status=0x%x,ctl=0x%x,vol=0x%x]\n",
621                 m[mode], p[pilot], reg,
622                 cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
623
624         t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
625                 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
626         t->rxsubchans = V4L2_TUNER_SUB_MONO;
627         t->audmode    = V4L2_TUNER_MODE_MONO;
628
629         switch (dev->tvaudio) {
630         case WW_A2_BG:
631                 if (1 == pilot) {
632                         /* stereo */
633                         t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
634                         if (0 == mode)
635                                 t->audmode = V4L2_TUNER_MODE_STEREO;
636                 }
637                 if (2 == pilot) {
638                         /* dual language -- FIXME */
639                         t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
640                         t->audmode = V4L2_TUNER_MODE_LANG1;
641                 }
642                 break;
643         case WW_NICAM_BGDKL:
644                 if (0 == mode)
645                         t->audmode = V4L2_TUNER_MODE_STEREO;
646                 break;
647         default:
648                 t->rxsubchans = V4L2_TUNER_SUB_MONO;
649                 t->audmode    = V4L2_TUNER_MODE_MONO;
650                 break;
651         }
652         return;
653 }
654
655 void cx88_set_stereo(struct cx8800_dev *dev, u32 mode)
656 {
657         u32 ctl  = UNSET;
658         u32 mask = UNSET;
659
660         switch (dev->tvaudio) {
661         case WW_A2_BG:
662                 switch (mode) {
663                 case V4L2_TUNER_MODE_MONO:   
664                 case V4L2_TUNER_MODE_LANG1:
665                         ctl  = EN_A2_FORCE_MONO1;
666                         mask = 0x3f;
667                         break;
668                 case V4L2_TUNER_MODE_LANG2:
669                         ctl  = EN_A2_AUTO_MONO2;
670                         mask = 0x3f;
671                         break;
672                 case V4L2_TUNER_MODE_STEREO:
673                         ctl  = EN_A2_AUTO_STEREO | EN_DMTRX_SUMR;
674                         mask = 0x8bf;
675                         break;
676                 }
677                 break;
678         case WW_NICAM_BGDKL:
679                 switch (mode) {
680                 case V4L2_TUNER_MODE_MONO:   
681                         ctl  = EN_NICAM_FORCE_MONO1;
682                         mask = 0x3f;
683                         break;
684                 case V4L2_TUNER_MODE_LANG1:
685                         ctl  = EN_NICAM_AUTO_MONO2;
686                         mask = 0x3f;
687                         break;
688                 case V4L2_TUNER_MODE_STEREO:
689                         ctl  = EN_NICAM_FORCE_STEREO | EN_DMTRX_LR;
690                         mask = 0x93f;
691                         break;
692                 }
693                 break;  
694         case WW_FM:
695                 switch (mode) {
696                 case V4L2_TUNER_MODE_MONO:   
697                         ctl  = EN_FMRADIO_FORCE_MONO;
698                         mask = 0x3f;
699                         break;
700                 case V4L2_TUNER_MODE_STEREO:
701                         ctl  = EN_FMRADIO_AUTO_STEREO;
702                         mask = 0x3f;
703                         break;
704                 }
705                 break;  
706         }
707
708         if (UNSET != ctl) {
709                 cx_write(AUD_SOFT_RESET, 0x0001);
710                 cx_andor(AUD_CTL, mask,  ctl);
711                 cx_write(AUD_SOFT_RESET, 0x0000);
712                 dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x "
713                         "[status=0x%x,ctl=0x%x,vol=0x%x]\n",
714                         mask, ctl, cx_read(AUD_STATUS),
715                         cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
716         }
717         return;
718 }
719
720 /*
721  * Local variables:
722  * c-basic-offset: 8
723  * End:
724  */