diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 11:13:30 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 15:36:22 -0400 |
commit | b285192a43f0432d82c2c10974204e78af0da596 (patch) | |
tree | 618aa87e760c9c949eca9e4df6ae0eeffa11dcfc /drivers/media/pci/cx88/cx88-tvaudio.c | |
parent | 68de959f773a1d49096835c411390bceff5d1549 (diff) |
[media] rename most media/video pci drivers to media/pci
Rename all PCI drivers with their own directory under
drivers/media/video into drivers/media/pci and update the
building system.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/pci/cx88/cx88-tvaudio.c')
-rw-r--r-- | drivers/media/pci/cx88/cx88-tvaudio.c | 1059 |
1 files changed, 1059 insertions, 0 deletions
diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c new file mode 100644 index 000000000000..770ec05b5e9b --- /dev/null +++ b/drivers/media/pci/cx88/cx88-tvaudio.c | |||
@@ -0,0 +1,1059 @@ | |||
1 | /* | ||
2 | |||
3 | cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver | ||
4 | |||
5 | (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version] | ||
6 | (c) 2002 Yurij Sysoev <yurij@naturesoft.net> | ||
7 | (c) 2003 Gerd Knorr <kraxel@bytesex.org> | ||
8 | |||
9 | ----------------------------------------------------------------------- | ||
10 | |||
11 | Lot of voodoo here. Even the data sheet doesn't help to | ||
12 | understand what is going on here, the documentation for the audio | ||
13 | part of the cx2388x chip is *very* bad. | ||
14 | |||
15 | Some of this comes from party done linux driver sources I got from | ||
16 | [undocumented]. | ||
17 | |||
18 | Some comes from the dscaler sources, one of the dscaler driver guy works | ||
19 | for Conexant ... | ||
20 | |||
21 | ----------------------------------------------------------------------- | ||
22 | |||
23 | This program is free software; you can redistribute it and/or modify | ||
24 | it under the terms of the GNU General Public License as published by | ||
25 | the Free Software Foundation; either version 2 of the License, or | ||
26 | (at your option) any later version. | ||
27 | |||
28 | This program is distributed in the hope that it will be useful, | ||
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
31 | GNU General Public License for more details. | ||
32 | |||
33 | You should have received a copy of the GNU General Public License | ||
34 | along with this program; if not, write to the Free Software | ||
35 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
36 | */ | ||
37 | |||
38 | #include <linux/module.h> | ||
39 | #include <linux/errno.h> | ||
40 | #include <linux/freezer.h> | ||
41 | #include <linux/kernel.h> | ||
42 | #include <linux/mm.h> | ||
43 | #include <linux/poll.h> | ||
44 | #include <linux/signal.h> | ||
45 | #include <linux/ioport.h> | ||
46 | #include <linux/types.h> | ||
47 | #include <linux/interrupt.h> | ||
48 | #include <linux/vmalloc.h> | ||
49 | #include <linux/init.h> | ||
50 | #include <linux/delay.h> | ||
51 | #include <linux/kthread.h> | ||
52 | |||
53 | #include "cx88.h" | ||
54 | |||
55 | static unsigned int audio_debug; | ||
56 | module_param(audio_debug, int, 0644); | ||
57 | MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]"); | ||
58 | |||
59 | static unsigned int always_analog; | ||
60 | module_param(always_analog,int,0644); | ||
61 | MODULE_PARM_DESC(always_analog,"force analog audio out"); | ||
62 | |||
63 | static unsigned int radio_deemphasis; | ||
64 | module_param(radio_deemphasis,int,0644); | ||
65 | MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, " | ||
66 | "0=None, 1=50us (elsewhere), 2=75us (USA)"); | ||
67 | |||
68 | #define dprintk(fmt, arg...) if (audio_debug) \ | ||
69 | printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) | ||
70 | |||
71 | /* ----------------------------------------------------------- */ | ||
72 | |||
73 | static const char * const aud_ctl_names[64] = { | ||
74 | [EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO", | ||
75 | [EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO", | ||
76 | [EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP", | ||
77 | [EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO", | ||
78 | [EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP", | ||
79 | [EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1", | ||
80 | [EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2", | ||
81 | [EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO", | ||
82 | [EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2", | ||
83 | [EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO", | ||
84 | [EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1", | ||
85 | [EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2", | ||
86 | [EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO", | ||
87 | [EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2", | ||
88 | [EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO", | ||
89 | [EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1", | ||
90 | [EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2", | ||
91 | [EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO", | ||
92 | [EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2", | ||
93 | [EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO", | ||
94 | [EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO", | ||
95 | [EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO", | ||
96 | [EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO", | ||
97 | }; | ||
98 | |||
99 | struct rlist { | ||
100 | u32 reg; | ||
101 | u32 val; | ||
102 | }; | ||
103 | |||
104 | static void set_audio_registers(struct cx88_core *core, const struct rlist *l) | ||
105 | { | ||
106 | int i; | ||
107 | |||
108 | for (i = 0; l[i].reg; i++) { | ||
109 | switch (l[i].reg) { | ||
110 | case AUD_PDF_DDS_CNST_BYTE2: | ||
111 | case AUD_PDF_DDS_CNST_BYTE1: | ||
112 | case AUD_PDF_DDS_CNST_BYTE0: | ||
113 | case AUD_QAM_MODE: | ||
114 | case AUD_PHACC_FREQ_8MSB: | ||
115 | case AUD_PHACC_FREQ_8LSB: | ||
116 | cx_writeb(l[i].reg, l[i].val); | ||
117 | break; | ||
118 | default: | ||
119 | cx_write(l[i].reg, l[i].val); | ||
120 | break; | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | |||
125 | static void set_audio_start(struct cx88_core *core, u32 mode) | ||
126 | { | ||
127 | /* mute */ | ||
128 | cx_write(AUD_VOL_CTL, (1 << 6)); | ||
129 | |||
130 | /* start programming */ | ||
131 | cx_write(AUD_INIT, mode); | ||
132 | cx_write(AUD_INIT_LD, 0x0001); | ||
133 | cx_write(AUD_SOFT_RESET, 0x0001); | ||
134 | } | ||
135 | |||
136 | static void set_audio_finish(struct cx88_core *core, u32 ctl) | ||
137 | { | ||
138 | u32 volume; | ||
139 | |||
140 | /* restart dma; This avoids buzz in NICAM and is good in others */ | ||
141 | cx88_stop_audio_dma(core); | ||
142 | cx_write(AUD_RATE_THRES_DMD, 0x000000C0); | ||
143 | cx88_start_audio_dma(core); | ||
144 | |||
145 | if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { | ||
146 | cx_write(AUD_I2SINPUTCNTL, 4); | ||
147 | cx_write(AUD_BAUDRATE, 1); | ||
148 | /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ | ||
149 | cx_set(AUD_CTL, EN_I2SOUT_ENABLE); | ||
150 | cx_write(AUD_I2SOUTPUTCNTL, 1); | ||
151 | cx_write(AUD_I2SCNTL, 0); | ||
152 | /* cx_write(AUD_APB_IN_RATE_ADJ, 0); */ | ||
153 | } | ||
154 | if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) { | ||
155 | ctl |= EN_DAC_ENABLE; | ||
156 | cx_write(AUD_CTL, ctl); | ||
157 | } | ||
158 | |||
159 | /* finish programming */ | ||
160 | cx_write(AUD_SOFT_RESET, 0x0000); | ||
161 | |||
162 | /* unmute */ | ||
163 | volume = cx_sread(SHADOW_AUD_VOL_CTL); | ||
164 | cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume); | ||
165 | |||
166 | core->last_change = jiffies; | ||
167 | } | ||
168 | |||
169 | /* ----------------------------------------------------------- */ | ||
170 | |||
171 | static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, | ||
172 | u32 mode) | ||
173 | { | ||
174 | static const struct rlist btsc[] = { | ||
175 | {AUD_AFE_12DB_EN, 0x00000001}, | ||
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_AFE_12DB_EN, 0x00000001}, | ||
213 | {AUD_DBX_IN_GAIN, 0x00007200}, | ||
214 | {AUD_DBX_WBE_GAIN, 0x00006200}, | ||
215 | {AUD_DBX_SE_GAIN, 0x00006200}, | ||
216 | {AUD_IIR1_1_SEL, 0x00000000}, | ||
217 | {AUD_IIR1_3_SEL, 0x00000001}, | ||
218 | {AUD_DN1_SRC_SEL, 0x00000007}, | ||
219 | {AUD_IIR1_4_SHIFT, 0x00000006}, | ||
220 | {AUD_IIR2_1_SHIFT, 0x00000000}, | ||
221 | {AUD_IIR2_2_SHIFT, 0x00000000}, | ||
222 | {AUD_IIR3_0_SHIFT, 0x00000000}, | ||
223 | {AUD_IIR3_1_SHIFT, 0x00000000}, | ||
224 | {AUD_IIR3_0_SEL, 0x0000000d}, | ||
225 | {AUD_IIR3_1_SEL, 0x0000000e}, | ||
226 | {AUD_DEEMPH1_SRC_SEL, 0x00000014}, | ||
227 | {AUD_DEEMPH1_SHIFT, 0x00000000}, | ||
228 | {AUD_DEEMPH1_G0, 0x00004000}, | ||
229 | {AUD_DEEMPH1_A0, 0x00000000}, | ||
230 | {AUD_DEEMPH1_B0, 0x00000000}, | ||
231 | {AUD_DEEMPH1_A1, 0x00000000}, | ||
232 | {AUD_DEEMPH1_B1, 0x00000000}, | ||
233 | {AUD_OUT0_SEL, 0x0000003f}, | ||
234 | {AUD_OUT1_SEL, 0x0000003f}, | ||
235 | {AUD_DN1_AFC, 0x00000002}, | ||
236 | {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, | ||
237 | {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, | ||
238 | {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, | ||
239 | {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, | ||
240 | {AUD_IIR1_0_SEL, 0x0000001d}, | ||
241 | {AUD_IIR1_2_SEL, 0x0000001e}, | ||
242 | {AUD_IIR2_1_SEL, 0x00000002}, | ||
243 | {AUD_IIR2_2_SEL, 0x00000004}, | ||
244 | {AUD_IIR3_2_SEL, 0x0000000f}, | ||
245 | {AUD_DCOC2_SHIFT, 0x00000001}, | ||
246 | {AUD_IIR3_2_SHIFT, 0x00000001}, | ||
247 | {AUD_DEEMPH0_SRC_SEL, 0x00000014}, | ||
248 | {AUD_CORDIC_SHIFT_1, 0x00000006}, | ||
249 | {AUD_POLY0_DDS_CONSTANT, 0x000e4db2}, | ||
250 | {AUD_DMD_RA_DDS, 0x00f696e6}, | ||
251 | {AUD_IIR2_3_SEL, 0x00000025}, | ||
252 | {AUD_IIR1_4_SEL, 0x00000021}, | ||
253 | {AUD_DN1_FREQ, 0x0000c965}, | ||
254 | {AUD_DCOC_PASS_IN, 0x00000003}, | ||
255 | {AUD_DCOC_0_SRC, 0x0000001a}, | ||
256 | {AUD_DCOC_1_SRC, 0x0000001b}, | ||
257 | {AUD_DCOC1_SHIFT, 0x00000000}, | ||
258 | {AUD_RDSI_SEL, 0x00000009}, | ||
259 | {AUD_RDSQ_SEL, 0x00000009}, | ||
260 | {AUD_RDSI_SHIFT, 0x00000000}, | ||
261 | {AUD_RDSQ_SHIFT, 0x00000000}, | ||
262 | {AUD_POLYPH80SCALEFAC, 0x00000003}, | ||
263 | { /* end of list */ }, | ||
264 | }; | ||
265 | |||
266 | mode |= EN_FMRADIO_EN_RDS; | ||
267 | |||
268 | if (sap) { | ||
269 | dprintk("%s SAP (status: unknown)\n", __func__); | ||
270 | set_audio_start(core, SEL_SAP); | ||
271 | set_audio_registers(core, btsc_sap); | ||
272 | set_audio_finish(core, mode); | ||
273 | } else { | ||
274 | dprintk("%s (status: known-good)\n", __func__); | ||
275 | set_audio_start(core, SEL_BTSC); | ||
276 | set_audio_registers(core, btsc); | ||
277 | set_audio_finish(core, mode); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) | ||
282 | { | ||
283 | static const struct rlist nicam_l[] = { | ||
284 | {AUD_AFE_12DB_EN, 0x00000001}, | ||
285 | {AUD_RATE_ADJ1, 0x00000060}, | ||
286 | {AUD_RATE_ADJ2, 0x000000F9}, | ||
287 | {AUD_RATE_ADJ3, 0x000001CC}, | ||
288 | {AUD_RATE_ADJ4, 0x000002B3}, | ||
289 | {AUD_RATE_ADJ5, 0x00000726}, | ||
290 | {AUD_DEEMPHDENOM1_R, 0x0000F3D0}, | ||
291 | {AUD_DEEMPHDENOM2_R, 0x00000000}, | ||
292 | {AUD_ERRLOGPERIOD_R, 0x00000064}, | ||
293 | {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF}, | ||
294 | {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F}, | ||
295 | {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F}, | ||
296 | {AUD_POLYPH80SCALEFAC, 0x00000003}, | ||
297 | {AUD_DMD_RA_DDS, 0x00C00000}, | ||
298 | {AUD_PLL_INT, 0x0000001E}, | ||
299 | {AUD_PLL_DDS, 0x00000000}, | ||
300 | {AUD_PLL_FRAC, 0x0000E542}, | ||
301 | {AUD_START_TIMER, 0x00000000}, | ||
302 | {AUD_DEEMPHNUMER1_R, 0x000353DE}, | ||
303 | {AUD_DEEMPHNUMER2_R, 0x000001B1}, | ||
304 | {AUD_PDF_DDS_CNST_BYTE2, 0x06}, | ||
305 | {AUD_PDF_DDS_CNST_BYTE1, 0x82}, | ||
306 | {AUD_PDF_DDS_CNST_BYTE0, 0x12}, | ||
307 | {AUD_QAM_MODE, 0x05}, | ||
308 | {AUD_PHACC_FREQ_8MSB, 0x34}, | ||
309 | {AUD_PHACC_FREQ_8LSB, 0x4C}, | ||
310 | {AUD_DEEMPHGAIN_R, 0x00006680}, | ||
311 | {AUD_RATE_THRES_DMD, 0x000000C0}, | ||
312 | { /* end of list */ }, | ||
313 | }; | ||
314 | |||
315 | static const struct rlist nicam_bgdki_common[] = { | ||
316 | {AUD_AFE_12DB_EN, 0x00000001}, | ||
317 | {AUD_RATE_ADJ1, 0x00000010}, | ||
318 | {AUD_RATE_ADJ2, 0x00000040}, | ||
319 | {AUD_RATE_ADJ3, 0x00000100}, | ||
320 | {AUD_RATE_ADJ4, 0x00000400}, | ||
321 | {AUD_RATE_ADJ5, 0x00001000}, | ||
322 | {AUD_ERRLOGPERIOD_R, 0x00000fff}, | ||
323 | {AUD_ERRINTRPTTHSHLD1_R, 0x000003ff}, | ||
324 | {AUD_ERRINTRPTTHSHLD2_R, 0x000000ff}, | ||
325 | {AUD_ERRINTRPTTHSHLD3_R, 0x0000003f}, | ||
326 | {AUD_POLYPH80SCALEFAC, 0x00000003}, | ||
327 | {AUD_DEEMPHGAIN_R, 0x000023c2}, | ||
328 | {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, | ||
329 | {AUD_DEEMPHNUMER2_R, 0x0003023e}, | ||
330 | {AUD_DEEMPHDENOM1_R, 0x0000f3d0}, | ||
331 | {AUD_DEEMPHDENOM2_R, 0x00000000}, | ||
332 | {AUD_PDF_DDS_CNST_BYTE2, 0x06}, | ||
333 | {AUD_PDF_DDS_CNST_BYTE1, 0x82}, | ||
334 | {AUD_QAM_MODE, 0x05}, | ||
335 | { /* end of list */ }, | ||
336 | }; | ||
337 | |||
338 | static const struct rlist nicam_i[] = { | ||
339 | {AUD_PDF_DDS_CNST_BYTE0, 0x12}, | ||
340 | {AUD_PHACC_FREQ_8MSB, 0x3a}, | ||
341 | {AUD_PHACC_FREQ_8LSB, 0x93}, | ||
342 | { /* end of list */ }, | ||
343 | }; | ||
344 | |||
345 | static const struct rlist nicam_default[] = { | ||
346 | {AUD_PDF_DDS_CNST_BYTE0, 0x16}, | ||
347 | {AUD_PHACC_FREQ_8MSB, 0x34}, | ||
348 | {AUD_PHACC_FREQ_8LSB, 0x4c}, | ||
349 | { /* end of list */ }, | ||
350 | }; | ||
351 | |||
352 | set_audio_start(core,SEL_NICAM); | ||
353 | switch (core->tvaudio) { | ||
354 | case WW_L: | ||
355 | dprintk("%s SECAM-L NICAM (status: devel)\n", __func__); | ||
356 | set_audio_registers(core, nicam_l); | ||
357 | break; | ||
358 | case WW_I: | ||
359 | dprintk("%s PAL-I NICAM (status: known-good)\n", __func__); | ||
360 | set_audio_registers(core, nicam_bgdki_common); | ||
361 | set_audio_registers(core, nicam_i); | ||
362 | break; | ||
363 | case WW_NONE: | ||
364 | case WW_BTSC: | ||
365 | case WW_BG: | ||
366 | case WW_DK: | ||
367 | case WW_EIAJ: | ||
368 | case WW_I2SPT: | ||
369 | case WW_FM: | ||
370 | case WW_I2SADC: | ||
371 | case WW_M: | ||
372 | dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__); | ||
373 | set_audio_registers(core, nicam_bgdki_common); | ||
374 | set_audio_registers(core, nicam_default); | ||
375 | break; | ||
376 | }; | ||
377 | |||
378 | mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS; | ||
379 | set_audio_finish(core, mode); | ||
380 | } | ||
381 | |||
382 | static void set_audio_standard_A2(struct cx88_core *core, u32 mode) | ||
383 | { | ||
384 | static const struct rlist a2_bgdk_common[] = { | ||
385 | {AUD_ERRLOGPERIOD_R, 0x00000064}, | ||
386 | {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, | ||
387 | {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, | ||
388 | {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, | ||
389 | {AUD_PDF_DDS_CNST_BYTE2, 0x06}, | ||
390 | {AUD_PDF_DDS_CNST_BYTE1, 0x82}, | ||
391 | {AUD_PDF_DDS_CNST_BYTE0, 0x12}, | ||
392 | {AUD_QAM_MODE, 0x05}, | ||
393 | {AUD_PHACC_FREQ_8MSB, 0x34}, | ||
394 | {AUD_PHACC_FREQ_8LSB, 0x4c}, | ||
395 | {AUD_RATE_ADJ1, 0x00000100}, | ||
396 | {AUD_RATE_ADJ2, 0x00000200}, | ||
397 | {AUD_RATE_ADJ3, 0x00000300}, | ||
398 | {AUD_RATE_ADJ4, 0x00000400}, | ||
399 | {AUD_RATE_ADJ5, 0x00000500}, | ||
400 | {AUD_THR_FR, 0x00000000}, | ||
401 | {AAGC_HYST, 0x0000001a}, | ||
402 | {AUD_PILOT_BQD_1_K0, 0x0000755b}, | ||
403 | {AUD_PILOT_BQD_1_K1, 0x00551340}, | ||
404 | {AUD_PILOT_BQD_1_K2, 0x006d30be}, | ||
405 | {AUD_PILOT_BQD_1_K3, 0xffd394af}, | ||
406 | {AUD_PILOT_BQD_1_K4, 0x00400000}, | ||
407 | {AUD_PILOT_BQD_2_K0, 0x00040000}, | ||
408 | {AUD_PILOT_BQD_2_K1, 0x002a4841}, | ||
409 | {AUD_PILOT_BQD_2_K2, 0x00400000}, | ||
410 | {AUD_PILOT_BQD_2_K3, 0x00000000}, | ||
411 | {AUD_PILOT_BQD_2_K4, 0x00000000}, | ||
412 | {AUD_MODE_CHG_TIMER, 0x00000040}, | ||
413 | {AUD_AFE_12DB_EN, 0x00000001}, | ||
414 | {AUD_CORDIC_SHIFT_0, 0x00000007}, | ||
415 | {AUD_CORDIC_SHIFT_1, 0x00000007}, | ||
416 | {AUD_DEEMPH0_G0, 0x00000380}, | ||
417 | {AUD_DEEMPH1_G0, 0x00000380}, | ||
418 | {AUD_DCOC_0_SRC, 0x0000001a}, | ||
419 | {AUD_DCOC0_SHIFT, 0x00000000}, | ||
420 | {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, | ||
421 | {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, | ||
422 | {AUD_DCOC_PASS_IN, 0x00000003}, | ||
423 | {AUD_IIR3_0_SEL, 0x00000021}, | ||
424 | {AUD_DN2_AFC, 0x00000002}, | ||
425 | {AUD_DCOC_1_SRC, 0x0000001b}, | ||
426 | {AUD_DCOC1_SHIFT, 0x00000000}, | ||
427 | {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, | ||
428 | {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, | ||
429 | {AUD_IIR3_1_SEL, 0x00000023}, | ||
430 | {AUD_RDSI_SEL, 0x00000017}, | ||
431 | {AUD_RDSI_SHIFT, 0x00000000}, | ||
432 | {AUD_RDSQ_SEL, 0x00000017}, | ||
433 | {AUD_RDSQ_SHIFT, 0x00000000}, | ||
434 | {AUD_PLL_INT, 0x0000001e}, | ||
435 | {AUD_PLL_DDS, 0x00000000}, | ||
436 | {AUD_PLL_FRAC, 0x0000e542}, | ||
437 | {AUD_POLYPH80SCALEFAC, 0x00000001}, | ||
438 | {AUD_START_TIMER, 0x00000000}, | ||
439 | { /* end of list */ }, | ||
440 | }; | ||
441 | |||
442 | static const struct rlist a2_bg[] = { | ||
443 | {AUD_DMD_RA_DDS, 0x002a4f2f}, | ||
444 | {AUD_C1_UP_THR, 0x00007000}, | ||
445 | {AUD_C1_LO_THR, 0x00005400}, | ||
446 | {AUD_C2_UP_THR, 0x00005400}, | ||
447 | {AUD_C2_LO_THR, 0x00003000}, | ||
448 | { /* end of list */ }, | ||
449 | }; | ||
450 | |||
451 | static const struct rlist a2_dk[] = { | ||
452 | {AUD_DMD_RA_DDS, 0x002a4f2f}, | ||
453 | {AUD_C1_UP_THR, 0x00007000}, | ||
454 | {AUD_C1_LO_THR, 0x00005400}, | ||
455 | {AUD_C2_UP_THR, 0x00005400}, | ||
456 | {AUD_C2_LO_THR, 0x00003000}, | ||
457 | {AUD_DN0_FREQ, 0x00003a1c}, | ||
458 | {AUD_DN2_FREQ, 0x0000d2e0}, | ||
459 | { /* end of list */ }, | ||
460 | }; | ||
461 | |||
462 | static const struct rlist a1_i[] = { | ||
463 | {AUD_ERRLOGPERIOD_R, 0x00000064}, | ||
464 | {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, | ||
465 | {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, | ||
466 | {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, | ||
467 | {AUD_PDF_DDS_CNST_BYTE2, 0x06}, | ||
468 | {AUD_PDF_DDS_CNST_BYTE1, 0x82}, | ||
469 | {AUD_PDF_DDS_CNST_BYTE0, 0x12}, | ||
470 | {AUD_QAM_MODE, 0x05}, | ||
471 | {AUD_PHACC_FREQ_8MSB, 0x3a}, | ||
472 | {AUD_PHACC_FREQ_8LSB, 0x93}, | ||
473 | {AUD_DMD_RA_DDS, 0x002a4f2f}, | ||
474 | {AUD_PLL_INT, 0x0000001e}, | ||
475 | {AUD_PLL_DDS, 0x00000004}, | ||
476 | {AUD_PLL_FRAC, 0x0000e542}, | ||
477 | {AUD_RATE_ADJ1, 0x00000100}, | ||
478 | {AUD_RATE_ADJ2, 0x00000200}, | ||
479 | {AUD_RATE_ADJ3, 0x00000300}, | ||
480 | {AUD_RATE_ADJ4, 0x00000400}, | ||
481 | {AUD_RATE_ADJ5, 0x00000500}, | ||
482 | {AUD_THR_FR, 0x00000000}, | ||
483 | {AUD_PILOT_BQD_1_K0, 0x0000755b}, | ||
484 | {AUD_PILOT_BQD_1_K1, 0x00551340}, | ||
485 | {AUD_PILOT_BQD_1_K2, 0x006d30be}, | ||
486 | {AUD_PILOT_BQD_1_K3, 0xffd394af}, | ||
487 | {AUD_PILOT_BQD_1_K4, 0x00400000}, | ||
488 | {AUD_PILOT_BQD_2_K0, 0x00040000}, | ||
489 | {AUD_PILOT_BQD_2_K1, 0x002a4841}, | ||
490 | {AUD_PILOT_BQD_2_K2, 0x00400000}, | ||
491 | {AUD_PILOT_BQD_2_K3, 0x00000000}, | ||
492 | {AUD_PILOT_BQD_2_K4, 0x00000000}, | ||
493 | {AUD_MODE_CHG_TIMER, 0x00000060}, | ||
494 | {AUD_AFE_12DB_EN, 0x00000001}, | ||
495 | {AAGC_HYST, 0x0000000a}, | ||
496 | {AUD_CORDIC_SHIFT_0, 0x00000007}, | ||
497 | {AUD_CORDIC_SHIFT_1, 0x00000007}, | ||
498 | {AUD_C1_UP_THR, 0x00007000}, | ||
499 | {AUD_C1_LO_THR, 0x00005400}, | ||
500 | {AUD_C2_UP_THR, 0x00005400}, | ||
501 | {AUD_C2_LO_THR, 0x00003000}, | ||
502 | {AUD_DCOC_0_SRC, 0x0000001a}, | ||
503 | {AUD_DCOC0_SHIFT, 0x00000000}, | ||
504 | {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, | ||
505 | {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, | ||
506 | {AUD_DCOC_PASS_IN, 0x00000003}, | ||
507 | {AUD_IIR3_0_SEL, 0x00000021}, | ||
508 | {AUD_DN2_AFC, 0x00000002}, | ||
509 | {AUD_DCOC_1_SRC, 0x0000001b}, | ||
510 | {AUD_DCOC1_SHIFT, 0x00000000}, | ||
511 | {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, | ||
512 | {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, | ||
513 | {AUD_IIR3_1_SEL, 0x00000023}, | ||
514 | {AUD_DN0_FREQ, 0x000035a3}, | ||
515 | {AUD_DN2_FREQ, 0x000029c7}, | ||
516 | {AUD_CRDC0_SRC_SEL, 0x00000511}, | ||
517 | {AUD_IIR1_0_SEL, 0x00000001}, | ||
518 | {AUD_IIR1_1_SEL, 0x00000000}, | ||
519 | {AUD_IIR3_2_SEL, 0x00000003}, | ||
520 | {AUD_IIR3_2_SHIFT, 0x00000000}, | ||
521 | {AUD_IIR3_0_SEL, 0x00000002}, | ||
522 | {AUD_IIR2_0_SEL, 0x00000021}, | ||
523 | {AUD_IIR2_0_SHIFT, 0x00000002}, | ||
524 | {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, | ||
525 | {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, | ||
526 | {AUD_POLYPH80SCALEFAC, 0x00000001}, | ||
527 | {AUD_START_TIMER, 0x00000000}, | ||
528 | { /* end of list */ }, | ||
529 | }; | ||
530 | |||
531 | static const struct rlist am_l[] = { | ||
532 | {AUD_ERRLOGPERIOD_R, 0x00000064}, | ||
533 | {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF}, | ||
534 | {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F}, | ||
535 | {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F}, | ||
536 | {AUD_PDF_DDS_CNST_BYTE2, 0x48}, | ||
537 | {AUD_PDF_DDS_CNST_BYTE1, 0x3D}, | ||
538 | {AUD_QAM_MODE, 0x00}, | ||
539 | {AUD_PDF_DDS_CNST_BYTE0, 0xf5}, | ||
540 | {AUD_PHACC_FREQ_8MSB, 0x3a}, | ||
541 | {AUD_PHACC_FREQ_8LSB, 0x4a}, | ||
542 | {AUD_DEEMPHGAIN_R, 0x00006680}, | ||
543 | {AUD_DEEMPHNUMER1_R, 0x000353DE}, | ||
544 | {AUD_DEEMPHNUMER2_R, 0x000001B1}, | ||
545 | {AUD_DEEMPHDENOM1_R, 0x0000F3D0}, | ||
546 | {AUD_DEEMPHDENOM2_R, 0x00000000}, | ||
547 | {AUD_FM_MODE_ENABLE, 0x00000007}, | ||
548 | {AUD_POLYPH80SCALEFAC, 0x00000003}, | ||
549 | {AUD_AFE_12DB_EN, 0x00000001}, | ||
550 | {AAGC_GAIN, 0x00000000}, | ||
551 | {AAGC_HYST, 0x00000018}, | ||
552 | {AAGC_DEF, 0x00000020}, | ||
553 | {AUD_DN0_FREQ, 0x00000000}, | ||
554 | {AUD_POLY0_DDS_CONSTANT, 0x000E4DB2}, | ||
555 | {AUD_DCOC_0_SRC, 0x00000021}, | ||
556 | {AUD_IIR1_0_SEL, 0x00000000}, | ||
557 | {AUD_IIR1_0_SHIFT, 0x00000007}, | ||
558 | {AUD_IIR1_1_SEL, 0x00000002}, | ||
559 | {AUD_IIR1_1_SHIFT, 0x00000000}, | ||
560 | {AUD_DCOC_1_SRC, 0x00000003}, | ||
561 | {AUD_DCOC1_SHIFT, 0x00000000}, | ||
562 | {AUD_DCOC_PASS_IN, 0x00000000}, | ||
563 | {AUD_IIR1_2_SEL, 0x00000023}, | ||
564 | {AUD_IIR1_2_SHIFT, 0x00000000}, | ||
565 | {AUD_IIR1_3_SEL, 0x00000004}, | ||
566 | {AUD_IIR1_3_SHIFT, 0x00000007}, | ||
567 | {AUD_IIR1_4_SEL, 0x00000005}, | ||
568 | {AUD_IIR1_4_SHIFT, 0x00000007}, | ||
569 | {AUD_IIR3_0_SEL, 0x00000007}, | ||
570 | {AUD_IIR3_0_SHIFT, 0x00000000}, | ||
571 | {AUD_DEEMPH0_SRC_SEL, 0x00000011}, | ||
572 | {AUD_DEEMPH0_SHIFT, 0x00000000}, | ||
573 | {AUD_DEEMPH0_G0, 0x00007000}, | ||
574 | {AUD_DEEMPH0_A0, 0x00000000}, | ||
575 | {AUD_DEEMPH0_B0, 0x00000000}, | ||
576 | {AUD_DEEMPH0_A1, 0x00000000}, | ||
577 | {AUD_DEEMPH0_B1, 0x00000000}, | ||
578 | {AUD_DEEMPH1_SRC_SEL, 0x00000011}, | ||
579 | {AUD_DEEMPH1_SHIFT, 0x00000000}, | ||
580 | {AUD_DEEMPH1_G0, 0x00007000}, | ||
581 | {AUD_DEEMPH1_A0, 0x00000000}, | ||
582 | {AUD_DEEMPH1_B0, 0x00000000}, | ||
583 | {AUD_DEEMPH1_A1, 0x00000000}, | ||
584 | {AUD_DEEMPH1_B1, 0x00000000}, | ||
585 | {AUD_OUT0_SEL, 0x0000003F}, | ||
586 | {AUD_OUT1_SEL, 0x0000003F}, | ||
587 | {AUD_DMD_RA_DDS, 0x00F5C285}, | ||
588 | {AUD_PLL_INT, 0x0000001E}, | ||
589 | {AUD_PLL_DDS, 0x00000000}, | ||
590 | {AUD_PLL_FRAC, 0x0000E542}, | ||
591 | {AUD_RATE_ADJ1, 0x00000100}, | ||
592 | {AUD_RATE_ADJ2, 0x00000200}, | ||
593 | {AUD_RATE_ADJ3, 0x00000300}, | ||
594 | {AUD_RATE_ADJ4, 0x00000400}, | ||
595 | {AUD_RATE_ADJ5, 0x00000500}, | ||
596 | {AUD_RATE_THRES_DMD, 0x000000C0}, | ||
597 | { /* end of list */ }, | ||
598 | }; | ||
599 | |||
600 | static const struct rlist a2_deemph50[] = { | ||
601 | {AUD_DEEMPH0_G0, 0x00000380}, | ||
602 | {AUD_DEEMPH1_G0, 0x00000380}, | ||
603 | {AUD_DEEMPHGAIN_R, 0x000011e1}, | ||
604 | {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, | ||
605 | {AUD_DEEMPHNUMER2_R, 0x0003023c}, | ||
606 | { /* end of list */ }, | ||
607 | }; | ||
608 | |||
609 | set_audio_start(core, SEL_A2); | ||
610 | switch (core->tvaudio) { | ||
611 | case WW_BG: | ||
612 | dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__); | ||
613 | set_audio_registers(core, a2_bgdk_common); | ||
614 | set_audio_registers(core, a2_bg); | ||
615 | set_audio_registers(core, a2_deemph50); | ||
616 | break; | ||
617 | case WW_DK: | ||
618 | dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__); | ||
619 | set_audio_registers(core, a2_bgdk_common); | ||
620 | set_audio_registers(core, a2_dk); | ||
621 | set_audio_registers(core, a2_deemph50); | ||
622 | break; | ||
623 | case WW_I: | ||
624 | dprintk("%s PAL-I A1 (status: known-good)\n", __func__); | ||
625 | set_audio_registers(core, a1_i); | ||
626 | set_audio_registers(core, a2_deemph50); | ||
627 | break; | ||
628 | case WW_L: | ||
629 | dprintk("%s AM-L (status: devel)\n", __func__); | ||
630 | set_audio_registers(core, am_l); | ||
631 | break; | ||
632 | case WW_NONE: | ||
633 | case WW_BTSC: | ||
634 | case WW_EIAJ: | ||
635 | case WW_I2SPT: | ||
636 | case WW_FM: | ||
637 | case WW_I2SADC: | ||
638 | case WW_M: | ||
639 | dprintk("%s Warning: wrong value\n", __func__); | ||
640 | return; | ||
641 | break; | ||
642 | }; | ||
643 | |||
644 | mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; | ||
645 | set_audio_finish(core, mode); | ||
646 | } | ||
647 | |||
648 | static void set_audio_standard_EIAJ(struct cx88_core *core) | ||
649 | { | ||
650 | static const struct rlist eiaj[] = { | ||
651 | /* TODO: eiaj register settings are not there yet ... */ | ||
652 | |||
653 | { /* end of list */ }, | ||
654 | }; | ||
655 | dprintk("%s (status: unknown)\n", __func__); | ||
656 | |||
657 | set_audio_start(core, SEL_EIAJ); | ||
658 | set_audio_registers(core, eiaj); | ||
659 | set_audio_finish(core, EN_EIAJ_AUTO_STEREO); | ||
660 | } | ||
661 | |||
662 | static void set_audio_standard_FM(struct cx88_core *core, | ||
663 | enum cx88_deemph_type deemph) | ||
664 | { | ||
665 | static const struct rlist fm_deemph_50[] = { | ||
666 | {AUD_DEEMPH0_G0, 0x0C45}, | ||
667 | {AUD_DEEMPH0_A0, 0x6262}, | ||
668 | {AUD_DEEMPH0_B0, 0x1C29}, | ||
669 | {AUD_DEEMPH0_A1, 0x3FC66}, | ||
670 | {AUD_DEEMPH0_B1, 0x399A}, | ||
671 | |||
672 | {AUD_DEEMPH1_G0, 0x0D80}, | ||
673 | {AUD_DEEMPH1_A0, 0x6262}, | ||
674 | {AUD_DEEMPH1_B0, 0x1C29}, | ||
675 | {AUD_DEEMPH1_A1, 0x3FC66}, | ||
676 | {AUD_DEEMPH1_B1, 0x399A}, | ||
677 | |||
678 | {AUD_POLYPH80SCALEFAC, 0x0003}, | ||
679 | { /* end of list */ }, | ||
680 | }; | ||
681 | static const struct rlist fm_deemph_75[] = { | ||
682 | {AUD_DEEMPH0_G0, 0x091B}, | ||
683 | {AUD_DEEMPH0_A0, 0x6B68}, | ||
684 | {AUD_DEEMPH0_B0, 0x11EC}, | ||
685 | {AUD_DEEMPH0_A1, 0x3FC66}, | ||
686 | {AUD_DEEMPH0_B1, 0x399A}, | ||
687 | |||
688 | {AUD_DEEMPH1_G0, 0x0AA0}, | ||
689 | {AUD_DEEMPH1_A0, 0x6B68}, | ||
690 | {AUD_DEEMPH1_B0, 0x11EC}, | ||
691 | {AUD_DEEMPH1_A1, 0x3FC66}, | ||
692 | {AUD_DEEMPH1_B1, 0x399A}, | ||
693 | |||
694 | {AUD_POLYPH80SCALEFAC, 0x0003}, | ||
695 | { /* end of list */ }, | ||
696 | }; | ||
697 | |||
698 | /* It is enough to leave default values? */ | ||
699 | /* No, it's not! The deemphasis registers are reset to the 75us | ||
700 | * values by default. Analyzing the spectrum of the decoded audio | ||
701 | * reveals that "no deemphasis" is the same as 75 us, while the 50 us | ||
702 | * setting results in less deemphasis. */ | ||
703 | static const struct rlist fm_no_deemph[] = { | ||
704 | |||
705 | {AUD_POLYPH80SCALEFAC, 0x0003}, | ||
706 | { /* end of list */ }, | ||
707 | }; | ||
708 | |||
709 | dprintk("%s (status: unknown)\n", __func__); | ||
710 | set_audio_start(core, SEL_FMRADIO); | ||
711 | |||
712 | switch (deemph) { | ||
713 | default: | ||
714 | case FM_NO_DEEMPH: | ||
715 | set_audio_registers(core, fm_no_deemph); | ||
716 | break; | ||
717 | |||
718 | case FM_DEEMPH_50: | ||
719 | set_audio_registers(core, fm_deemph_50); | ||
720 | break; | ||
721 | |||
722 | case FM_DEEMPH_75: | ||
723 | set_audio_registers(core, fm_deemph_75); | ||
724 | break; | ||
725 | } | ||
726 | |||
727 | set_audio_finish(core, EN_FMRADIO_AUTO_STEREO); | ||
728 | } | ||
729 | |||
730 | /* ----------------------------------------------------------- */ | ||
731 | |||
732 | static int cx88_detect_nicam(struct cx88_core *core) | ||
733 | { | ||
734 | int i, j = 0; | ||
735 | |||
736 | dprintk("start nicam autodetect.\n"); | ||
737 | |||
738 | for (i = 0; i < 6; i++) { | ||
739 | /* if bit1=1 then nicam is detected */ | ||
740 | j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1); | ||
741 | |||
742 | if (j == 1) { | ||
743 | dprintk("nicam is detected.\n"); | ||
744 | return 1; | ||
745 | } | ||
746 | |||
747 | /* wait a little bit for next reading status */ | ||
748 | msleep(10); | ||
749 | } | ||
750 | |||
751 | dprintk("nicam is not detected.\n"); | ||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | void cx88_set_tvaudio(struct cx88_core *core) | ||
756 | { | ||
757 | switch (core->tvaudio) { | ||
758 | case WW_BTSC: | ||
759 | set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); | ||
760 | break; | ||
761 | case WW_BG: | ||
762 | case WW_DK: | ||
763 | case WW_M: | ||
764 | case WW_I: | ||
765 | case WW_L: | ||
766 | /* prepare all dsp registers */ | ||
767 | set_audio_standard_A2(core, EN_A2_FORCE_MONO1); | ||
768 | |||
769 | /* set nicam mode - otherwise | ||
770 | AUD_NICAM_STATUS2 contains wrong values */ | ||
771 | set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO); | ||
772 | if (0 == cx88_detect_nicam(core)) { | ||
773 | /* fall back to fm / am mono */ | ||
774 | set_audio_standard_A2(core, EN_A2_FORCE_MONO1); | ||
775 | core->audiomode_current = V4L2_TUNER_MODE_MONO; | ||
776 | core->use_nicam = 0; | ||
777 | } else { | ||
778 | core->use_nicam = 1; | ||
779 | } | ||
780 | break; | ||
781 | case WW_EIAJ: | ||
782 | set_audio_standard_EIAJ(core); | ||
783 | break; | ||
784 | case WW_FM: | ||
785 | set_audio_standard_FM(core, radio_deemphasis); | ||
786 | break; | ||
787 | case WW_I2SADC: | ||
788 | set_audio_start(core, 0x01); | ||
789 | /* | ||
790 | * Slave/Philips/Autobaud | ||
791 | * NB on Nova-S bit1 NPhilipsSony appears to be inverted: | ||
792 | * 0= Sony, 1=Philips | ||
793 | */ | ||
794 | cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl); | ||
795 | /* Switch to "I2S ADC mode" */ | ||
796 | cx_write(AUD_I2SCNTL, 0x1); | ||
797 | set_audio_finish(core, EN_I2SIN_ENABLE); | ||
798 | break; | ||
799 | case WW_NONE: | ||
800 | case WW_I2SPT: | ||
801 | printk("%s/0: unknown tv audio mode [%d]\n", | ||
802 | core->name, core->tvaudio); | ||
803 | break; | ||
804 | } | ||
805 | return; | ||
806 | } | ||
807 | |||
808 | void cx88_newstation(struct cx88_core *core) | ||
809 | { | ||
810 | core->audiomode_manual = UNSET; | ||
811 | core->last_change = jiffies; | ||
812 | } | ||
813 | |||
814 | void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) | ||
815 | { | ||
816 | static const char * const m[] = { "stereo", "dual mono", "mono", "sap" }; | ||
817 | static const char * const p[] = { "no pilot", "pilot c1", "pilot c2", "?" }; | ||
818 | u32 reg, mode, pilot; | ||
819 | |||
820 | reg = cx_read(AUD_STATUS); | ||
821 | mode = reg & 0x03; | ||
822 | pilot = (reg >> 2) & 0x03; | ||
823 | |||
824 | if (core->astat != reg) | ||
825 | dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n", | ||
826 | reg, m[mode], p[pilot], | ||
827 | aud_ctl_names[cx_read(AUD_CTL) & 63]); | ||
828 | core->astat = reg; | ||
829 | |||
830 | t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP | | ||
831 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; | ||
832 | t->rxsubchans = UNSET; | ||
833 | t->audmode = V4L2_TUNER_MODE_MONO; | ||
834 | |||
835 | switch (mode) { | ||
836 | case 0: | ||
837 | t->audmode = V4L2_TUNER_MODE_STEREO; | ||
838 | break; | ||
839 | case 1: | ||
840 | t->audmode = V4L2_TUNER_MODE_LANG2; | ||
841 | break; | ||
842 | case 2: | ||
843 | t->audmode = V4L2_TUNER_MODE_MONO; | ||
844 | break; | ||
845 | case 3: | ||
846 | t->audmode = V4L2_TUNER_MODE_SAP; | ||
847 | break; | ||
848 | } | ||
849 | |||
850 | switch (core->tvaudio) { | ||
851 | case WW_BTSC: | ||
852 | case WW_BG: | ||
853 | case WW_DK: | ||
854 | case WW_M: | ||
855 | case WW_EIAJ: | ||
856 | if (!core->use_nicam) { | ||
857 | t->rxsubchans = cx88_dsp_detect_stereo_sap(core); | ||
858 | break; | ||
859 | } | ||
860 | break; | ||
861 | case WW_NONE: | ||
862 | case WW_I: | ||
863 | case WW_L: | ||
864 | case WW_I2SPT: | ||
865 | case WW_FM: | ||
866 | case WW_I2SADC: | ||
867 | /* nothing */ | ||
868 | break; | ||
869 | } | ||
870 | |||
871 | /* If software stereo detection is not supported... */ | ||
872 | if (UNSET == t->rxsubchans) { | ||
873 | t->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
874 | /* If the hardware itself detected stereo, also return | ||
875 | stereo as an available subchannel */ | ||
876 | if (V4L2_TUNER_MODE_STEREO == t->audmode) | ||
877 | t->rxsubchans |= V4L2_TUNER_SUB_STEREO; | ||
878 | } | ||
879 | return; | ||
880 | } | ||
881 | |||
882 | void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) | ||
883 | { | ||
884 | u32 ctl = UNSET; | ||
885 | u32 mask = UNSET; | ||
886 | |||
887 | if (manual) { | ||
888 | core->audiomode_manual = mode; | ||
889 | } else { | ||
890 | if (UNSET != core->audiomode_manual) | ||
891 | return; | ||
892 | } | ||
893 | core->audiomode_current = mode; | ||
894 | |||
895 | switch (core->tvaudio) { | ||
896 | case WW_BTSC: | ||
897 | switch (mode) { | ||
898 | case V4L2_TUNER_MODE_MONO: | ||
899 | set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO); | ||
900 | break; | ||
901 | case V4L2_TUNER_MODE_LANG1: | ||
902 | set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); | ||
903 | break; | ||
904 | case V4L2_TUNER_MODE_LANG2: | ||
905 | set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP); | ||
906 | break; | ||
907 | case V4L2_TUNER_MODE_STEREO: | ||
908 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
909 | set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO); | ||
910 | break; | ||
911 | } | ||
912 | break; | ||
913 | case WW_BG: | ||
914 | case WW_DK: | ||
915 | case WW_M: | ||
916 | case WW_I: | ||
917 | case WW_L: | ||
918 | if (1 == core->use_nicam) { | ||
919 | switch (mode) { | ||
920 | case V4L2_TUNER_MODE_MONO: | ||
921 | case V4L2_TUNER_MODE_LANG1: | ||
922 | set_audio_standard_NICAM(core, | ||
923 | EN_NICAM_FORCE_MONO1); | ||
924 | break; | ||
925 | case V4L2_TUNER_MODE_LANG2: | ||
926 | set_audio_standard_NICAM(core, | ||
927 | EN_NICAM_FORCE_MONO2); | ||
928 | break; | ||
929 | case V4L2_TUNER_MODE_STEREO: | ||
930 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
931 | set_audio_standard_NICAM(core, | ||
932 | EN_NICAM_FORCE_STEREO); | ||
933 | break; | ||
934 | } | ||
935 | } else { | ||
936 | if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) { | ||
937 | /* fall back to fm / am mono */ | ||
938 | set_audio_standard_A2(core, EN_A2_FORCE_MONO1); | ||
939 | } else { | ||
940 | /* TODO: Add A2 autodection */ | ||
941 | mask = 0x3f; | ||
942 | switch (mode) { | ||
943 | case V4L2_TUNER_MODE_MONO: | ||
944 | case V4L2_TUNER_MODE_LANG1: | ||
945 | ctl = EN_A2_FORCE_MONO1; | ||
946 | break; | ||
947 | case V4L2_TUNER_MODE_LANG2: | ||
948 | ctl = EN_A2_FORCE_MONO2; | ||
949 | break; | ||
950 | case V4L2_TUNER_MODE_STEREO: | ||
951 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
952 | ctl = EN_A2_FORCE_STEREO; | ||
953 | break; | ||
954 | } | ||
955 | } | ||
956 | } | ||
957 | break; | ||
958 | case WW_FM: | ||
959 | switch (mode) { | ||
960 | case V4L2_TUNER_MODE_MONO: | ||
961 | ctl = EN_FMRADIO_FORCE_MONO; | ||
962 | mask = 0x3f; | ||
963 | break; | ||
964 | case V4L2_TUNER_MODE_STEREO: | ||
965 | ctl = EN_FMRADIO_AUTO_STEREO; | ||
966 | mask = 0x3f; | ||
967 | break; | ||
968 | } | ||
969 | break; | ||
970 | case WW_I2SADC: | ||
971 | case WW_NONE: | ||
972 | case WW_EIAJ: | ||
973 | case WW_I2SPT: | ||
974 | /* DO NOTHING */ | ||
975 | break; | ||
976 | } | ||
977 | |||
978 | if (UNSET != ctl) { | ||
979 | dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x " | ||
980 | "[status=0x%x,ctl=0x%x,vol=0x%x]\n", | ||
981 | mask, ctl, cx_read(AUD_STATUS), | ||
982 | cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); | ||
983 | cx_andor(AUD_CTL, mask, ctl); | ||
984 | } | ||
985 | return; | ||
986 | } | ||
987 | |||
988 | int cx88_audio_thread(void *data) | ||
989 | { | ||
990 | struct cx88_core *core = data; | ||
991 | struct v4l2_tuner t; | ||
992 | u32 mode = 0; | ||
993 | |||
994 | dprintk("cx88: tvaudio thread started\n"); | ||
995 | set_freezable(); | ||
996 | for (;;) { | ||
997 | msleep_interruptible(1000); | ||
998 | if (kthread_should_stop()) | ||
999 | break; | ||
1000 | try_to_freeze(); | ||
1001 | |||
1002 | switch (core->tvaudio) { | ||
1003 | case WW_BG: | ||
1004 | case WW_DK: | ||
1005 | case WW_M: | ||
1006 | case WW_I: | ||
1007 | case WW_L: | ||
1008 | if (core->use_nicam) | ||
1009 | goto hw_autodetect; | ||
1010 | |||
1011 | /* just monitor the audio status for now ... */ | ||
1012 | memset(&t, 0, sizeof(t)); | ||
1013 | cx88_get_stereo(core, &t); | ||
1014 | |||
1015 | if (UNSET != core->audiomode_manual) | ||
1016 | /* manually set, don't do anything. */ | ||
1017 | continue; | ||
1018 | |||
1019 | /* monitor signal and set stereo if available */ | ||
1020 | if (t.rxsubchans & V4L2_TUNER_SUB_STEREO) | ||
1021 | mode = V4L2_TUNER_MODE_STEREO; | ||
1022 | else | ||
1023 | mode = V4L2_TUNER_MODE_MONO; | ||
1024 | if (mode == core->audiomode_current) | ||
1025 | continue; | ||
1026 | /* automatically switch to best available mode */ | ||
1027 | cx88_set_stereo(core, mode, 0); | ||
1028 | break; | ||
1029 | case WW_NONE: | ||
1030 | case WW_BTSC: | ||
1031 | case WW_EIAJ: | ||
1032 | case WW_I2SPT: | ||
1033 | case WW_FM: | ||
1034 | case WW_I2SADC: | ||
1035 | hw_autodetect: | ||
1036 | /* stereo autodetection is supported by hardware so | ||
1037 | we don't need to do it manually. Do nothing. */ | ||
1038 | break; | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | dprintk("cx88: tvaudio thread exiting\n"); | ||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | /* ----------------------------------------------------------- */ | ||
1047 | |||
1048 | EXPORT_SYMBOL(cx88_set_tvaudio); | ||
1049 | EXPORT_SYMBOL(cx88_newstation); | ||
1050 | EXPORT_SYMBOL(cx88_set_stereo); | ||
1051 | EXPORT_SYMBOL(cx88_get_stereo); | ||
1052 | EXPORT_SYMBOL(cx88_audio_thread); | ||
1053 | |||
1054 | /* | ||
1055 | * Local variables: | ||
1056 | * c-basic-offset: 8 | ||
1057 | * End: | ||
1058 | * 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 | ||
1059 | */ | ||