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 55static unsigned int audio_debug; 56module_param(audio_debug, int, 0644); 57MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]"); 58 59static unsigned int always_analog; 60module_param(always_analog,int,0644); 61MODULE_PARM_DESC(always_analog,"force analog audio out"); 62 63static unsigned int radio_deemphasis; 64module_param(radio_deemphasis,int,0644); 65MODULE_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 73static 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 99struct rlist { 100 u32 reg; 101 u32 val; 102}; 103 104static 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 125static 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 136static 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 171static 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 281static 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 382static 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 648static 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 662static 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 732static 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 755void 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 808void cx88_newstation(struct cx88_core *core) 809{ 810 core->audiomode_manual = UNSET; 811 core->last_change = jiffies; 812} 813 814void 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 882void 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 988int 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: 1035hw_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 1048EXPORT_SYMBOL(cx88_set_tvaudio); 1049EXPORT_SYMBOL(cx88_newstation); 1050EXPORT_SYMBOL(cx88_set_stereo); 1051EXPORT_SYMBOL(cx88_get_stereo); 1052EXPORT_SYMBOL(cx88_audio_thread); 1053