Input: synaptics - fix setting packet size on passthrough port.
[pandora-kernel.git] / drivers / media / video / cx88 / cx88-tvaudio.c
1 /*
2     $Id: cx88-tvaudio.c,v 1.36 2005/06/05 05:53:45 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 #if 0
282 static void set_audio_standard_NICAM(struct cx88_core *core)
283 {
284         static const struct rlist nicam_common[] = {
285                 /* from dscaler */
286                 { AUD_RATE_ADJ1,           0x00000010 },
287                 { AUD_RATE_ADJ2,           0x00000040 },
288                 { AUD_RATE_ADJ3,           0x00000100 },
289                 { AUD_RATE_ADJ4,           0x00000400 },
290                 { AUD_RATE_ADJ5,           0x00001000 },
291     //          { AUD_DMD_RA_DDS,          0x00c0d5ce },
292
293                 // Deemphasis 1:
294                 { AUD_DEEMPHGAIN_R,        0x000023c2 },
295                 { AUD_DEEMPHNUMER1_R,      0x0002a7bc },
296                 { AUD_DEEMPHNUMER2_R,      0x0003023e },
297                 { AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
298                 { AUD_DEEMPHDENOM2_R,      0x00000000 },
299
300 #if 0
301                 // Deemphasis 2: (other tv norm?)
302                 { AUD_DEEMPHGAIN_R,        0x0000c600 },
303                 { AUD_DEEMPHNUMER1_R,      0x00066738 },
304                 { AUD_DEEMPHNUMER2_R,      0x00066739 },
305                 { AUD_DEEMPHDENOM1_R,      0x0001e88c },
306                 { AUD_DEEMPHDENOM2_R,      0x0001e88c },
307 #endif
308
309                 { AUD_DEEMPHDENOM2_R,      0x00000000 },
310                 { AUD_ERRLOGPERIOD_R,      0x00000fff },
311                 { AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
312                 { AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
313                 { AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
314                 { AUD_POLYPH80SCALEFAC,    0x00000003 },
315
316                 // setup QAM registers
317                 { AUD_PDF_DDS_CNST_BYTE2,  0x06 },
318                 { AUD_PDF_DDS_CNST_BYTE1,  0x82 },
319                 { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
320                 { AUD_QAM_MODE,            0x05 },
321
322                 { /* end of list */ },
323         };
324         static const struct rlist nicam_pal_i[] = {
325                 { AUD_PDF_DDS_CNST_BYTE0,  0x12 },
326                 { AUD_PHACC_FREQ_8MSB,     0x3a },
327                 { AUD_PHACC_FREQ_8LSB,     0x93 },
328
329                 { /* end of list */ },
330         };
331         static const struct rlist nicam_default[] = {
332                 { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
333                 { AUD_PHACC_FREQ_8MSB,     0x34 },
334                 { AUD_PHACC_FREQ_8LSB,     0x4c },
335
336                 { /* end of list */ },
337         };
338
339         set_audio_start(core, 0x0010,
340                         EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
341         set_audio_registers(core, nicam_common);
342         switch (core->tvaudio) {
343         case WW_NICAM_I:
344                 dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__);
345                 set_audio_registers(core, nicam_pal_i);
346                 break;
347         case WW_NICAM_BGDKL:
348                 dprintk("%s PAL-BGDK NICAM (status: unknown)\n",__FUNCTION__);
349                 set_audio_registers(core, nicam_default);
350                 break;
351         };
352         set_audio_finish(core);
353 }
354 #endif
355
356 static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
357 {
358         /* This is probably weird..
359          * Let's operate and find out. */
360
361         static const struct rlist nicam_l_mono[] = {
362                 { AUD_ERRLOGPERIOD_R,     0x00000064 },
363                 { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
364                 { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
365                 { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
366
367                 { AUD_PDF_DDS_CNST_BYTE2, 0x48 },
368                 { AUD_PDF_DDS_CNST_BYTE1, 0x3D },
369                 { AUD_QAM_MODE,           0x00 },
370                 { AUD_PDF_DDS_CNST_BYTE0, 0xf5 },
371                 { AUD_PHACC_FREQ_8MSB,    0x3a },
372                 { AUD_PHACC_FREQ_8LSB,    0x4a },
373
374                 { AUD_DEEMPHGAIN_R, 0x6680 },
375                 { AUD_DEEMPHNUMER1_R, 0x353DE },
376                 { AUD_DEEMPHNUMER2_R, 0x1B1 },
377                 { AUD_DEEMPHDENOM1_R, 0x0F3D0 },
378                 { AUD_DEEMPHDENOM2_R, 0x0 },
379                 { AUD_FM_MODE_ENABLE, 0x7 },
380                 { AUD_POLYPH80SCALEFAC, 0x3 },
381                 { AUD_AFE_12DB_EN, 0x1 },
382                 { AAGC_GAIN, 0x0 },
383                 { AAGC_HYST, 0x18 },
384                 { AAGC_DEF, 0x20 },
385                 { AUD_DN0_FREQ, 0x0 },
386                 { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 },
387                 { AUD_DCOC_0_SRC, 0x21 },
388                 { AUD_IIR1_0_SEL, 0x0 },
389                 { AUD_IIR1_0_SHIFT, 0x7 },
390                 { AUD_IIR1_1_SEL, 0x2 },
391                 { AUD_IIR1_1_SHIFT, 0x0 },
392                 { AUD_DCOC_1_SRC, 0x3 },
393                 { AUD_DCOC1_SHIFT, 0x0 },
394                 { AUD_DCOC_PASS_IN, 0x0 },
395                 { AUD_IIR1_2_SEL, 0x23 },
396                 { AUD_IIR1_2_SHIFT, 0x0 },
397                 { AUD_IIR1_3_SEL, 0x4 },
398                 { AUD_IIR1_3_SHIFT, 0x7 },
399                 { AUD_IIR1_4_SEL, 0x5 },
400                 { AUD_IIR1_4_SHIFT, 0x7 },
401                 { AUD_IIR3_0_SEL, 0x7 },
402                 { AUD_IIR3_0_SHIFT, 0x0 },
403                 { AUD_DEEMPH0_SRC_SEL, 0x11 },
404                 { AUD_DEEMPH0_SHIFT, 0x0 },
405                 { AUD_DEEMPH0_G0, 0x7000 },
406                 { AUD_DEEMPH0_A0, 0x0 },
407                 { AUD_DEEMPH0_B0, 0x0 },
408                 { AUD_DEEMPH0_A1, 0x0 },
409                 { AUD_DEEMPH0_B1, 0x0 },
410                 { AUD_DEEMPH1_SRC_SEL, 0x11 },
411                 { AUD_DEEMPH1_SHIFT, 0x0 },
412                 { AUD_DEEMPH1_G0, 0x7000 },
413                 { AUD_DEEMPH1_A0, 0x0 },
414                 { AUD_DEEMPH1_B0, 0x0 },
415                 { AUD_DEEMPH1_A1, 0x0 },
416                 { AUD_DEEMPH1_B1, 0x0 },
417                 { AUD_OUT0_SEL, 0x3F },
418                 { AUD_OUT1_SEL, 0x3F },
419                 { AUD_DMD_RA_DDS, 0x0F5C285 },
420                 { AUD_PLL_INT, 0x1E },
421                 { AUD_PLL_DDS, 0x0 },
422                 { AUD_PLL_FRAC, 0x0E542 },
423
424                 // setup QAM registers
425                 { AUD_RATE_ADJ1,      0x00000100 },
426                 { AUD_RATE_ADJ2,      0x00000200 },
427                 { AUD_RATE_ADJ3,      0x00000300 },
428                 { AUD_RATE_ADJ4,      0x00000400 },
429                 { AUD_RATE_ADJ5,      0x00000500 },
430                 { AUD_RATE_THRES_DMD, 0x000000C0 },
431                 { /* end of list */ },
432         };
433
434         static const struct rlist nicam_l[] = {
435                 // setup QAM registers
436                 { AUD_RATE_ADJ1, 0x00000060 },
437                 { AUD_RATE_ADJ2, 0x000000F9 },
438                 { AUD_RATE_ADJ3, 0x000001CC },
439                 { AUD_RATE_ADJ4, 0x000002B3 },
440                 { AUD_RATE_ADJ5, 0x00000726 },
441                 { AUD_DEEMPHDENOM1_R, 0x0000F3D0 },
442                 { AUD_DEEMPHDENOM2_R, 0x00000000 },
443                 { AUD_ERRLOGPERIOD_R, 0x00000064 },
444                 { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
445                 { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
446                 { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
447                 { AUD_POLYPH80SCALEFAC, 0x00000003 },
448                 { AUD_DMD_RA_DDS, 0x00C00000 },
449                 { AUD_PLL_INT, 0x0000001E },
450                 { AUD_PLL_DDS, 0x00000000 },
451                 { AUD_PLL_FRAC, 0x0000E542 },
452                 { AUD_START_TIMER, 0x00000000 },
453                 { AUD_DEEMPHNUMER1_R, 0x000353DE },
454                 { AUD_DEEMPHNUMER2_R, 0x000001B1 },
455                 { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
456                 { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
457                 { AUD_QAM_MODE, 0x05 },
458                 { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
459                 { AUD_PHACC_FREQ_8MSB, 0x34 },
460                 { AUD_PHACC_FREQ_8LSB, 0x4C },
461                 { AUD_DEEMPHGAIN_R, 0x00006680 },
462                 { AUD_RATE_THRES_DMD, 0x000000C0  },
463                 { /* end of list */ },
464         } ;
465         dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
466
467         if (!stereo) {
468                 /* AM mono sound */
469                 set_audio_start(core, 0x0004,
470                                 0x100c /* FIXME again */);
471                 set_audio_registers(core, nicam_l_mono);
472         } else {
473                 set_audio_start(core, 0x0010,
474                                 0x1924 /* FIXME again */);
475                 set_audio_registers(core, nicam_l);
476         }
477         set_audio_finish(core);
478
479 }
480
481 static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo)
482 {
483        static const struct rlist pal_i_fm_mono[] = {
484             {AUD_ERRLOGPERIOD_R,       0x00000064},
485             {AUD_ERRINTRPTTHSHLD1_R,   0x00000fff},
486             {AUD_ERRINTRPTTHSHLD2_R,   0x0000001f},
487             {AUD_ERRINTRPTTHSHLD3_R,   0x0000000f},
488             {AUD_PDF_DDS_CNST_BYTE2,   0x06},
489             {AUD_PDF_DDS_CNST_BYTE1,   0x82},
490             {AUD_PDF_DDS_CNST_BYTE0,   0x12},
491             {AUD_QAM_MODE,             0x05},
492             {AUD_PHACC_FREQ_8MSB,      0x3a},
493             {AUD_PHACC_FREQ_8LSB,      0x93},
494             {AUD_DMD_RA_DDS,           0x002a4f2f},
495             {AUD_PLL_INT,              0x0000001e},
496             {AUD_PLL_DDS,              0x00000004},
497             {AUD_PLL_FRAC,             0x0000e542},
498             {AUD_RATE_ADJ1,            0x00000100},
499             {AUD_RATE_ADJ2,            0x00000200},
500             {AUD_RATE_ADJ3,            0x00000300},
501             {AUD_RATE_ADJ4,            0x00000400},
502             {AUD_RATE_ADJ5,            0x00000500},
503             {AUD_THR_FR,               0x00000000},
504             {AUD_PILOT_BQD_1_K0,       0x0000755b},
505             {AUD_PILOT_BQD_1_K1,       0x00551340},
506             {AUD_PILOT_BQD_1_K2,       0x006d30be},
507             {AUD_PILOT_BQD_1_K3,       0xffd394af},
508             {AUD_PILOT_BQD_1_K4,       0x00400000},
509             {AUD_PILOT_BQD_2_K0,       0x00040000},
510             {AUD_PILOT_BQD_2_K1,       0x002a4841},
511             {AUD_PILOT_BQD_2_K2,       0x00400000},
512             {AUD_PILOT_BQD_2_K3,       0x00000000},
513             {AUD_PILOT_BQD_2_K4,       0x00000000},
514             {AUD_MODE_CHG_TIMER,       0x00000060},
515             {AUD_AFE_12DB_EN,          0x00000001},
516             {AAGC_HYST,                0x0000000a},
517             {AUD_CORDIC_SHIFT_0,       0x00000007},
518             {AUD_CORDIC_SHIFT_1,       0x00000007},
519             {AUD_C1_UP_THR,            0x00007000},
520             {AUD_C1_LO_THR,            0x00005400},
521             {AUD_C2_UP_THR,            0x00005400},
522             {AUD_C2_LO_THR,            0x00003000},
523             {AUD_DCOC_0_SRC,           0x0000001a},
524             {AUD_DCOC0_SHIFT,          0x00000000},
525             {AUD_DCOC_0_SHIFT_IN0,     0x0000000a},
526             {AUD_DCOC_0_SHIFT_IN1,     0x00000008},
527             {AUD_DCOC_PASS_IN,         0x00000003},
528             {AUD_IIR3_0_SEL,           0x00000021},
529             {AUD_DN2_AFC,              0x00000002},
530             {AUD_DCOC_1_SRC,           0x0000001b},
531             {AUD_DCOC1_SHIFT,          0x00000000},
532             {AUD_DCOC_1_SHIFT_IN0,     0x0000000a},
533             {AUD_DCOC_1_SHIFT_IN1,     0x00000008},
534             {AUD_IIR3_1_SEL,           0x00000023},
535             {AUD_DN0_FREQ,             0x000035a3},
536             {AUD_DN2_FREQ,             0x000029c7},
537             {AUD_CRDC0_SRC_SEL,        0x00000511},
538             {AUD_IIR1_0_SEL,           0x00000001},
539             {AUD_IIR1_1_SEL,           0x00000000},
540             {AUD_IIR3_2_SEL,           0x00000003},
541             {AUD_IIR3_2_SHIFT,         0x00000000},
542             {AUD_IIR3_0_SEL,           0x00000002},
543             {AUD_IIR2_0_SEL,           0x00000021},
544             {AUD_IIR2_0_SHIFT,         0x00000002},
545             {AUD_DEEMPH0_SRC_SEL,      0x0000000b},
546             {AUD_DEEMPH1_SRC_SEL,      0x0000000b},
547             {AUD_POLYPH80SCALEFAC,     0x00000001},
548             {AUD_START_TIMER,          0x00000000},
549             { /* end of list */ },
550        };
551
552        static const struct rlist pal_i_nicam[] = {
553            { AUD_RATE_ADJ1,           0x00000010 },
554            { AUD_RATE_ADJ2,           0x00000040 },
555            { AUD_RATE_ADJ3,           0x00000100 },
556            { AUD_RATE_ADJ4,           0x00000400 },
557            { AUD_RATE_ADJ5,           0x00001000 },
558            //     { AUD_DMD_RA_DDS,          0x00c0d5ce },
559            { AUD_DEEMPHGAIN_R,        0x000023c2 },
560            { AUD_DEEMPHNUMER1_R,      0x0002a7bc },
561            { AUD_DEEMPHNUMER2_R,      0x0003023e },
562            { AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
563            { AUD_DEEMPHDENOM2_R,      0x00000000 },
564            { AUD_DEEMPHDENOM2_R,      0x00000000 },
565            { AUD_ERRLOGPERIOD_R,      0x00000fff },
566            { AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
567            { AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
568            { AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
569            { AUD_POLYPH80SCALEFAC,    0x00000003 },
570            { AUD_PDF_DDS_CNST_BYTE2,  0x06 },
571            { AUD_PDF_DDS_CNST_BYTE1,  0x82 },
572            { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
573            { AUD_QAM_MODE,            0x05 },
574            { AUD_PDF_DDS_CNST_BYTE0,  0x12 },
575            { AUD_PHACC_FREQ_8MSB,     0x3a },
576            { AUD_PHACC_FREQ_8LSB,     0x93 },
577             { /* end of list */ },
578         };
579
580         dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
581
582         if (!stereo) {
583                 // FM mono
584                 set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1);
585                 set_audio_registers(core, pal_i_fm_mono);
586         } else {
587                 // Nicam Stereo
588                 set_audio_start(core, 0x0010, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
589                 set_audio_registers(core, pal_i_nicam);
590         }
591         set_audio_finish(core);
592 }
593
594 static void set_audio_standard_A2(struct cx88_core *core)
595 {
596         /* from dscaler cvs */
597         static const struct rlist a2_common[] = {
598                 { AUD_PDF_DDS_CNST_BYTE2,     0x06 },
599                 { AUD_PDF_DDS_CNST_BYTE1,     0x82 },
600                 { AUD_PDF_DDS_CNST_BYTE0,     0x12 },
601                 { AUD_QAM_MODE,               0x05 },
602                 { AUD_PHACC_FREQ_8MSB,        0x34 },
603                 { AUD_PHACC_FREQ_8LSB,        0x4c },
604
605                 { AUD_RATE_ADJ1,        0x00001000 },
606                 { AUD_RATE_ADJ2,        0x00002000 },
607                 { AUD_RATE_ADJ3,        0x00003000 },
608                 { AUD_RATE_ADJ4,        0x00004000 },
609                 { AUD_RATE_ADJ5,        0x00005000 },
610                 { AUD_THR_FR,           0x00000000 },
611                 { AAGC_HYST,            0x0000001a },
612                 { AUD_PILOT_BQD_1_K0,   0x0000755b },
613                 { AUD_PILOT_BQD_1_K1,   0x00551340 },
614                 { AUD_PILOT_BQD_1_K2,   0x006d30be },
615                 { AUD_PILOT_BQD_1_K3,   0xffd394af },
616                 { AUD_PILOT_BQD_1_K4,   0x00400000 },
617                 { AUD_PILOT_BQD_2_K0,   0x00040000 },
618                 { AUD_PILOT_BQD_2_K1,   0x002a4841 },
619                 { AUD_PILOT_BQD_2_K2,   0x00400000 },
620                 { AUD_PILOT_BQD_2_K3,   0x00000000 },
621                 { AUD_PILOT_BQD_2_K4,   0x00000000 },
622                 { AUD_MODE_CHG_TIMER,   0x00000040 },
623                 { AUD_START_TIMER,      0x00000200 },
624                 { AUD_AFE_12DB_EN,      0x00000000 },
625                 { AUD_CORDIC_SHIFT_0,   0x00000007 },
626                 { AUD_CORDIC_SHIFT_1,   0x00000007 },
627                 { AUD_DEEMPH0_G0,       0x00000380 },
628                 { AUD_DEEMPH1_G0,       0x00000380 },
629                 { AUD_DCOC_0_SRC,       0x0000001a },
630                 { AUD_DCOC0_SHIFT,      0x00000000 },
631                 { AUD_DCOC_0_SHIFT_IN0, 0x0000000a },
632                 { AUD_DCOC_0_SHIFT_IN1, 0x00000008 },
633                 { AUD_DCOC_PASS_IN,     0x00000003 },
634                 { AUD_IIR3_0_SEL,       0x00000021 },
635                 { AUD_DN2_AFC,          0x00000002 },
636                 { AUD_DCOC_1_SRC,       0x0000001b },
637                 { AUD_DCOC1_SHIFT,      0x00000000 },
638                 { AUD_DCOC_1_SHIFT_IN0, 0x0000000a },
639                 { AUD_DCOC_1_SHIFT_IN1, 0x00000008 },
640                 { AUD_IIR3_1_SEL,       0x00000023 },
641                 { AUD_RDSI_SEL,         0x00000017 },
642                 { AUD_RDSI_SHIFT,       0x00000000 },
643                 { AUD_RDSQ_SEL,         0x00000017 },
644                 { AUD_RDSQ_SHIFT,       0x00000000 },
645                 { AUD_POLYPH80SCALEFAC, 0x00000001 },
646
647                 { /* end of list */ },
648         };
649
650         static const struct rlist a2_table1[] = {
651                 // PAL-BG
652                 { AUD_DMD_RA_DDS,       0x002a73bd },
653                 { AUD_C1_UP_THR,        0x00007000 },
654                 { AUD_C1_LO_THR,        0x00005400 },
655                 { AUD_C2_UP_THR,        0x00005400 },
656                 { AUD_C2_LO_THR,        0x00003000 },
657                 { /* end of list */ },
658         };
659         static const struct rlist a2_table2[] = {
660                 // PAL-DK
661                 { AUD_DMD_RA_DDS,       0x002a73bd },
662                 { AUD_C1_UP_THR,        0x00007000 },
663                 { AUD_C1_LO_THR,        0x00005400 },
664                 { AUD_C2_UP_THR,        0x00005400 },
665                 { AUD_C2_LO_THR,        0x00003000 },
666                 { AUD_DN0_FREQ,         0x00003a1c },
667                 { AUD_DN2_FREQ,         0x0000d2e0 },
668                 { /* end of list */ },
669         };
670         static const struct rlist a2_table3[] = {
671                 // unknown, probably NTSC-M
672                 { AUD_DMD_RA_DDS,       0x002a2873 },
673                 { AUD_C1_UP_THR,        0x00003c00 },
674                 { AUD_C1_LO_THR,        0x00003000 },
675                 { AUD_C2_UP_THR,        0x00006000 },
676                 { AUD_C2_LO_THR,        0x00003c00 },
677                 { AUD_DN0_FREQ,         0x00002836 },
678                 { AUD_DN1_FREQ,         0x00003418 },
679                 { AUD_DN2_FREQ,         0x000029c7 },
680                 { AUD_POLY0_DDS_CONSTANT, 0x000a7540 },
681                 { /* end of list */ },
682         };
683
684         set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO);
685         set_audio_registers(core, a2_common);
686         switch (core->tvaudio) {
687         case WW_A2_BG:
688                 dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
689                 set_audio_registers(core, a2_table1);
690                 break;
691         case WW_A2_DK:
692                 dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
693                 set_audio_registers(core, a2_table2);
694                 break;
695         case WW_A2_M:
696                 dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
697                 set_audio_registers(core, a2_table3);
698                 break;
699         };
700         set_audio_finish(core);
701 }
702
703 static void set_audio_standard_EIAJ(struct cx88_core *core)
704 {
705         static const struct rlist eiaj[] = {
706                 /* TODO: eiaj register settings are not there yet ... */
707
708                 { /* end of list */ },
709         };
710         dprintk("%s (status: unknown)\n",__FUNCTION__);
711
712         set_audio_start(core, 0x0002, EN_EIAJ_AUTO_STEREO);
713         set_audio_registers(core, eiaj);
714         set_audio_finish(core);
715 }
716
717 static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph)
718 {
719         static const struct rlist fm_deemph_50[] = {
720                 { AUD_DEEMPH0_G0,       0x0C45 },
721                 { AUD_DEEMPH0_A0,       0x6262 },
722                 { AUD_DEEMPH0_B0,       0x1C29 },
723                 { AUD_DEEMPH0_A1,       0x3FC66},
724                 { AUD_DEEMPH0_B1,       0x399A },
725
726                 { AUD_DEEMPH1_G0,       0x0D80 },
727                 { AUD_DEEMPH1_A0,       0x6262 },
728                 { AUD_DEEMPH1_B0,       0x1C29 },
729                 { AUD_DEEMPH1_A1,       0x3FC66},
730                 { AUD_DEEMPH1_B1,       0x399A},
731
732                 { AUD_POLYPH80SCALEFAC, 0x0003},
733                 { /* end of list */ },
734         };
735         static const struct rlist fm_deemph_75[] = {
736                 { AUD_DEEMPH0_G0,       0x091B },
737                 { AUD_DEEMPH0_A0,       0x6B68 },
738                 { AUD_DEEMPH0_B0,       0x11EC },
739                 { AUD_DEEMPH0_A1,       0x3FC66},
740                 { AUD_DEEMPH0_B1,       0x399A },
741
742                 { AUD_DEEMPH1_G0,       0x0AA0 },
743                 { AUD_DEEMPH1_A0,       0x6B68 },
744                 { AUD_DEEMPH1_B0,       0x11EC },
745                 { AUD_DEEMPH1_A1,       0x3FC66},
746                 { AUD_DEEMPH1_B1,       0x399A},
747
748                 { AUD_POLYPH80SCALEFAC, 0x0003},
749                 { /* end of list */ },
750         };
751
752         /* It is enough to leave default values? */
753         static const struct rlist fm_no_deemph[] = {
754
755                 { AUD_POLYPH80SCALEFAC, 0x0003},
756                 { /* end of list */ },
757         };
758
759         dprintk("%s (status: unknown)\n",__FUNCTION__);
760         set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
761
762         switch (deemph)
763         {
764                 case FM_NO_DEEMPH:
765                         set_audio_registers(core, fm_no_deemph);
766                         break;
767
768                 case FM_DEEMPH_50:
769                         set_audio_registers(core, fm_deemph_50);
770                         break;
771
772                 case FM_DEEMPH_75:
773                         set_audio_registers(core, fm_deemph_75);
774                         break;
775         }
776
777         set_audio_finish(core);
778 }
779
780 /* ----------------------------------------------------------- */
781
782 void cx88_set_tvaudio(struct cx88_core *core)
783 {
784         switch (core->tvaudio) {
785         case WW_BTSC:
786                 set_audio_standard_BTSC(core,0);
787                 break;
788         case WW_NICAM_BGDKL:
789                 set_audio_standard_NICAM_L(core,0);
790                 break;
791         case WW_NICAM_I:
792                 set_audio_standard_PAL_I(core,0);
793                 break;
794         case WW_A2_BG:
795         case WW_A2_DK:
796         case WW_A2_M:
797                 set_audio_standard_A2(core);
798                 break;
799         case WW_EIAJ:
800                 set_audio_standard_EIAJ(core);
801                 break;
802         case WW_FM:
803                 set_audio_standard_FM(core,FM_NO_DEEMPH);
804                 break;
805         case WW_SYSTEM_L_AM:
806                 set_audio_standard_NICAM_L(core, 1);
807                 break;
808         case WW_NONE:
809         default:
810                 printk("%s/0: unknown tv audio mode [%d]\n",
811                        core->name, core->tvaudio);
812                 break;
813         }
814         return;
815 }
816
817 void cx88_newstation(struct cx88_core *core)
818 {
819         core->audiomode_manual = UNSET;
820
821         switch (core->tvaudio) {
822         case WW_SYSTEM_L_AM:
823                 /* try nicam ... */
824                 core->audiomode_current = V4L2_TUNER_MODE_STEREO;
825                 set_audio_standard_NICAM_L(core, 1);
826                 break;
827         }
828 }
829
830 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
831 {
832         static char *m[] = {"stereo", "dual mono", "mono", "sap"};
833         static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
834         u32 reg,mode,pilot;
835
836         reg   = cx_read(AUD_STATUS);
837         mode  = reg & 0x03;
838         pilot = (reg >> 2) & 0x03;
839
840         if (core->astat != reg)
841                 dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n",
842                         reg, m[mode], p[pilot],
843                         aud_ctl_names[cx_read(AUD_CTL) & 63]);
844         core->astat = reg;
845
846         t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
847                 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
848         t->rxsubchans = V4L2_TUNER_SUB_MONO;
849         t->audmode    = V4L2_TUNER_MODE_MONO;
850
851         switch (core->tvaudio) {
852         case WW_BTSC:
853                 t->capability = V4L2_TUNER_CAP_STEREO |
854                         V4L2_TUNER_CAP_SAP;
855                 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
856                 if (1 == pilot) {
857                         /* SAP */
858                         t->rxsubchans |= V4L2_TUNER_SUB_SAP;
859                 }
860                 break;
861         case WW_A2_BG:
862         case WW_A2_DK:
863         case WW_A2_M:
864                 if (1 == pilot) {
865                         /* stereo */
866                         t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
867                         if (0 == mode)
868                                 t->audmode = V4L2_TUNER_MODE_STEREO;
869                 }
870                 if (2 == pilot) {
871                         /* dual language -- FIXME */
872                         t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
873                         t->audmode = V4L2_TUNER_MODE_LANG1;
874                 }
875                 break;
876         case WW_NICAM_BGDKL:
877                 if (0 == mode) {
878                         t->audmode = V4L2_TUNER_MODE_STEREO;
879                         t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
880                 }
881                 break;
882         case WW_SYSTEM_L_AM:
883                 if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) {
884                         t->audmode = V4L2_TUNER_MODE_STEREO;
885                         t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
886                 }
887                 break ;
888         default:
889                 /* nothing */
890                 break;
891         }
892         return;
893 }
894
895 void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
896 {
897         u32 ctl  = UNSET;
898         u32 mask = UNSET;
899
900         if (manual) {
901                 core->audiomode_manual = mode;
902         } else {
903                 if (UNSET != core->audiomode_manual)
904                         return;
905         }
906         core->audiomode_current = mode;
907
908         switch (core->tvaudio) {
909         case WW_BTSC:
910                 switch (mode) {
911                 case V4L2_TUNER_MODE_MONO:
912                         ctl  = EN_BTSC_FORCE_MONO;
913                         mask = 0x3f;
914                         break;
915                 case V4L2_TUNER_MODE_SAP:
916                         ctl  = EN_BTSC_FORCE_SAP;
917                         mask = 0x3f;
918                         break;
919                 case V4L2_TUNER_MODE_STEREO:
920                         ctl  = EN_BTSC_AUTO_STEREO;
921                         mask = 0x3f;
922                         break;
923                 }
924                 break;
925         case WW_A2_BG:
926         case WW_A2_DK:
927         case WW_A2_M:
928                 switch (mode) {
929                 case V4L2_TUNER_MODE_MONO:
930                 case V4L2_TUNER_MODE_LANG1:
931                         ctl  = EN_A2_FORCE_MONO1;
932                         mask = 0x3f;
933                         break;
934                 case V4L2_TUNER_MODE_LANG2:
935                         ctl  = EN_A2_AUTO_MONO2;
936                         mask = 0x3f;
937                         break;
938                 case V4L2_TUNER_MODE_STEREO:
939                         ctl  = EN_A2_AUTO_STEREO | EN_DMTRX_SUMR;
940                         mask = 0x8bf;
941                         break;
942                 }
943                 break;
944         case WW_NICAM_BGDKL:
945                 switch (mode) {
946                 case V4L2_TUNER_MODE_MONO:
947                         ctl  = EN_NICAM_FORCE_MONO1;
948                         mask = 0x3f;
949                         break;
950                 case V4L2_TUNER_MODE_LANG1:
951                         ctl  = EN_NICAM_AUTO_MONO2;
952                         mask = 0x3f;
953                         break;
954                 case V4L2_TUNER_MODE_STEREO:
955                         ctl  = EN_NICAM_FORCE_STEREO | EN_DMTRX_LR;
956                         mask = 0x93f;
957                         break;
958                 }
959                 break;
960         case WW_SYSTEM_L_AM:
961                 switch (mode) {
962                 case V4L2_TUNER_MODE_MONO:
963                 case V4L2_TUNER_MODE_LANG1:  /* FIXME */
964                         set_audio_standard_NICAM_L(core, 0);
965                         break;
966                 case V4L2_TUNER_MODE_STEREO:
967                         set_audio_standard_NICAM_L(core, 1);
968                         break;
969                 }
970                 break;
971         case WW_NICAM_I:
972                 switch (mode) {
973                 case V4L2_TUNER_MODE_MONO:
974                 case V4L2_TUNER_MODE_LANG1:
975                         set_audio_standard_PAL_I(core, 0);
976                         break;
977                 case V4L2_TUNER_MODE_STEREO:
978                         set_audio_standard_PAL_I(core, 1);
979                         break;
980                 }
981                 break;
982         case WW_FM:
983                 switch (mode) {
984                 case V4L2_TUNER_MODE_MONO:
985                         ctl  = EN_FMRADIO_FORCE_MONO;
986                         mask = 0x3f;
987                         break;
988                 case V4L2_TUNER_MODE_STEREO:
989                         ctl  = EN_FMRADIO_AUTO_STEREO;
990                         mask = 0x3f;
991                         break;
992                 }
993                 break;
994         }
995
996         if (UNSET != ctl) {
997                 dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x "
998                         "[status=0x%x,ctl=0x%x,vol=0x%x]\n",
999                         mask, ctl, cx_read(AUD_STATUS),
1000                         cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL));
1001                 cx_andor(AUD_CTL, mask, ctl);
1002         }
1003         return;
1004 }
1005
1006 int cx88_audio_thread(void *data)
1007 {
1008         struct cx88_core *core = data;
1009         struct v4l2_tuner t;
1010         u32 mode = 0;
1011
1012         dprintk("cx88: tvaudio thread started\n");
1013         for (;;) {
1014                 msleep_interruptible(1000);
1015                 if (kthread_should_stop())
1016                         break;
1017
1018                 /* just monitor the audio status for now ... */
1019                 memset(&t,0,sizeof(t));
1020                 cx88_get_stereo(core,&t);
1021
1022                 if (UNSET != core->audiomode_manual)
1023                         /* manually set, don't do anything. */
1024                         continue;
1025
1026                 /* monitor signal */
1027                 if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
1028                         mode = V4L2_TUNER_MODE_STEREO;
1029                 else
1030                         mode = V4L2_TUNER_MODE_MONO;
1031                 if (mode == core->audiomode_current)
1032                         continue;
1033
1034                 /* automatically switch to best available mode */
1035                 cx88_set_stereo(core, mode, 0);
1036         }
1037
1038         dprintk("cx88: tvaudio thread exiting\n");
1039         return 0;
1040 }
1041
1042 /* ----------------------------------------------------------- */
1043
1044 EXPORT_SYMBOL(cx88_set_tvaudio);
1045 EXPORT_SYMBOL(cx88_newstation);
1046 EXPORT_SYMBOL(cx88_set_stereo);
1047 EXPORT_SYMBOL(cx88_get_stereo);
1048 EXPORT_SYMBOL(cx88_audio_thread);
1049
1050 /*
1051  * Local variables:
1052  * c-basic-offset: 8
1053  * End:
1054  * 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
1055  */