vserver 1.9.5.x5
[linux-2.6.git] / drivers / media / video / cx88 / cx88-tvaudio.c
1 /*
2     $Id: cx88-tvaudio.c,v 1.24 2004/10/25 11:51:00 kraxel Exp $
3
4     cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
5
6      (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version]
7      (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
8      (c) 2003 Gerd Knorr <kraxel@bytesex.org>
9
10     -----------------------------------------------------------------------
11
12     Lot of voodoo here.  Even the data sheet doesn't help to
13     understand what is going on here, the documentation for the audio
14     part of the cx2388x chip is *very* bad.
15
16     Some of this comes from party done linux driver sources I got from
17     [undocumented].
18
19     Some comes from the dscaler sources, one of the dscaler driver guy works
20     for Conexant ...
21
22     -----------------------------------------------------------------------
23
24     This program is free software; you can redistribute it and/or modify
25     it under the terms of the GNU General Public License as published by
26     the Free Software Foundation; either version 2 of the License, or
27     (at your option) any later version.
28
29     This program is distributed in the hope that it will be useful,
30     but WITHOUT ANY WARRANTY; without even the implied warranty of
31     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32     GNU General Public License for more details.
33
34     You should have received a copy of the GNU General Public License
35     along with this program; if not, write to the Free Software
36     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37 */
38
39 #include <linux/module.h>
40 #include <linux/errno.h>
41 #include <linux/kernel.h>
42 #include <linux/slab.h>
43 #include <linux/mm.h>
44 #include <linux/poll.h>
45 #include <linux/pci.h>
46 #include <linux/signal.h>
47 #include <linux/ioport.h>
48 #include <linux/sched.h>
49 #include <linux/types.h>
50 #include <linux/interrupt.h>
51 #include <linux/vmalloc.h>
52 #include <linux/init.h>
53 #include <linux/smp_lock.h>
54 #include <linux/delay.h>
55 #include <linux/kthread.h>
56
57 #include "cx88.h"
58
59 static unsigned int audio_debug = 1;
60 module_param(audio_debug,int,0644);
61 MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
62
63 #define dprintk(fmt, arg...)    if (audio_debug) \
64         printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
65
66 /* ----------------------------------------------------------- */
67
68 static char *aud_ctl_names[64] =
69 {
70         [ EN_BTSC_FORCE_MONO       ] = "BTSC_FORCE_MONO",
71         [ EN_BTSC_FORCE_STEREO     ] = "BTSC_FORCE_STEREO",
72         [ EN_BTSC_FORCE_SAP        ] = "BTSC_FORCE_SAP",
73         [ EN_BTSC_AUTO_STEREO      ] = "BTSC_AUTO_STEREO",
74         [ EN_BTSC_AUTO_SAP         ] = "BTSC_AUTO_SAP",
75         [ EN_A2_FORCE_MONO1        ] = "A2_FORCE_MONO1",
76         [ EN_A2_FORCE_MONO2        ] = "A2_FORCE_MONO2",
77         [ EN_A2_FORCE_STEREO       ] = "A2_FORCE_STEREO",
78         [ EN_A2_AUTO_MONO2         ] = "A2_AUTO_MONO2",
79         [ EN_A2_AUTO_STEREO        ] = "A2_AUTO_STEREO",
80         [ EN_EIAJ_FORCE_MONO1      ] = "EIAJ_FORCE_MONO1",
81         [ EN_EIAJ_FORCE_MONO2      ] = "EIAJ_FORCE_MONO2",
82         [ EN_EIAJ_FORCE_STEREO     ] = "EIAJ_FORCE_STEREO",
83         [ EN_EIAJ_AUTO_MONO2       ] = "EIAJ_AUTO_MONO2",
84         [ EN_EIAJ_AUTO_STEREO      ] = "EIAJ_AUTO_STEREO",
85         [ EN_NICAM_FORCE_MONO1     ] = "NICAM_FORCE_MONO1",
86         [ EN_NICAM_FORCE_MONO2     ] = "NICAM_FORCE_MONO2",
87         [ EN_NICAM_FORCE_STEREO    ] = "NICAM_FORCE_STEREO",
88         [ EN_NICAM_AUTO_MONO2      ] = "NICAM_AUTO_MONO2",
89         [ EN_NICAM_AUTO_STEREO     ] = "NICAM_AUTO_STEREO",
90         [ EN_FMRADIO_FORCE_MONO    ] = "FMRADIO_FORCE_MONO",
91         [ EN_FMRADIO_FORCE_STEREO  ] = "FMRADIO_FORCE_STEREO",
92         [ EN_FMRADIO_AUTO_STEREO   ] = "FMRADIO_AUTO_STEREO",
93 };
94
95 struct rlist {
96         u32 reg;
97         u32 val;
98 };
99
100 static void set_audio_registers(struct cx88_core *core,
101                                 const struct rlist *l)
102 {
103         int i;
104
105         for (i = 0; l[i].reg; i++) {
106                 switch (l[i].reg) {
107                 case AUD_PDF_DDS_CNST_BYTE2:
108                 case AUD_PDF_DDS_CNST_BYTE1:
109                 case AUD_PDF_DDS_CNST_BYTE0:
110                 case AUD_QAM_MODE:
111                 case AUD_PHACC_FREQ_8MSB:
112                 case AUD_PHACC_FREQ_8LSB:
113                         cx_writeb(l[i].reg, l[i].val);
114                         break;
115                 default:
116                         cx_write(l[i].reg, l[i].val);
117                         break;
118                 }
119         }
120 }
121
122 static void set_audio_start(struct cx88_core *core,
123                             u32 mode, u32 ctl)
124 {
125         // mute
126         cx_write(AUD_VOL_CTL,       (1 << 6));
127
128         //  increase level of input by 12dB
129         cx_write(AUD_AFE_12DB_EN,   0x0001);
130
131         // start programming
132         cx_write(AUD_CTL,           0x0000);
133         cx_write(AUD_INIT,          mode);
134         cx_write(AUD_INIT_LD,       0x0001);
135         cx_write(AUD_SOFT_RESET,    0x0001);
136
137         cx_write(AUD_CTL,           ctl);
138 }
139
140 static void set_audio_finish(struct cx88_core *core)
141 {
142         u32 volume;
143
144         // finish programming
145         cx_write(AUD_SOFT_RESET, 0x0000);
146
147         // start audio processing
148         cx_set(AUD_CTL, EN_DAC_ENABLE);
149
150         // unmute
151         volume = cx_sread(SHADOW_AUD_VOL_CTL);
152         cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume);
153 }
154
155 /* ----------------------------------------------------------- */
156
157 static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap)
158 {
159         static const struct rlist btsc[] = {
160                 /* from dscaler */
161                 { AUD_OUT1_SEL,                0x00000013 },
162                 { AUD_OUT1_SHIFT,              0x00000000 },
163                 { AUD_POLY0_DDS_CONSTANT,      0x0012010c },
164                 { AUD_DMD_RA_DDS,              0x00c3e7aa },
165                 { AUD_DBX_IN_GAIN,             0x00004734 },
166                 { AUD_DBX_WBE_GAIN,            0x00004640 },
167                 { AUD_DBX_SE_GAIN,             0x00008d31 },
168                 { AUD_DCOC_0_SRC,              0x0000001a },
169                 { AUD_IIR1_4_SEL,              0x00000021 },
170                 { AUD_DCOC_PASS_IN,            0x00000003 },
171                 { AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
172                 { AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
173                 { AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
174                 { AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
175                 { AUD_DN0_FREQ,                0x0000283b },
176                 { AUD_DN2_SRC_SEL,             0x00000008 },
177                 { AUD_DN2_FREQ,                0x00003000 },
178                 { AUD_DN2_AFC,                 0x00000002 },
179                 { AUD_DN2_SHFT,                0x00000000 },
180                 { AUD_IIR2_2_SEL,              0x00000020 },
181                 { AUD_IIR2_2_SHIFT,            0x00000000 },
182                 { AUD_IIR2_3_SEL,              0x0000001f },
183                 { AUD_IIR2_3_SHIFT,            0x00000000 },
184                 { AUD_CRDC1_SRC_SEL,           0x000003ce },
185                 { AUD_CRDC1_SHIFT,             0x00000000 },
186                 { AUD_CORDIC_SHIFT_1,          0x00000007 },
187                 { AUD_DCOC_1_SRC,              0x0000001b },
188                 { AUD_DCOC1_SHIFT,             0x00000000 },
189                 { AUD_RDSI_SEL,                0x00000008 },
190                 { AUD_RDSQ_SEL,                0x00000008 },
191                 { AUD_RDSI_SHIFT,              0x00000000 },
192                 { AUD_RDSQ_SHIFT,              0x00000000 },
193                 { AUD_POLYPH80SCALEFAC,        0x00000003 },
194                 { /* end of list */ },
195         };
196         static const struct rlist btsc_sap[] = {
197                 { AUD_DBX_IN_GAIN,             0x00007200 },
198                 { AUD_DBX_WBE_GAIN,            0x00006200 },
199                 { AUD_DBX_SE_GAIN,             0x00006200 },
200                 { AUD_IIR1_1_SEL,              0x00000000 },
201                 { AUD_IIR1_3_SEL,              0x00000001 },
202                 { AUD_DN1_SRC_SEL,             0x00000007 },
203                 { AUD_IIR1_4_SHIFT,            0x00000006 },
204                 { AUD_IIR2_1_SHIFT,            0x00000000 },
205                 { AUD_IIR2_2_SHIFT,            0x00000000 },
206                 { AUD_IIR3_0_SHIFT,            0x00000000 },
207                 { AUD_IIR3_1_SHIFT,            0x00000000 },
208                 { AUD_IIR3_0_SEL,              0x0000000d },
209                 { AUD_IIR3_1_SEL,              0x0000000e },
210                 { AUD_DEEMPH1_SRC_SEL,         0x00000014 },
211                 { AUD_DEEMPH1_SHIFT,           0x00000000 },
212                 { AUD_DEEMPH1_G0,              0x00004000 },
213                 { AUD_DEEMPH1_A0,              0x00000000 },
214                 { AUD_DEEMPH1_B0,              0x00000000 },
215                 { AUD_DEEMPH1_A1,              0x00000000 },
216                 { AUD_DEEMPH1_B1,              0x00000000 },
217                 { AUD_OUT0_SEL,                0x0000003f },
218                 { AUD_OUT1_SEL,                0x0000003f },
219                 { AUD_DN1_AFC,                 0x00000002 },
220                 { AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
221                 { AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
222                 { AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
223                 { AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
224                 { AUD_IIR1_0_SEL,              0x0000001d },
225                 { AUD_IIR1_2_SEL,              0x0000001e },
226                 { AUD_IIR2_1_SEL,              0x00000002 },
227                 { AUD_IIR2_2_SEL,              0x00000004 },
228                 { AUD_IIR3_2_SEL,              0x0000000f },
229                 { AUD_DCOC2_SHIFT,             0x00000001 },
230                 { AUD_IIR3_2_SHIFT,            0x00000001 },
231                 { AUD_DEEMPH0_SRC_SEL,         0x00000014 },
232                 { AUD_CORDIC_SHIFT_1,          0x00000006 },
233                 { AUD_POLY0_DDS_CONSTANT,      0x000e4db2 },
234                 { AUD_DMD_RA_DDS,              0x00f696e6 },
235                 { AUD_IIR2_3_SEL,              0x00000025 },
236                 { AUD_IIR1_4_SEL,              0x00000021 },
237                 { AUD_DN1_FREQ,                0x0000c965 },
238                 { AUD_DCOC_PASS_IN,            0x00000003 },
239                 { AUD_DCOC_0_SRC,              0x0000001a },
240                 { AUD_DCOC_1_SRC,              0x0000001b },
241                 { AUD_DCOC1_SHIFT,             0x00000000 },
242                 { AUD_RDSI_SEL,                0x00000009 },
243                 { AUD_RDSQ_SEL,                0x00000009 },
244                 { AUD_RDSI_SHIFT,              0x00000000 },
245                 { AUD_RDSQ_SHIFT,              0x00000000 },
246                 { AUD_POLYPH80SCALEFAC,        0x00000003 },
247                 { /* end of list */ },
248         };
249
250         // dscaler: exactly taken from driver,
251         // dscaler: don't know why to set EN_FMRADIO_EN_RDS
252         if (sap) {
253                 dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
254                 set_audio_start(core, 0x0001,
255                                 EN_FMRADIO_EN_RDS | EN_BTSC_FORCE_SAP);
256                 set_audio_registers(core, btsc_sap);
257         } else {
258                 dprintk("%s (status: known-good)\n",__FUNCTION__);
259                 set_audio_start(core, 0x0001,
260                                 EN_FMRADIO_EN_RDS | EN_BTSC_AUTO_STEREO);
261                 set_audio_registers(core, btsc);
262         }
263         set_audio_finish(core);
264 }
265
266 static void set_audio_standard_NICAM(struct cx88_core *core)
267 {
268         static const struct rlist nicam_common[] = {
269                 /* from dscaler */
270                 { AUD_RATE_ADJ1,           0x00000010 },
271                 { AUD_RATE_ADJ2,           0x00000040 },
272                 { AUD_RATE_ADJ3,           0x00000100 },
273                 { AUD_RATE_ADJ4,           0x00000400 },
274                 { AUD_RATE_ADJ5,           0x00001000 },
275     //          { AUD_DMD_RA_DDS,          0x00c0d5ce },
276
277                 // Deemphasis 1:
278                 { AUD_DEEMPHGAIN_R,        0x000023c2 },
279                 { AUD_DEEMPHNUMER1_R,      0x0002a7bc },
280                 { AUD_DEEMPHNUMER2_R,      0x0003023e },
281                 { AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
282                 { AUD_DEEMPHDENOM2_R,      0x00000000 },
283
284 #if 0
285                 // Deemphasis 2: (other tv norm?)
286                 { AUD_DEEMPHGAIN_R,        0x0000c600 },
287                 { AUD_DEEMPHNUMER1_R,      0x00066738 },
288                 { AUD_DEEMPHNUMER2_R,      0x00066739 },
289                 { AUD_DEEMPHDENOM1_R,      0x0001e88c },
290                 { AUD_DEEMPHDENOM2_R,      0x0001e88c },
291 #endif
292
293                 { AUD_DEEMPHDENOM2_R,      0x00000000 },
294                 { AUD_ERRLOGPERIOD_R,      0x00000fff },
295                 { AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
296                 { AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
297                 { AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
298                 { AUD_POLYPH80SCALEFAC,    0x00000003 },
299
300                 // setup QAM registers
301                 { AUD_PDF_DDS_CNST_BYTE2,  0x06 },
302                 { AUD_PDF_DDS_CNST_BYTE1,  0x82 },
303                 { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
304                 { AUD_QAM_MODE,            0x05 },
305
306                 { /* end of list */ },
307         };
308         static const struct rlist nicam_pal_i[] = {
309                 { AUD_PDF_DDS_CNST_BYTE0,  0x12 },
310                 { AUD_PHACC_FREQ_8MSB,     0x3a },
311                 { AUD_PHACC_FREQ_8LSB,     0x93 },
312
313                 { /* end of list */ },
314         };
315         static const struct rlist nicam_default[] = {
316                 { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
317                 { AUD_PHACC_FREQ_8MSB,     0x34 },
318                 { AUD_PHACC_FREQ_8LSB,     0x4c },
319
320                 { /* end of list */ },
321         };
322
323         set_audio_start(core, 0x0010,
324                         EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
325         set_audio_registers(core, nicam_common);
326         switch (core->tvaudio) {
327         case WW_NICAM_I:
328                 dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__);
329                 set_audio_registers(core, nicam_pal_i);
330                 break;
331         case WW_NICAM_BGDKL:
332                 dprintk("%s PAL-BGDK NICAM (status: unknown)\n",__FUNCTION__);
333                 set_audio_registers(core, nicam_default);
334                 break;
335         };
336         set_audio_finish(core);
337 }
338
339 static void set_audio_standard_NICAM_L(struct cx88_core *core)
340 {
341         /* This is officially weird.. register dumps indicate windows
342          * uses audio mode 4.. A2. Let's operate and find out. */
343
344         static const struct rlist nicam_l[] = {
345                 // setup QAM registers
346                 { AUD_PDF_DDS_CNST_BYTE2,          0x48 },
347                 { AUD_PDF_DDS_CNST_BYTE1,          0x3d },
348                 { AUD_PDF_DDS_CNST_BYTE0,          0xf5 },
349                 { AUD_QAM_MODE,                    0x00 },
350                 { AUD_PHACC_FREQ_8MSB,             0x3a },
351                 { AUD_PHACC_FREQ_8LSB,             0x4a },
352
353                 { AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
354                 { AUD_IIR1_0_SEL,                  0x00000000 },
355                 { AUD_IIR1_1_SEL,                  0x00000002 },
356                 { AUD_IIR1_2_SEL,                  0x00000023 },
357                 { AUD_IIR1_3_SEL,                  0x00000004 },
358                 { AUD_IIR1_4_SEL,                  0x00000005 },
359                 { AUD_IIR1_5_SEL,                  0x00000007 },
360                 { AUD_IIR1_0_SHIFT,                0x00000007 },
361                 { AUD_IIR1_1_SHIFT,                0x00000000 },
362                 { AUD_IIR1_2_SHIFT,                0x00000000 },
363                 { AUD_IIR1_3_SHIFT,                0x00000007 },
364                 { AUD_IIR1_4_SHIFT,                0x00000007 },
365                 { AUD_IIR1_5_SHIFT,                0x00000007 },
366                 { AUD_IIR2_0_SEL,                  0x00000002 },
367                 { AUD_IIR2_1_SEL,                  0x00000003 },
368                 { AUD_IIR2_2_SEL,                  0x00000004 },
369                 { AUD_IIR2_3_SEL,                  0x00000005 },
370                 { AUD_IIR3_0_SEL,                  0x00000007 },
371                 { AUD_IIR3_1_SEL,                  0x00000023 },
372                 { AUD_IIR3_2_SEL,                  0x00000016 },
373                 { AUD_IIR4_0_SHIFT,                0x00000000 },
374                 { AUD_IIR4_1_SHIFT,                0x00000000 },
375                 { AUD_IIR3_2_SHIFT,                0x00000002 },
376                 { AUD_IIR4_0_SEL,                  0x0000001d },
377                 { AUD_IIR4_1_SEL,                  0x00000019 },
378                 { AUD_IIR4_2_SEL,                  0x00000008 },
379                 { AUD_IIR4_0_SHIFT,                0x00000000 },
380                 { AUD_IIR4_1_SHIFT,                0x00000007 },
381                 { AUD_IIR4_2_SHIFT,                0x00000007 },
382                 { AUD_IIR4_0_CA0,                  0x0003e57e },
383                 { AUD_IIR4_0_CA1,                  0x00005e11 },
384                 { AUD_IIR4_0_CA2,                  0x0003a7cf },
385                 { AUD_IIR4_0_CB0,                  0x00002368 },
386                 { AUD_IIR4_0_CB1,                  0x0003bf1b },
387                 { AUD_IIR4_1_CA0,                  0x00006349 },
388                 { AUD_IIR4_1_CA1,                  0x00006f27 },
389                 { AUD_IIR4_1_CA2,                  0x0000e7a3 },
390                 { AUD_IIR4_1_CB0,                  0x00005653 },
391                 { AUD_IIR4_1_CB1,                  0x0000cf97 },
392                 { AUD_IIR4_2_CA0,                  0x00006349 },
393                 { AUD_IIR4_2_CA1,                  0x00006f27 },
394                 { AUD_IIR4_2_CA2,                  0x0000e7a3 },
395                 { AUD_IIR4_2_CB0,                  0x00005653 },
396                 { AUD_IIR4_2_CB1,                  0x0000cf97 },
397                 { AUD_HP_MD_IIR4_1,                0x00000001 },
398                 { AUD_HP_PROG_IIR4_1,              0x0000001a },
399                 { AUD_DN0_FREQ,                    0x00000000 },
400                 { AUD_DN1_FREQ,                    0x00003318 },
401                 { AUD_DN1_SRC_SEL,                 0x00000017 },
402                 { AUD_DN1_SHFT,                    0x00000007 },
403                 { AUD_DN1_AFC,                     0x00000000 },
404                 { AUD_DN1_FREQ_SHIFT,              0x00000000 },
405                 { AUD_DN2_FREQ,                    0x00003551 },
406                 { AUD_DN2_SRC_SEL,                 0x00000001 },
407                 { AUD_DN2_SHFT,                    0x00000000 },
408                 { AUD_DN2_AFC,                     0x00000002 },
409                 { AUD_DN2_FREQ_SHIFT,              0x00000000 },
410                 { AUD_PDET_SRC,                    0x00000014 },
411                 { AUD_PDET_SHIFT,                  0x00000000 },
412                 { AUD_DEEMPH0_SRC_SEL,             0x00000011 },
413                 { AUD_DEEMPH1_SRC_SEL,             0x00000011 },
414                 { AUD_DEEMPH0_SHIFT,               0x00000000 },
415                 { AUD_DEEMPH1_SHIFT,               0x00000000 },
416                 { AUD_DEEMPH0_G0,                  0x00007000 },
417                 { AUD_DEEMPH0_A0,                  0x00000000 },
418                 { AUD_DEEMPH0_B0,                  0x00000000 },
419                 { AUD_DEEMPH0_A1,                  0x00000000 },
420                 { AUD_DEEMPH0_B1,                  0x00000000 },
421                 { AUD_DEEMPH1_G0,                  0x00007000 },
422                 { AUD_DEEMPH1_A0,                  0x00000000 },
423                 { AUD_DEEMPH1_B0,                  0x00000000 },
424                 { AUD_DEEMPH1_A1,                  0x00000000 },
425                 { AUD_DEEMPH1_B1,                  0x00000000 },
426                 { AUD_DMD_RA_DDS,                  0x00f5c285 },
427                 { AUD_RATE_ADJ1,                   0x00000100 },
428                 { AUD_RATE_ADJ2,                   0x00000200 },
429                 { AUD_RATE_ADJ3,                   0x00000300 },
430                 { AUD_RATE_ADJ4,                   0x00000400 },
431                 { AUD_RATE_ADJ5,                   0x00000500 },
432                 { AUD_C2_UP_THR,                   0x00005400 },
433                 { AUD_C2_LO_THR,                   0x00003000 },
434                 { AUD_C1_UP_THR,                   0x00007000 },
435                 { AUD_C2_LO_THR,                   0x00005400 },
436                 { AUD_CTL,                         0x0000100c },
437                 { AUD_DCOC_0_SRC,                  0x00000021 },
438                 { AUD_DCOC_1_SRC,                  0x00000003 },
439                 { AUD_DCOC1_SHIFT,                 0x00000000 },
440                 { AUD_DCOC_1_SHIFT_IN0,            0x0000000a },
441                 { AUD_DCOC_1_SHIFT_IN1,            0x00000008 },
442                 { AUD_DCOC_PASS_IN,                0x00000000 },
443                 { AUD_DCOC_2_SRC,                  0x0000001b },
444                 { AUD_IIR4_0_SEL,                  0x0000001d },
445                 { AUD_POLY0_DDS_CONSTANT,          0x000e4db2 },
446                 { AUD_PHASE_FIX_CTL,               0x00000000 },
447                 { AUD_CORDIC_SHIFT_1,              0x00000007 },
448                 { AUD_PLL_EN,                      0x00000000 },
449                 { AUD_PLL_PRESCALE,                0x00000002 },
450                 { AUD_PLL_INT,                     0x0000001e },
451                 { AUD_OUT1_SHIFT,                  0x00000000 },
452
453                 { /* end of list */ },
454         };
455
456         dprintk("%s (status: unknown)\n",__FUNCTION__);
457         set_audio_start(core, 0x0004,
458                         0 /* FIXME */);
459         set_audio_registers(core, nicam_l);
460         set_audio_finish(core);
461 }
462
463 static void set_audio_standard_A2(struct cx88_core *core)
464 {
465         /* from dscaler cvs */
466         static const struct rlist a2_common[] = {
467                 { AUD_PDF_DDS_CNST_BYTE2,     0x06 },
468                 { AUD_PDF_DDS_CNST_BYTE1,     0x82 },
469                 { AUD_PDF_DDS_CNST_BYTE0,     0x12 },
470                 { AUD_QAM_MODE,               0x05 },
471                 { AUD_PHACC_FREQ_8MSB,        0x34 },
472                 { AUD_PHACC_FREQ_8LSB,        0x4c },
473
474                 { AUD_RATE_ADJ1,        0x00001000 },
475                 { AUD_RATE_ADJ2,        0x00002000 },
476                 { AUD_RATE_ADJ3,        0x00003000 },
477                 { AUD_RATE_ADJ4,        0x00004000 },
478                 { AUD_RATE_ADJ5,        0x00005000 },
479                 { AUD_THR_FR,           0x00000000 },
480                 { AAGC_HYST,            0x0000001a },
481                 { AUD_PILOT_BQD_1_K0,   0x0000755b },
482                 { AUD_PILOT_BQD_1_K1,   0x00551340 },
483                 { AUD_PILOT_BQD_1_K2,   0x006d30be },
484                 { AUD_PILOT_BQD_1_K3,   0xffd394af },
485                 { AUD_PILOT_BQD_1_K4,   0x00400000 },
486                 { AUD_PILOT_BQD_2_K0,   0x00040000 },
487                 { AUD_PILOT_BQD_2_K1,   0x002a4841 },
488                 { AUD_PILOT_BQD_2_K2,   0x00400000 },
489                 { AUD_PILOT_BQD_2_K3,   0x00000000 },
490                 { AUD_PILOT_BQD_2_K4,   0x00000000 },
491                 { AUD_MODE_CHG_TIMER,   0x00000040 },
492                 { AUD_START_TIMER,      0x00000200 },
493                 { AUD_AFE_12DB_EN,      0x00000000 },
494                 { AUD_CORDIC_SHIFT_0,   0x00000007 },
495                 { AUD_CORDIC_SHIFT_1,   0x00000007 },
496                 { AUD_DEEMPH0_G0,       0x00000380 },
497                 { AUD_DEEMPH1_G0,       0x00000380 },
498                 { AUD_DCOC_0_SRC,       0x0000001a },
499                 { AUD_DCOC0_SHIFT,      0x00000000 },
500                 { AUD_DCOC_0_SHIFT_IN0, 0x0000000a },
501                 { AUD_DCOC_0_SHIFT_IN1, 0x00000008 },
502                 { AUD_DCOC_PASS_IN,     0x00000003 },
503                 { AUD_IIR3_0_SEL,       0x00000021 },
504                 { AUD_DN2_AFC,          0x00000002 },
505                 { AUD_DCOC_1_SRC,       0x0000001b },
506                 { AUD_DCOC1_SHIFT,      0x00000000 },
507                 { AUD_DCOC_1_SHIFT_IN0, 0x0000000a },
508                 { AUD_DCOC_1_SHIFT_IN1, 0x00000008 },
509                 { AUD_IIR3_1_SEL,       0x00000023 },
510                 { AUD_RDSI_SEL,         0x00000017 },
511                 { AUD_RDSI_SHIFT,       0x00000000 },
512                 { AUD_RDSQ_SEL,         0x00000017 },
513                 { AUD_RDSQ_SHIFT,       0x00000000 },
514                 { AUD_POLYPH80SCALEFAC, 0x00000001 },
515
516                 { /* end of list */ },
517         };
518
519         static const struct rlist a2_table1[] = {
520                 // PAL-BG
521                 { AUD_DMD_RA_DDS,       0x002a73bd },
522                 { AUD_C1_UP_THR,        0x00007000 },
523                 { AUD_C1_LO_THR,        0x00005400 },
524                 { AUD_C2_UP_THR,        0x00005400 },
525                 { AUD_C2_LO_THR,        0x00003000 },
526                 { /* end of list */ },
527         };
528         static const struct rlist a2_table2[] = {
529                 // PAL-DK
530                 { AUD_DMD_RA_DDS,       0x002a73bd },
531                 { AUD_C1_UP_THR,        0x00007000 },
532                 { AUD_C1_LO_THR,        0x00005400 },
533                 { AUD_C2_UP_THR,        0x00005400 },
534                 { AUD_C2_LO_THR,        0x00003000 },
535                 { AUD_DN0_FREQ,         0x00003a1c },
536                 { AUD_DN2_FREQ,         0x0000d2e0 },
537                 { /* end of list */ },
538         };
539         static const struct rlist a2_table3[] = {
540                 // unknown, probably NTSC-M
541                 { AUD_DMD_RA_DDS,       0x002a2873 },
542                 { AUD_C1_UP_THR,        0x00003c00 },
543                 { AUD_C1_LO_THR,        0x00003000 },
544                 { AUD_C2_UP_THR,        0x00006000 },
545                 { AUD_C2_LO_THR,        0x00003c00 },
546                 { AUD_DN0_FREQ,         0x00002836 },
547                 { AUD_DN1_FREQ,         0x00003418 },
548                 { AUD_DN2_FREQ,         0x000029c7 },
549                 { AUD_POLY0_DDS_CONSTANT, 0x000a7540 },
550                 { /* end of list */ },
551         };
552
553         set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
554         set_audio_registers(core, a2_common);
555         switch (core->tvaudio) {
556         case WW_NICAM_I:
557                 /* gives at least mono according to the dscaler guys */
558                 /* so use use that while nicam is broken ...         */
559                 dprintk("%s PAL-I mono (status: unknown)\n",__FUNCTION__);
560                 set_audio_registers(core, a2_table1);
561                 cx_write(AUD_CTL, EN_A2_FORCE_MONO1);
562                 break;
563         case WW_A2_BG:
564                 dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
565                 set_audio_registers(core, a2_table1);
566                 break;
567         case WW_A2_DK:
568                 dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
569                 set_audio_registers(core, a2_table2);
570                 break;
571         case WW_A2_M:
572                 dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
573                 set_audio_registers(core, a2_table3);
574                 break;
575         };
576         set_audio_finish(core);
577 }
578
579 static void set_audio_standard_EIAJ(struct cx88_core *core)
580 {
581         static const struct rlist eiaj[] = {
582                 /* TODO: eiaj register settings are not there yet ... */
583
584                 { /* end of list */ },
585         };
586         dprintk("%s (status: unknown)\n",__FUNCTION__);
587
588         set_audio_start(core, 0x0002, EN_EIAJ_AUTO_STEREO);
589         set_audio_registers(core, eiaj);
590         set_audio_finish(core);
591 }
592
593 static void set_audio_standard_FM(struct cx88_core *core)
594 {
595 #if 0 /* FIXME */
596         switch (dev->audio_properties.FM_deemphasis)
597         {
598                 case WW_FM_DEEMPH_50:
599                         //Set De-emphasis filter coefficients for 50 usec
600                         cx_write(AUD_DEEMPH0_G0, 0x0C45);
601                         cx_write(AUD_DEEMPH0_A0, 0x6262);
602                         cx_write(AUD_DEEMPH0_B0, 0x1C29);
603                         cx_write(AUD_DEEMPH0_A1, 0x3FC66);
604                         cx_write(AUD_DEEMPH0_B1, 0x399A);
605
606                         cx_write(AUD_DEEMPH1_G0, 0x0D80);
607                         cx_write(AUD_DEEMPH1_A0, 0x6262);
608                         cx_write(AUD_DEEMPH1_B0, 0x1C29);
609                         cx_write(AUD_DEEMPH1_A1, 0x3FC66);
610                         cx_write(AUD_DEEMPH1_B1, 0x399A);
611
612                         break;
613
614                 case WW_FM_DEEMPH_75:
615                         //Set De-emphasis filter coefficients for 75 usec
616                         cx_write(AUD_DEEMPH0_G0, 0x91B );
617                         cx_write(AUD_DEEMPH0_A0, 0x6B68);
618                         cx_write(AUD_DEEMPH0_B0, 0x11EC);
619                         cx_write(AUD_DEEMPH0_A1, 0x3FC66);
620                         cx_write(AUD_DEEMPH0_B1, 0x399A);
621
622                         cx_write(AUD_DEEMPH1_G0, 0xAA0 );
623                         cx_write(AUD_DEEMPH1_A0, 0x6B68);
624                         cx_write(AUD_DEEMPH1_B0, 0x11EC);
625                         cx_write(AUD_DEEMPH1_A1, 0x3FC66);
626                         cx_write(AUD_DEEMPH1_B1, 0x399A);
627
628                         break;
629         }
630 #endif
631
632         dprintk("%s (status: unknown)\n",__FUNCTION__);
633         set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
634
635         // AB: 10/2/01: this register is not being reset appropriately on occasion.
636         cx_write(AUD_POLYPH80SCALEFAC,3);
637
638         set_audio_finish(core);
639 }
640
641 /* ----------------------------------------------------------- */
642
643 void cx88_set_tvaudio(struct cx88_core *core)
644 {
645         switch (core->tvaudio) {
646         case WW_BTSC:
647                 set_audio_standard_BTSC(core,0);
648                 break;
649         // case WW_NICAM_I:
650         case WW_NICAM_BGDKL:
651                 set_audio_standard_NICAM(core);
652                 break;
653         case WW_NICAM_I:
654         case WW_A2_BG:
655         case WW_A2_DK:
656         case WW_A2_M:
657                 set_audio_standard_A2(core);
658                 break;
659         case WW_EIAJ:
660                 set_audio_standard_EIAJ(core);
661                 break;
662         case WW_FM:
663                 set_audio_standard_FM(core);
664                 break;
665         case WW_SYSTEM_L_AM:
666                 set_audio_standard_NICAM_L(core);
667                 break;
668         case WW_NONE:
669         default:
670                 printk("%s/0: unknown tv audio mode [%d]\n",
671                        core->name, core->tvaudio);
672                 break;
673         }
674         return;
675 }
676
677 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
678 {
679         static char *m[] = {"stereo", "dual mono", "mono", "sap"};
680         static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
681         u32 reg,mode,pilot;
682
683         reg   = cx_read(AUD_STATUS);
684         mode  = reg & 0x03;
685         pilot = (reg >> 2) & 0x03;
686
687         if (core->astat != reg)
688                 dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
689                         reg, m[mode], p[pilot],
690                         aud_ctl_names[cx_read(AUD_CTL) & 63]);
691         core->astat = reg;
692
693         t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
694                 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
695         t->rxsubchans = V4L2_TUNER_SUB_MONO;
696         t->audmode    = V4L2_TUNER_MODE_MONO;
697
698         switch (core->tvaudio) {
699         case WW_BTSC:
700                 t->capability = V4L2_TUNER_CAP_STEREO |
701                         V4L2_TUNER_CAP_SAP;
702                 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
703                 if (1 == pilot) {
704                         /* SAP */
705                         t->rxsubchans |= V4L2_TUNER_SUB_SAP;
706                 }
707                 break;
708         case WW_A2_BG:
709         case WW_A2_DK:
710         case WW_A2_M:
711                 if (1 == pilot) {
712                         /* stereo */
713                         t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
714                         if (0 == mode)
715                                 t->audmode = V4L2_TUNER_MODE_STEREO;
716                 }
717                 if (2 == pilot) {
718                         /* dual language -- FIXME */
719                         t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
720                         t->audmode = V4L2_TUNER_MODE_LANG1;
721                 }
722                 break;
723         case WW_NICAM_BGDKL:
724                 if (0 == mode)
725                         t->audmode = V4L2_TUNER_MODE_STEREO;
726                 break;
727         default:
728                 t->rxsubchans = V4L2_TUNER_SUB_MONO;
729                 t->audmode    = V4L2_TUNER_MODE_MONO;
730                 break;
731         }
732         return;
733 }
734
735 void cx88_set_stereo(struct cx88_core *core, u32 mode)
736 {
737         u32 ctl  = UNSET;
738         u32 mask = UNSET;
739
740         switch (core->tvaudio) {
741         case WW_BTSC:
742                 switch (mode) {
743                 case V4L2_TUNER_MODE_MONO:
744                         ctl  = EN_BTSC_FORCE_MONO;
745                         mask = 0x3f;
746                         break;
747                 case V4L2_TUNER_MODE_SAP:
748                         ctl  = EN_BTSC_FORCE_SAP;
749                         mask = 0x3f;
750                         break;
751                 case V4L2_TUNER_MODE_STEREO:
752                         ctl  = EN_BTSC_AUTO_STEREO;
753                         mask = 0x3f;
754                         break;
755                 }
756                 break;
757         case WW_A2_BG:
758         case WW_A2_DK:
759         case WW_A2_M:
760                 switch (mode) {
761                 case V4L2_TUNER_MODE_MONO:
762                 case V4L2_TUNER_MODE_LANG1:
763                         ctl  = EN_A2_FORCE_MONO1;
764                         mask = 0x3f;
765                         break;
766                 case V4L2_TUNER_MODE_LANG2:
767                         ctl  = EN_A2_AUTO_MONO2;
768                         mask = 0x3f;
769                         break;
770                 case V4L2_TUNER_MODE_STEREO:
771                         ctl  = EN_A2_AUTO_STEREO | EN_DMTRX_SUMR;
772                         mask = 0x8bf;
773                         break;
774                 }
775                 break;
776         case WW_NICAM_BGDKL:
777                 switch (mode) {
778                 case V4L2_TUNER_MODE_MONO:
779                         ctl  = EN_NICAM_FORCE_MONO1;
780                         mask = 0x3f;
781                         break;
782                 case V4L2_TUNER_MODE_LANG1:
783                         ctl  = EN_NICAM_AUTO_MONO2;
784                         mask = 0x3f;
785                         break;
786                 case V4L2_TUNER_MODE_STEREO:
787                         ctl  = EN_NICAM_FORCE_STEREO | EN_DMTRX_LR;
788                         mask = 0x93f;
789                         break;
790                 }
791                 break;
792         case WW_FM:
793                 switch (mode) {
794                 case V4L2_TUNER_MODE_MONO:
795                         ctl  = EN_FMRADIO_FORCE_MONO;
796                         mask = 0x3f;
797                         break;
798                 case V4L2_TUNER_MODE_STEREO:
799                         ctl  = EN_FMRADIO_AUTO_STEREO;
800                         mask = 0x3f;
801                         break;
802                 }
803                 break;
804         }
805
806         if (UNSET != ctl) {
807                 cx_write(AUD_SOFT_RESET, 0x0001);
808                 cx_andor(AUD_CTL, mask,  ctl);
809                 cx_write(AUD_SOFT_RESET, 0x0000);
810                 dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x "
811                         "[status=0x%x,ctl=0x%x,vol=0x%x]\n",
812                         mask, ctl, cx_read(AUD_STATUS),
813                         cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
814         }
815         return;
816 }
817
818 int cx88_audio_thread(void *data)
819 {
820         struct cx88_core *core = data;
821         struct v4l2_tuner t;
822
823         dprintk("cx88: tvaudio thread started\n");
824         for (;;) {
825                 if (kthread_should_stop())
826                         break;
827
828                 /* just monitor the audio status for now ... */
829                 memset(&t,0,sizeof(t));
830                 cx88_get_stereo(core,&t);
831                 msleep_interruptible(1000);
832         }
833
834         dprintk("cx88: tvaudio thread exiting\n");
835         return 0;
836 }
837
838 /* ----------------------------------------------------------- */
839
840 EXPORT_SYMBOL(cx88_set_tvaudio);
841 EXPORT_SYMBOL(cx88_set_stereo);
842 EXPORT_SYMBOL(cx88_get_stereo);
843 EXPORT_SYMBOL(cx88_audio_thread);
844
845 /*
846  * Local variables:
847  * c-basic-offset: 8
848  * End:
849  */