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