Auto merge with /home/aegl/GIT/linus
[linux-2.6] / drivers / media / video / cx88 / cx88-tvaudio.c
1 /*
2     $Id: cx88-tvaudio.c,v 1.37 2005/07/07 13:58:38 mchehab 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/moduleparam.h>
41 #include <linux/errno.h>
42 #include <linux/kernel.h>
43 #include <linux/slab.h>
44 #include <linux/mm.h>
45 #include <linux/poll.h>
46 #include <linux/pci.h>
47 #include <linux/signal.h>
48 #include <linux/ioport.h>
49 #include <linux/sched.h>
50 #include <linux/types.h>
51 #include <linux/interrupt.h>
52 #include <linux/vmalloc.h>
53 #include <linux/init.h>
54 #include <linux/smp_lock.h>
55 #include <linux/delay.h>
56 #include <linux/kthread.h>
57
58 #include "cx88.h"
59
60 static unsigned int audio_debug = 0;
61 module_param(audio_debug,int,0644);
62 MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
63
64 #define dprintk(fmt, arg...)    if (audio_debug) \
65         printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
66
67 /* ----------------------------------------------------------- */
68
69 static char *aud_ctl_names[64] =
70 {
71         [ EN_BTSC_FORCE_MONO       ] = "BTSC_FORCE_MONO",
72         [ EN_BTSC_FORCE_STEREO     ] = "BTSC_FORCE_STEREO",
73         [ EN_BTSC_FORCE_SAP        ] = "BTSC_FORCE_SAP",
74         [ EN_BTSC_AUTO_STEREO      ] = "BTSC_AUTO_STEREO",
75         [ EN_BTSC_AUTO_SAP         ] = "BTSC_AUTO_SAP",
76         [ EN_A2_FORCE_MONO1        ] = "A2_FORCE_MONO1",
77         [ EN_A2_FORCE_MONO2        ] = "A2_FORCE_MONO2",
78         [ EN_A2_FORCE_STEREO       ] = "A2_FORCE_STEREO",
79         [ EN_A2_AUTO_MONO2         ] = "A2_AUTO_MONO2",
80         [ EN_A2_AUTO_STEREO        ] = "A2_AUTO_STEREO",
81         [ EN_EIAJ_FORCE_MONO1      ] = "EIAJ_FORCE_MONO1",
82         [ EN_EIAJ_FORCE_MONO2      ] = "EIAJ_FORCE_MONO2",
83         [ EN_EIAJ_FORCE_STEREO     ] = "EIAJ_FORCE_STEREO",
84         [ EN_EIAJ_AUTO_MONO2       ] = "EIAJ_AUTO_MONO2",
85         [ EN_EIAJ_AUTO_STEREO      ] = "EIAJ_AUTO_STEREO",
86         [ EN_NICAM_FORCE_MONO1     ] = "NICAM_FORCE_MONO1",
87         [ EN_NICAM_FORCE_MONO2     ] = "NICAM_FORCE_MONO2",
88         [ EN_NICAM_FORCE_STEREO    ] = "NICAM_FORCE_STEREO",
89         [ EN_NICAM_AUTO_MONO2      ] = "NICAM_AUTO_MONO2",
90         [ EN_NICAM_AUTO_STEREO     ] = "NICAM_AUTO_STEREO",
91         [ EN_FMRADIO_FORCE_MONO    ] = "FMRADIO_FORCE_MONO",
92         [ EN_FMRADIO_FORCE_STEREO  ] = "FMRADIO_FORCE_STEREO",
93         [ EN_FMRADIO_AUTO_STEREO   ] = "FMRADIO_AUTO_STEREO",
94 };
95
96 struct rlist {
97         u32 reg;
98         u32 val;
99 };
100
101 static void set_audio_registers(struct cx88_core *core,
102                                 const struct rlist *l)
103 {
104         int i;
105
106         for (i = 0; l[i].reg; i++) {
107                 switch (l[i].reg) {
108                 case AUD_PDF_DDS_CNST_BYTE2:
109                 case AUD_PDF_DDS_CNST_BYTE1:
110                 case AUD_PDF_DDS_CNST_BYTE0:
111                 case AUD_QAM_MODE:
112                 case AUD_PHACC_FREQ_8MSB:
113                 case AUD_PHACC_FREQ_8LSB:
114                         cx_writeb(l[i].reg, l[i].val);
115                         break;
116                 default:
117                         cx_write(l[i].reg, l[i].val);
118                         break;
119                 }
120         }
121 }
122
123 static void set_audio_start(struct cx88_core *core,
124                             u32 mode, u32 ctl)
125 {
126         // mute
127         cx_write(AUD_VOL_CTL,       (1 << 6));
128
129         //  increase level of input by 12dB
130 //      cx_write(AUD_AFE_12DB_EN,   0x0001);
131         cx_write(AUD_AFE_12DB_EN,   0x0000);
132
133         // start programming
134         cx_write(AUD_CTL,           0x0000);
135         cx_write(AUD_INIT,          mode);
136         cx_write(AUD_INIT_LD,       0x0001);
137         cx_write(AUD_SOFT_RESET,    0x0001);
138
139         cx_write(AUD_CTL,           ctl);
140 }
141
142 static void set_audio_finish(struct cx88_core *core)
143 {
144         u32 volume;
145
146         if (cx88_boards[core->board].blackbird) {
147                 // sets sound input from external adc
148                 cx_set(AUD_CTL, EN_I2SIN_ENABLE);
149                 //cx_write(AUD_I2SINPUTCNTL, 0);
150                 cx_write(AUD_I2SINPUTCNTL, 4);
151                 cx_write(AUD_BAUDRATE, 1);
152                 // 'pass-thru mode': this enables the i2s output to the mpeg encoder
153                 cx_set(AUD_CTL, EN_I2SOUT_ENABLE);
154                 cx_write(AUD_I2SOUTPUTCNTL, 1);
155                 cx_write(AUD_I2SCNTL, 0);
156                 //cx_write(AUD_APB_IN_RATE_ADJ, 0);
157         }
158
159         // finish programming
160         cx_write(AUD_SOFT_RESET, 0x0000);
161
162         // start audio processing
163         cx_set(AUD_CTL, EN_DAC_ENABLE);
164
165         // unmute
166         volume = cx_sread(SHADOW_AUD_VOL_CTL);
167         cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume);
168 }
169
170 /* ----------------------------------------------------------- */
171
172 static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap)
173 {
174         static const struct rlist btsc[] = {
175                 /* from dscaler */
176                 { AUD_OUT1_SEL,                0x00000013 },
177                 { AUD_OUT1_SHIFT,              0x00000000 },
178                 { AUD_POLY0_DDS_CONSTANT,      0x0012010c },
179                 { AUD_DMD_RA_DDS,              0x00c3e7aa },
180                 { AUD_DBX_IN_GAIN,             0x00004734 },
181                 { AUD_DBX_WBE_GAIN,            0x00004640 },
182                 { AUD_DBX_SE_GAIN,             0x00008d31 },
183                 { AUD_DCOC_0_SRC,              0x0000001a },
184                 { AUD_IIR1_4_SEL,              0x00000021 },
185                 { AUD_DCOC_PASS_IN,            0x00000003 },
186                 { AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
187                 { AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
188                 { AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
189                 { AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
190                 { AUD_DN0_FREQ,                0x0000283b },
191                 { AUD_DN2_SRC_SEL,             0x00000008 },
192                 { AUD_DN2_FREQ,                0x00003000 },
193                 { AUD_DN2_AFC,                 0x00000002 },
194                 { AUD_DN2_SHFT,                0x00000000 },
195                 { AUD_IIR2_2_SEL,              0x00000020 },
196                 { AUD_IIR2_2_SHIFT,            0x00000000 },
197                 { AUD_IIR2_3_SEL,              0x0000001f },
198                 { AUD_IIR2_3_SHIFT,            0x00000000 },
199                 { AUD_CRDC1_SRC_SEL,           0x000003ce },
200                 { AUD_CRDC1_SHIFT,             0x00000000 },
201                 { AUD_CORDIC_SHIFT_1,          0x00000007 },
202                 { AUD_DCOC_1_SRC,              0x0000001b },
203                 { AUD_DCOC1_SHIFT,             0x00000000 },
204                 { AUD_RDSI_SEL,                0x00000008 },
205                 { AUD_RDSQ_SEL,                0x00000008 },
206                 { AUD_RDSI_SHIFT,              0x00000000 },
207                 { AUD_RDSQ_SHIFT,              0x00000000 },
208                 { AUD_POLYPH80SCALEFAC,        0x00000003 },
209                 { /* end of list */ },
210         };
211         static const struct rlist btsc_sap[] = {
212                 { AUD_DBX_IN_GAIN,             0x00007200 },
213                 { AUD_DBX_WBE_GAIN,            0x00006200 },
214                 { AUD_DBX_SE_GAIN,             0x00006200 },
215                 { AUD_IIR1_1_SEL,              0x00000000 },
216                 { AUD_IIR1_3_SEL,              0x00000001 },
217                 { AUD_DN1_SRC_SEL,             0x00000007 },
218                 { AUD_IIR1_4_SHIFT,            0x00000006 },
219                 { AUD_IIR2_1_SHIFT,            0x00000000 },
220                 { AUD_IIR2_2_SHIFT,            0x00000000 },
221                 { AUD_IIR3_0_SHIFT,            0x00000000 },
222                 { AUD_IIR3_1_SHIFT,            0x00000000 },
223                 { AUD_IIR3_0_SEL,              0x0000000d },
224                 { AUD_IIR3_1_SEL,              0x0000000e },
225                 { AUD_DEEMPH1_SRC_SEL,         0x00000014 },
226                 { AUD_DEEMPH1_SHIFT,           0x00000000 },
227                 { AUD_DEEMPH1_G0,              0x00004000 },
228                 { AUD_DEEMPH1_A0,              0x00000000 },
229                 { AUD_DEEMPH1_B0,              0x00000000 },
230                 { AUD_DEEMPH1_A1,              0x00000000 },
231                 { AUD_DEEMPH1_B1,              0x00000000 },
232                 { AUD_OUT0_SEL,                0x0000003f },
233                 { AUD_OUT1_SEL,                0x0000003f },
234                 { AUD_DN1_AFC,                 0x00000002 },
235                 { AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
236                 { AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
237                 { AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
238                 { AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
239                 { AUD_IIR1_0_SEL,              0x0000001d },
240                 { AUD_IIR1_2_SEL,              0x0000001e },
241                 { AUD_IIR2_1_SEL,              0x00000002 },
242                 { AUD_IIR2_2_SEL,              0x00000004 },
243                 { AUD_IIR3_2_SEL,              0x0000000f },
244                 { AUD_DCOC2_SHIFT,             0x00000001 },
245                 { AUD_IIR3_2_SHIFT,            0x00000001 },
246                 { AUD_DEEMPH0_SRC_SEL,         0x00000014 },
247                 { AUD_CORDIC_SHIFT_1,          0x00000006 },
248                 { AUD_POLY0_DDS_CONSTANT,      0x000e4db2 },
249                 { AUD_DMD_RA_DDS,              0x00f696e6 },
250                 { AUD_IIR2_3_SEL,              0x00000025 },
251                 { AUD_IIR1_4_SEL,              0x00000021 },
252                 { AUD_DN1_FREQ,                0x0000c965 },
253                 { AUD_DCOC_PASS_IN,            0x00000003 },
254                 { AUD_DCOC_0_SRC,              0x0000001a },
255                 { AUD_DCOC_1_SRC,              0x0000001b },
256                 { AUD_DCOC1_SHIFT,             0x00000000 },
257                 { AUD_RDSI_SEL,                0x00000009 },
258                 { AUD_RDSQ_SEL,                0x00000009 },
259                 { AUD_RDSI_SHIFT,              0x00000000 },
260                 { AUD_RDSQ_SHIFT,              0x00000000 },
261                 { AUD_POLYPH80SCALEFAC,        0x00000003 },
262                 { /* end of list */ },
263         };
264
265         // dscaler: exactly taken from driver,
266         // dscaler: don't know why to set EN_FMRADIO_EN_RDS
267         if (sap) {
268                 dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
269                 set_audio_start(core, 0x0001,
270                                 EN_FMRADIO_EN_RDS | EN_BTSC_FORCE_SAP);
271                 set_audio_registers(core, btsc_sap);
272         } else {
273                 dprintk("%s (status: known-good)\n",__FUNCTION__);
274                 set_audio_start(core, 0x0001,
275                                 EN_FMRADIO_EN_RDS | EN_BTSC_AUTO_STEREO);
276                 set_audio_registers(core, btsc);
277         }
278         set_audio_finish(core);
279 }
280
281
282 static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
283 {
284         /* This is probably weird..
285          * Let's operate and find out. */
286
287         static const struct rlist nicam_l_mono[] = {
288                 { AUD_ERRLOGPERIOD_R,     0x00000064 },
289                 { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
290                 { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
291                 { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
292
293                 { AUD_PDF_DDS_CNST_BYTE2, 0x48 },
294                 { AUD_PDF_DDS_CNST_BYTE1, 0x3D },
295                 { AUD_QAM_MODE,           0x00 },
296                 { AUD_PDF_DDS_CNST_BYTE0, 0xf5 },
297                 { AUD_PHACC_FREQ_8MSB,    0x3a },
298                 { AUD_PHACC_FREQ_8LSB,    0x4a },
299
300                 { AUD_DEEMPHGAIN_R, 0x6680 },
301                 { AUD_DEEMPHNUMER1_R, 0x353DE },
302                 { AUD_DEEMPHNUMER2_R, 0x1B1 },
303                 { AUD_DEEMPHDENOM1_R, 0x0F3D0 },
304                 { AUD_DEEMPHDENOM2_R, 0x0 },
305                 { AUD_FM_MODE_ENABLE, 0x7 },
306                 { AUD_POLYPH80SCALEFAC, 0x3 },
307                 { AUD_AFE_12DB_EN, 0x1 },
308                 { AAGC_GAIN, 0x0 },
309                 { AAGC_HYST, 0x18 },
310                 { AAGC_DEF, 0x20 },
311                 { AUD_DN0_FREQ, 0x0 },
312                 { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 },
313                 { AUD_DCOC_0_SRC, 0x21 },
314                 { AUD_IIR1_0_SEL, 0x0 },
315                 { AUD_IIR1_0_SHIFT, 0x7 },
316                 { AUD_IIR1_1_SEL, 0x2 },
317                 { AUD_IIR1_1_SHIFT, 0x0 },
318                 { AUD_DCOC_1_SRC, 0x3 },
319                 { AUD_DCOC1_SHIFT, 0x0 },
320                 { AUD_DCOC_PASS_IN, 0x0 },
321                 { AUD_IIR1_2_SEL, 0x23 },
322                 { AUD_IIR1_2_SHIFT, 0x0 },
323                 { AUD_IIR1_3_SEL, 0x4 },
324                 { AUD_IIR1_3_SHIFT, 0x7 },
325                 { AUD_IIR1_4_SEL, 0x5 },
326                 { AUD_IIR1_4_SHIFT, 0x7 },
327                 { AUD_IIR3_0_SEL, 0x7 },
328                 { AUD_IIR3_0_SHIFT, 0x0 },
329                 { AUD_DEEMPH0_SRC_SEL, 0x11 },
330                 { AUD_DEEMPH0_SHIFT, 0x0 },
331                 { AUD_DEEMPH0_G0, 0x7000 },
332                 { AUD_DEEMPH0_A0, 0x0 },
333                 { AUD_DEEMPH0_B0, 0x0 },
334                 { AUD_DEEMPH0_A1, 0x0 },
335                 { AUD_DEEMPH0_B1, 0x0 },
336                 { AUD_DEEMPH1_SRC_SEL, 0x11 },
337                 { AUD_DEEMPH1_SHIFT, 0x0 },
338                 { AUD_DEEMPH1_G0, 0x7000 },
339                 { AUD_DEEMPH1_A0, 0x0 },
340                 { AUD_DEEMPH1_B0, 0x0 },
341                 { AUD_DEEMPH1_A1, 0x0 },
342                 { AUD_DEEMPH1_B1, 0x0 },
343                 { AUD_OUT0_SEL, 0x3F },
344                 { AUD_OUT1_SEL, 0x3F },
345                 { AUD_DMD_RA_DDS, 0x0F5C285 },
346                 { AUD_PLL_INT, 0x1E },
347                 { AUD_PLL_DDS, 0x0 },
348                 { AUD_PLL_FRAC, 0x0E542 },
349
350                 // setup QAM registers
351                 { AUD_RATE_ADJ1,      0x00000100 },
352                 { AUD_RATE_ADJ2,      0x00000200 },
353                 { AUD_RATE_ADJ3,      0x00000300 },
354                 { AUD_RATE_ADJ4,      0x00000400 },
355                 { AUD_RATE_ADJ5,      0x00000500 },
356                 { AUD_RATE_THRES_DMD, 0x000000C0 },
357                 { /* end of list */ },
358         };
359
360         static const struct rlist nicam_l[] = {
361                 // setup QAM registers
362                 { AUD_RATE_ADJ1, 0x00000060 },
363                 { AUD_RATE_ADJ2, 0x000000F9 },
364                 { AUD_RATE_ADJ3, 0x000001CC },
365                 { AUD_RATE_ADJ4, 0x000002B3 },
366                 { AUD_RATE_ADJ5, 0x00000726 },
367                 { AUD_DEEMPHDENOM1_R, 0x0000F3D0 },
368                 { AUD_DEEMPHDENOM2_R, 0x00000000 },
369                 { AUD_ERRLOGPERIOD_R, 0x00000064 },
370                 { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
371                 { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
372                 { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
373                 { AUD_POLYPH80SCALEFAC, 0x00000003 },
374                 { AUD_DMD_RA_DDS, 0x00C00000 },
375                 { AUD_PLL_INT, 0x0000001E },
376                 { AUD_PLL_DDS, 0x00000000 },
377                 { AUD_PLL_FRAC, 0x0000E542 },
378                 { AUD_START_TIMER, 0x00000000 },
379                 { AUD_DEEMPHNUMER1_R, 0x000353DE },
380                 { AUD_DEEMPHNUMER2_R, 0x000001B1 },
381                 { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
382                 { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
383                 { AUD_QAM_MODE, 0x05 },
384                 { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
385                 { AUD_PHACC_FREQ_8MSB, 0x34 },
386                 { AUD_PHACC_FREQ_8LSB, 0x4C },
387                 { AUD_DEEMPHGAIN_R, 0x00006680 },
388                 { AUD_RATE_THRES_DMD, 0x000000C0  },
389                 { /* end of list */ },
390         } ;
391         dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
392
393         if (!stereo) {
394                 /* AM mono sound */
395                 set_audio_start(core, 0x0004,
396                                 0x100c /* FIXME again */);
397                 set_audio_registers(core, nicam_l_mono);
398         } else {
399                 set_audio_start(core, 0x0010,
400                                 0x1924 /* FIXME again */);
401                 set_audio_registers(core, nicam_l);
402         }
403         set_audio_finish(core);
404
405 }
406
407 static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo)
408 {
409        static const struct rlist pal_i_fm_mono[] = {
410             {AUD_ERRLOGPERIOD_R,       0x00000064},
411             {AUD_ERRINTRPTTHSHLD1_R,   0x00000fff},
412             {AUD_ERRINTRPTTHSHLD2_R,   0x0000001f},
413             {AUD_ERRINTRPTTHSHLD3_R,   0x0000000f},
414             {AUD_PDF_DDS_CNST_BYTE2,   0x06},
415             {AUD_PDF_DDS_CNST_BYTE1,   0x82},
416             {AUD_PDF_DDS_CNST_BYTE0,   0x12},
417             {AUD_QAM_MODE,             0x05},
418             {AUD_PHACC_FREQ_8MSB,      0x3a},
419             {AUD_PHACC_FREQ_8LSB,      0x93},
420             {AUD_DMD_RA_DDS,           0x002a4f2f},
421             {AUD_PLL_INT,              0x0000001e},
422             {AUD_PLL_DDS,              0x00000004},
423             {AUD_PLL_FRAC,             0x0000e542},
424             {AUD_RATE_ADJ1,            0x00000100},
425             {AUD_RATE_ADJ2,            0x00000200},
426             {AUD_RATE_ADJ3,            0x00000300},
427             {AUD_RATE_ADJ4,            0x00000400},
428             {AUD_RATE_ADJ5,            0x00000500},
429             {AUD_THR_FR,               0x00000000},
430             {AUD_PILOT_BQD_1_K0,       0x0000755b},
431             {AUD_PILOT_BQD_1_K1,       0x00551340},
432             {AUD_PILOT_BQD_1_K2,       0x006d30be},
433             {AUD_PILOT_BQD_1_K3,       0xffd394af},
434             {AUD_PILOT_BQD_1_K4,       0x00400000},
435             {AUD_PILOT_BQD_2_K0,       0x00040000},
436             {AUD_PILOT_BQD_2_K1,       0x002a4841},
437             {AUD_PILOT_BQD_2_K2,       0x00400000},
438             {AUD_PILOT_BQD_2_K3,       0x00000000},
439             {AUD_PILOT_BQD_2_K4,       0x00000000},
440             {AUD_MODE_CHG_TIMER,       0x00000060},
441             {AUD_AFE_12DB_EN,          0x00000001},
442             {AAGC_HYST,                0x0000000a},
443             {AUD_CORDIC_SHIFT_0,       0x00000007},
444             {AUD_CORDIC_SHIFT_1,       0x00000007},
445             {AUD_C1_UP_THR,            0x00007000},
446             {AUD_C1_LO_THR,            0x00005400},
447             {AUD_C2_UP_THR,            0x00005400},
448             {AUD_C2_LO_THR,            0x00003000},
449             {AUD_DCOC_0_SRC,           0x0000001a},
450             {AUD_DCOC0_SHIFT,          0x00000000},
451             {AUD_DCOC_0_SHIFT_IN0,     0x0000000a},
452             {AUD_DCOC_0_SHIFT_IN1,     0x00000008},
453             {AUD_DCOC_PASS_IN,         0x00000003},
454             {AUD_IIR3_0_SEL,           0x00000021},
455             {AUD_DN2_AFC,              0x00000002},
456             {AUD_DCOC_1_SRC,           0x0000001b},
457             {AUD_DCOC1_SHIFT,          0x00000000},
458             {AUD_DCOC_1_SHIFT_IN0,     0x0000000a},
459             {AUD_DCOC_1_SHIFT_IN1,     0x00000008},
460             {AUD_IIR3_1_SEL,           0x00000023},
461             {AUD_DN0_FREQ,             0x000035a3},
462             {AUD_DN2_FREQ,             0x000029c7},
463             {AUD_CRDC0_SRC_SEL,        0x00000511},
464             {AUD_IIR1_0_SEL,           0x00000001},
465             {AUD_IIR1_1_SEL,           0x00000000},
466             {AUD_IIR3_2_SEL,           0x00000003},
467             {AUD_IIR3_2_SHIFT,         0x00000000},
468             {AUD_IIR3_0_SEL,           0x00000002},
469             {AUD_IIR2_0_SEL,           0x00000021},
470             {AUD_IIR2_0_SHIFT,         0x00000002},
471             {AUD_DEEMPH0_SRC_SEL,      0x0000000b},
472             {AUD_DEEMPH1_SRC_SEL,      0x0000000b},
473             {AUD_POLYPH80SCALEFAC,     0x00000001},
474             {AUD_START_TIMER,          0x00000000},
475             { /* end of list */ },
476        };
477
478        static const struct rlist pal_i_nicam[] = {
479            { AUD_RATE_ADJ1,           0x00000010 },
480            { AUD_RATE_ADJ2,           0x00000040 },
481            { AUD_RATE_ADJ3,           0x00000100 },
482            { AUD_RATE_ADJ4,           0x00000400 },
483            { AUD_RATE_ADJ5,           0x00001000 },
484            //     { AUD_DMD_RA_DDS,          0x00c0d5ce },
485            { AUD_DEEMPHGAIN_R,        0x000023c2 },
486            { AUD_DEEMPHNUMER1_R,      0x0002a7bc },
487            { AUD_DEEMPHNUMER2_R,      0x0003023e },
488            { AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
489            { AUD_DEEMPHDENOM2_R,      0x00000000 },
490            { AUD_DEEMPHDENOM2_R,      0x00000000 },
491            { AUD_ERRLOGPERIOD_R,      0x00000fff },
492            { AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
493            { AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
494            { AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
495            { AUD_POLYPH80SCALEFAC,    0x00000003 },
496            { AUD_PDF_DDS_CNST_BYTE2,  0x06 },
497            { AUD_PDF_DDS_CNST_BYTE1,  0x82 },
498            { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
499            { AUD_QAM_MODE,            0x05 },
500            { AUD_PDF_DDS_CNST_BYTE0,  0x12 },
501            { AUD_PHACC_FREQ_8MSB,     0x3a },
502            { AUD_PHACC_FREQ_8LSB,     0x93 },
503             { /* end of list */ },
504         };
505
506         dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
507
508         if (!stereo) {
509                 // FM mono
510                 set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1);
511                 set_audio_registers(core, pal_i_fm_mono);
512         } else {
513                 // Nicam Stereo
514                 set_audio_start(core, 0x0010, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
515                 set_audio_registers(core, pal_i_nicam);
516         }
517         set_audio_finish(core);
518 }
519
520 static void set_audio_standard_A2(struct cx88_core *core)
521 {
522         /* from dscaler cvs */
523         static const struct rlist a2_common[] = {
524                 { AUD_PDF_DDS_CNST_BYTE2,     0x06 },
525                 { AUD_PDF_DDS_CNST_BYTE1,     0x82 },
526                 { AUD_PDF_DDS_CNST_BYTE0,     0x12 },
527                 { AUD_QAM_MODE,               0x05 },
528                 { AUD_PHACC_FREQ_8MSB,        0x34 },
529                 { AUD_PHACC_FREQ_8LSB,        0x4c },
530
531                 { AUD_RATE_ADJ1,        0x00001000 },
532                 { AUD_RATE_ADJ2,        0x00002000 },
533                 { AUD_RATE_ADJ3,        0x00003000 },
534                 { AUD_RATE_ADJ4,        0x00004000 },
535                 { AUD_RATE_ADJ5,        0x00005000 },
536                 { AUD_THR_FR,           0x00000000 },
537                 { AAGC_HYST,            0x0000001a },
538                 { AUD_PILOT_BQD_1_K0,   0x0000755b },
539                 { AUD_PILOT_BQD_1_K1,   0x00551340 },
540                 { AUD_PILOT_BQD_1_K2,   0x006d30be },
541                 { AUD_PILOT_BQD_1_K3,   0xffd394af },
542                 { AUD_PILOT_BQD_1_K4,   0x00400000 },
543                 { AUD_PILOT_BQD_2_K0,   0x00040000 },
544                 { AUD_PILOT_BQD_2_K1,   0x002a4841 },
545                 { AUD_PILOT_BQD_2_K2,   0x00400000 },
546                 { AUD_PILOT_BQD_2_K3,   0x00000000 },
547                 { AUD_PILOT_BQD_2_K4,   0x00000000 },
548                 { AUD_MODE_CHG_TIMER,   0x00000040 },
549                 { AUD_START_TIMER,      0x00000200 },
550                 { AUD_AFE_12DB_EN,      0x00000000 },
551                 { AUD_CORDIC_SHIFT_0,   0x00000007 },
552                 { AUD_CORDIC_SHIFT_1,   0x00000007 },
553                 { AUD_DEEMPH0_G0,       0x00000380 },
554                 { AUD_DEEMPH1_G0,       0x00000380 },
555                 { AUD_DCOC_0_SRC,       0x0000001a },
556                 { AUD_DCOC0_SHIFT,      0x00000000 },
557                 { AUD_DCOC_0_SHIFT_IN0, 0x0000000a },
558                 { AUD_DCOC_0_SHIFT_IN1, 0x00000008 },
559                 { AUD_DCOC_PASS_IN,     0x00000003 },
560                 { AUD_IIR3_0_SEL,       0x00000021 },
561                 { AUD_DN2_AFC,          0x00000002 },
562                 { AUD_DCOC_1_SRC,       0x0000001b },
563                 { AUD_DCOC1_SHIFT,      0x00000000 },
564                 { AUD_DCOC_1_SHIFT_IN0, 0x0000000a },
565                 { AUD_DCOC_1_SHIFT_IN1, 0x00000008 },
566                 { AUD_IIR3_1_SEL,       0x00000023 },
567                 { AUD_RDSI_SEL,         0x00000017 },
568                 { AUD_RDSI_SHIFT,       0x00000000 },
569                 { AUD_RDSQ_SEL,         0x00000017 },
570                 { AUD_RDSQ_SHIFT,       0x00000000 },
571                 { AUD_POLYPH80SCALEFAC, 0x00000001 },
572
573                 { /* end of list */ },
574         };
575
576         static const struct rlist a2_table1[] = {
577                 // PAL-BG
578                 { AUD_DMD_RA_DDS,       0x002a73bd },
579                 { AUD_C1_UP_THR,        0x00007000 },
580                 { AUD_C1_LO_THR,        0x00005400 },
581                 { AUD_C2_UP_THR,        0x00005400 },
582                 { AUD_C2_LO_THR,        0x00003000 },
583                 { /* end of list */ },
584         };
585         static const struct rlist a2_table2[] = {
586                 // PAL-DK
587                 { AUD_DMD_RA_DDS,       0x002a73bd },
588                 { AUD_C1_UP_THR,        0x00007000 },
589                 { AUD_C1_LO_THR,        0x00005400 },
590                 { AUD_C2_UP_THR,        0x00005400 },
591                 { AUD_C2_LO_THR,        0x00003000 },
592                 { AUD_DN0_FREQ,         0x00003a1c },
593                 { AUD_DN2_FREQ,         0x0000d2e0 },
594                 { /* end of list */ },
595         };
596         static const struct rlist a2_table3[] = {
597                 // unknown, probably NTSC-M
598                 { AUD_DMD_RA_DDS,       0x002a2873 },
599                 { AUD_C1_UP_THR,        0x00003c00 },
600                 { AUD_C1_LO_THR,        0x00003000 },
601                 { AUD_C2_UP_THR,        0x00006000 },
602                 { AUD_C2_LO_THR,        0x00003c00 },
603                 { AUD_DN0_FREQ,         0x00002836 },
604                 { AUD_DN1_FREQ,         0x00003418 },
605                 { AUD_DN2_FREQ,         0x000029c7 },
606                 { AUD_POLY0_DDS_CONSTANT, 0x000a7540 },
607                 { /* end of list */ },
608         };
609
610         set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
611         set_audio_registers(core, a2_common);
612         switch (core->tvaudio) {
613         case WW_A2_BG:
614                 dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
615                 set_audio_registers(core, a2_table1);
616                 break;
617         case WW_A2_DK:
618                 dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
619                 set_audio_registers(core, a2_table2);
620                 break;
621         case WW_A2_M:
622                 dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
623                 set_audio_registers(core, a2_table3);
624                 break;
625         };
626         set_audio_finish(core);
627 }
628
629 static void set_audio_standard_EIAJ(struct cx88_core *core)
630 {
631         static const struct rlist eiaj[] = {
632                 /* TODO: eiaj register settings are not there yet ... */
633
634                 { /* end of list */ },
635         };
636         dprintk("%s (status: unknown)\n",__FUNCTION__);
637
638         set_audio_start(core, 0x0002, EN_EIAJ_AUTO_STEREO);
639         set_audio_registers(core, eiaj);
640         set_audio_finish(core);
641 }
642
643 static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph)
644 {
645         static const struct rlist fm_deemph_50[] = {
646                 { AUD_DEEMPH0_G0,       0x0C45 },
647                 { AUD_DEEMPH0_A0,       0x6262 },
648                 { AUD_DEEMPH0_B0,       0x1C29 },
649                 { AUD_DEEMPH0_A1,       0x3FC66},
650                 { AUD_DEEMPH0_B1,       0x399A },
651
652                 { AUD_DEEMPH1_G0,       0x0D80 },
653                 { AUD_DEEMPH1_A0,       0x6262 },
654                 { AUD_DEEMPH1_B0,       0x1C29 },
655                 { AUD_DEEMPH1_A1,       0x3FC66},
656                 { AUD_DEEMPH1_B1,       0x399A},
657
658                 { AUD_POLYPH80SCALEFAC, 0x0003},
659                 { /* end of list */ },
660         };
661         static const struct rlist fm_deemph_75[] = {
662                 { AUD_DEEMPH0_G0,       0x091B },
663                 { AUD_DEEMPH0_A0,       0x6B68 },
664                 { AUD_DEEMPH0_B0,       0x11EC },
665                 { AUD_DEEMPH0_A1,       0x3FC66},
666                 { AUD_DEEMPH0_B1,       0x399A },
667
668                 { AUD_DEEMPH1_G0,       0x0AA0 },
669                 { AUD_DEEMPH1_A0,       0x6B68 },
670                 { AUD_DEEMPH1_B0,       0x11EC },
671                 { AUD_DEEMPH1_A1,       0x3FC66},
672                 { AUD_DEEMPH1_B1,       0x399A},
673
674                 { AUD_POLYPH80SCALEFAC, 0x0003},
675                 { /* end of list */ },
676         };
677
678         /* It is enough to leave default values? */
679         static const struct rlist fm_no_deemph[] = {
680
681                 { AUD_POLYPH80SCALEFAC, 0x0003},
682                 { /* end of list */ },
683         };
684
685         dprintk("%s (status: unknown)\n",__FUNCTION__);
686         set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
687
688         switch (deemph)
689         {
690                 case FM_NO_DEEMPH:
691                         set_audio_registers(core, fm_no_deemph);
692                         break;
693
694                 case FM_DEEMPH_50:
695                         set_audio_registers(core, fm_deemph_50);
696                         break;
697
698                 case FM_DEEMPH_75:
699                         set_audio_registers(core, fm_deemph_75);
700                         break;
701         }
702
703         set_audio_finish(core);
704 }
705
706 /* ----------------------------------------------------------- */
707
708 void cx88_set_tvaudio(struct cx88_core *core)
709 {
710         switch (core->tvaudio) {
711         case WW_BTSC:
712                 set_audio_standard_BTSC(core,0);
713                 break;
714         case WW_NICAM_BGDKL:
715                 set_audio_standard_NICAM_L(core,0);
716                 break;
717         case WW_NICAM_I:
718                 set_audio_standard_PAL_I(core,0);
719                 break;
720         case WW_A2_BG:
721         case WW_A2_DK:
722         case WW_A2_M:
723                 set_audio_standard_A2(core);
724                 break;
725         case WW_EIAJ:
726                 set_audio_standard_EIAJ(core);
727                 break;
728         case WW_FM:
729                 set_audio_standard_FM(core,FM_NO_DEEMPH);
730                 break;
731         case WW_SYSTEM_L_AM:
732                 set_audio_standard_NICAM_L(core, 1);
733                 break;
734         case WW_NONE:
735         default:
736                 printk("%s/0: unknown tv audio mode [%d]\n",
737                        core->name, core->tvaudio);
738                 break;
739         }
740         return;
741 }
742
743 void cx88_newstation(struct cx88_core *core)
744 {
745         core->audiomode_manual = UNSET;
746
747         switch (core->tvaudio) {
748         case WW_SYSTEM_L_AM:
749                 /* try nicam ... */
750                 core->audiomode_current = V4L2_TUNER_MODE_STEREO;
751                 set_audio_standard_NICAM_L(core, 1);
752                 break;
753         }
754 }
755
756 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
757 {
758         static char *m[] = {"stereo", "dual mono", "mono", "sap"};
759         static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
760         u32 reg,mode,pilot;
761
762         reg   = cx_read(AUD_STATUS);
763         mode  = reg & 0x03;
764         pilot = (reg >> 2) & 0x03;
765
766         if (core->astat != reg)
767                 dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
768                         reg, m[mode], p[pilot],
769                         aud_ctl_names[cx_read(AUD_CTL) & 63]);
770         core->astat = reg;
771
772         t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
773                 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
774         t->rxsubchans = V4L2_TUNER_SUB_MONO;
775         t->audmode    = V4L2_TUNER_MODE_MONO;
776
777         switch (core->tvaudio) {
778         case WW_BTSC:
779                 t->capability = V4L2_TUNER_CAP_STEREO |
780                         V4L2_TUNER_CAP_SAP;
781                 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
782                 if (1 == pilot) {
783                         /* SAP */
784                         t->rxsubchans |= V4L2_TUNER_SUB_SAP;
785                 }
786                 break;
787         case WW_A2_BG:
788         case WW_A2_DK:
789         case WW_A2_M:
790                 if (1 == pilot) {
791                         /* stereo */
792                         t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
793                         if (0 == mode)
794                                 t->audmode = V4L2_TUNER_MODE_STEREO;
795                 }
796                 if (2 == pilot) {
797                         /* dual language -- FIXME */
798                         t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
799                         t->audmode = V4L2_TUNER_MODE_LANG1;
800                 }
801                 break;
802         case WW_NICAM_BGDKL:
803                 if (0 == mode) {
804                         t->audmode = V4L2_TUNER_MODE_STEREO;
805                         t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
806                 }
807                 break;
808         case WW_SYSTEM_L_AM:
809                 if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) {
810                         t->audmode = V4L2_TUNER_MODE_STEREO;
811                         t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
812                 }
813                 break ;
814         default:
815                 /* nothing */
816                 break;
817         }
818         return;
819 }
820
821 void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
822 {
823         u32 ctl  = UNSET;
824         u32 mask = UNSET;
825
826         if (manual) {
827                 core->audiomode_manual = mode;
828         } else {
829                 if (UNSET != core->audiomode_manual)
830                         return;
831         }
832         core->audiomode_current = mode;
833
834         switch (core->tvaudio) {
835         case WW_BTSC:
836                 switch (mode) {
837                 case V4L2_TUNER_MODE_MONO:
838                         ctl  = EN_BTSC_FORCE_MONO;
839                         mask = 0x3f;
840                         break;
841                 case V4L2_TUNER_MODE_SAP:
842                         ctl  = EN_BTSC_FORCE_SAP;
843                         mask = 0x3f;
844                         break;
845                 case V4L2_TUNER_MODE_STEREO:
846                         ctl  = EN_BTSC_AUTO_STEREO;
847                         mask = 0x3f;
848                         break;
849                 }
850                 break;
851         case WW_A2_BG:
852         case WW_A2_DK:
853         case WW_A2_M:
854                 switch (mode) {
855                 case V4L2_TUNER_MODE_MONO:
856                 case V4L2_TUNER_MODE_LANG1:
857                         ctl  = EN_A2_FORCE_MONO1;
858                         mask = 0x3f;
859                         break;
860                 case V4L2_TUNER_MODE_LANG2:
861                         ctl  = EN_A2_AUTO_MONO2;
862                         mask = 0x3f;
863                         break;
864                 case V4L2_TUNER_MODE_STEREO:
865                         ctl  = EN_A2_AUTO_STEREO | EN_DMTRX_SUMR;
866                         mask = 0x8bf;
867                         break;
868                 }
869                 break;
870         case WW_NICAM_BGDKL:
871                 switch (mode) {
872                 case V4L2_TUNER_MODE_MONO:
873                         ctl  = EN_NICAM_FORCE_MONO1;
874                         mask = 0x3f;
875                         break;
876                 case V4L2_TUNER_MODE_LANG1:
877                         ctl  = EN_NICAM_AUTO_MONO2;
878                         mask = 0x3f;
879                         break;
880                 case V4L2_TUNER_MODE_STEREO:
881                         ctl  = EN_NICAM_FORCE_STEREO | EN_DMTRX_LR;
882                         mask = 0x93f;
883                         break;
884                 }
885                 break;
886         case WW_SYSTEM_L_AM:
887                 switch (mode) {
888                 case V4L2_TUNER_MODE_MONO:
889                 case V4L2_TUNER_MODE_LANG1:  /* FIXME */
890                         set_audio_standard_NICAM_L(core, 0);
891                         break;
892                 case V4L2_TUNER_MODE_STEREO:
893                         set_audio_standard_NICAM_L(core, 1);
894                         break;
895                 }
896                 break;
897         case WW_NICAM_I:
898                 switch (mode) {
899                 case V4L2_TUNER_MODE_MONO:
900                 case V4L2_TUNER_MODE_LANG1:
901                         set_audio_standard_PAL_I(core, 0);
902                         break;
903                 case V4L2_TUNER_MODE_STEREO:
904                         set_audio_standard_PAL_I(core, 1);
905                         break;
906                 }
907                 break;
908         case WW_FM:
909                 switch (mode) {
910                 case V4L2_TUNER_MODE_MONO:
911                         ctl  = EN_FMRADIO_FORCE_MONO;
912                         mask = 0x3f;
913                         break;
914                 case V4L2_TUNER_MODE_STEREO:
915                         ctl  = EN_FMRADIO_AUTO_STEREO;
916                         mask = 0x3f;
917                         break;
918                 }
919                 break;
920         }
921
922         if (UNSET != ctl) {
923                 dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x "
924                         "[status=0x%x,ctl=0x%x,vol=0x%x]\n",
925                         mask, ctl, cx_read(AUD_STATUS),
926                         cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
927                 cx_andor(AUD_CTL, mask, ctl);
928         }
929         return;
930 }
931
932 int cx88_audio_thread(void *data)
933 {
934         struct cx88_core *core = data;
935         struct v4l2_tuner t;
936         u32 mode = 0;
937
938         dprintk("cx88: tvaudio thread started\n");
939         for (;;) {
940                 msleep_interruptible(1000);
941                 if (kthread_should_stop())
942                         break;
943
944                 /* just monitor the audio status for now ... */
945                 memset(&t,0,sizeof(t));
946                 cx88_get_stereo(core,&t);
947
948                 if (UNSET != core->audiomode_manual)
949                         /* manually set, don't do anything. */
950                         continue;
951
952                 /* monitor signal */
953                 if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
954                         mode = V4L2_TUNER_MODE_STEREO;
955                 else
956                         mode = V4L2_TUNER_MODE_MONO;
957                 if (mode == core->audiomode_current)
958                         continue;
959
960                 /* automatically switch to best available mode */
961                 cx88_set_stereo(core, mode, 0);
962         }
963
964         dprintk("cx88: tvaudio thread exiting\n");
965         return 0;
966 }
967
968 /* ----------------------------------------------------------- */
969
970 EXPORT_SYMBOL(cx88_set_tvaudio);
971 EXPORT_SYMBOL(cx88_newstation);
972 EXPORT_SYMBOL(cx88_set_stereo);
973 EXPORT_SYMBOL(cx88_get_stereo);
974 EXPORT_SYMBOL(cx88_audio_thread);
975
976 /*
977  * Local variables:
978  * c-basic-offset: 8
979  * End:
980  * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
981  */