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 char *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 default: 364 dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__); 365 set_audio_registers(core, nicam_bgdki_common); 366 set_audio_registers(core, nicam_default); 367 break; 368 }; 369 370 mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS; 371 set_audio_finish(core, mode); 372} 373 374static void set_audio_standard_A2(struct cx88_core *core, u32 mode) 375{ 376 static const struct rlist a2_bgdk_common[] = { 377 {AUD_ERRLOGPERIOD_R, 0x00000064}, 378 {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, 379 {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, 380 {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, 381 {AUD_PDF_DDS_CNST_BYTE2, 0x06}, 382 {AUD_PDF_DDS_CNST_BYTE1, 0x82}, 383 {AUD_PDF_DDS_CNST_BYTE0, 0x12}, 384 {AUD_QAM_MODE, 0x05}, 385 {AUD_PHACC_FREQ_8MSB, 0x34}, 386 {AUD_PHACC_FREQ_8LSB, 0x4c}, 387 {AUD_RATE_ADJ1, 0x00000100}, 388 {AUD_RATE_ADJ2, 0x00000200}, 389 {AUD_RATE_ADJ3, 0x00000300}, 390 {AUD_RATE_ADJ4, 0x00000400}, 391 {AUD_RATE_ADJ5, 0x00000500}, 392 {AUD_THR_FR, 0x00000000}, 393 {AAGC_HYST, 0x0000001a}, 394 {AUD_PILOT_BQD_1_K0, 0x0000755b}, 395 {AUD_PILOT_BQD_1_K1, 0x00551340}, 396 {AUD_PILOT_BQD_1_K2, 0x006d30be}, 397 {AUD_PILOT_BQD_1_K3, 0xffd394af}, 398 {AUD_PILOT_BQD_1_K4, 0x00400000}, 399 {AUD_PILOT_BQD_2_K0, 0x00040000}, 400 {AUD_PILOT_BQD_2_K1, 0x002a4841}, 401 {AUD_PILOT_BQD_2_K2, 0x00400000}, 402 {AUD_PILOT_BQD_2_K3, 0x00000000}, 403 {AUD_PILOT_BQD_2_K4, 0x00000000}, 404 {AUD_MODE_CHG_TIMER, 0x00000040}, 405 {AUD_AFE_12DB_EN, 0x00000001}, 406 {AUD_CORDIC_SHIFT_0, 0x00000007}, 407 {AUD_CORDIC_SHIFT_1, 0x00000007}, 408 {AUD_DEEMPH0_G0, 0x00000380}, 409 {AUD_DEEMPH1_G0, 0x00000380}, 410 {AUD_DCOC_0_SRC, 0x0000001a}, 411 {AUD_DCOC0_SHIFT, 0x00000000}, 412 {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, 413 {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, 414 {AUD_DCOC_PASS_IN, 0x00000003}, 415 {AUD_IIR3_0_SEL, 0x00000021}, 416 {AUD_DN2_AFC, 0x00000002}, 417 {AUD_DCOC_1_SRC, 0x0000001b}, 418 {AUD_DCOC1_SHIFT, 0x00000000}, 419 {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, 420 {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, 421 {AUD_IIR3_1_SEL, 0x00000023}, 422 {AUD_RDSI_SEL, 0x00000017}, 423 {AUD_RDSI_SHIFT, 0x00000000}, 424 {AUD_RDSQ_SEL, 0x00000017}, 425 {AUD_RDSQ_SHIFT, 0x00000000}, 426 {AUD_PLL_INT, 0x0000001e}, 427 {AUD_PLL_DDS, 0x00000000}, 428 {AUD_PLL_FRAC, 0x0000e542}, 429 {AUD_POLYPH80SCALEFAC, 0x00000001}, 430 {AUD_START_TIMER, 0x00000000}, 431 { /* end of list */ }, 432 }; 433 434 static const struct rlist a2_bg[] = { 435 {AUD_DMD_RA_DDS, 0x002a4f2f}, 436 {AUD_C1_UP_THR, 0x00007000}, 437 {AUD_C1_LO_THR, 0x00005400}, 438 {AUD_C2_UP_THR, 0x00005400}, 439 {AUD_C2_LO_THR, 0x00003000}, 440 { /* end of list */ }, 441 }; 442 443 static const struct rlist a2_dk[] = { 444 {AUD_DMD_RA_DDS, 0x002a4f2f}, 445 {AUD_C1_UP_THR, 0x00007000}, 446 {AUD_C1_LO_THR, 0x00005400}, 447 {AUD_C2_UP_THR, 0x00005400}, 448 {AUD_C2_LO_THR, 0x00003000}, 449 {AUD_DN0_FREQ, 0x00003a1c}, 450 {AUD_DN2_FREQ, 0x0000d2e0}, 451 { /* end of list */ }, 452 }; 453 454 static const struct rlist a1_i[] = { 455 {AUD_ERRLOGPERIOD_R, 0x00000064}, 456 {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, 457 {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, 458 {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, 459 {AUD_PDF_DDS_CNST_BYTE2, 0x06}, 460 {AUD_PDF_DDS_CNST_BYTE1, 0x82}, 461 {AUD_PDF_DDS_CNST_BYTE0, 0x12}, 462 {AUD_QAM_MODE, 0x05}, 463 {AUD_PHACC_FREQ_8MSB, 0x3a}, 464 {AUD_PHACC_FREQ_8LSB, 0x93}, 465 {AUD_DMD_RA_DDS, 0x002a4f2f}, 466 {AUD_PLL_INT, 0x0000001e}, 467 {AUD_PLL_DDS, 0x00000004}, 468 {AUD_PLL_FRAC, 0x0000e542}, 469 {AUD_RATE_ADJ1, 0x00000100}, 470 {AUD_RATE_ADJ2, 0x00000200}, 471 {AUD_RATE_ADJ3, 0x00000300}, 472 {AUD_RATE_ADJ4, 0x00000400}, 473 {AUD_RATE_ADJ5, 0x00000500}, 474 {AUD_THR_FR, 0x00000000}, 475 {AUD_PILOT_BQD_1_K0, 0x0000755b}, 476 {AUD_PILOT_BQD_1_K1, 0x00551340}, 477 {AUD_PILOT_BQD_1_K2, 0x006d30be}, 478 {AUD_PILOT_BQD_1_K3, 0xffd394af}, 479 {AUD_PILOT_BQD_1_K4, 0x00400000}, 480 {AUD_PILOT_BQD_2_K0, 0x00040000}, 481 {AUD_PILOT_BQD_2_K1, 0x002a4841}, 482 {AUD_PILOT_BQD_2_K2, 0x00400000}, 483 {AUD_PILOT_BQD_2_K3, 0x00000000}, 484 {AUD_PILOT_BQD_2_K4, 0x00000000}, 485 {AUD_MODE_CHG_TIMER, 0x00000060}, 486 {AUD_AFE_12DB_EN, 0x00000001}, 487 {AAGC_HYST, 0x0000000a}, 488 {AUD_CORDIC_SHIFT_0, 0x00000007}, 489 {AUD_CORDIC_SHIFT_1, 0x00000007}, 490 {AUD_C1_UP_THR, 0x00007000}, 491 {AUD_C1_LO_THR, 0x00005400}, 492 {AUD_C2_UP_THR, 0x00005400}, 493 {AUD_C2_LO_THR, 0x00003000}, 494 {AUD_DCOC_0_SRC, 0x0000001a}, 495 {AUD_DCOC0_SHIFT, 0x00000000}, 496 {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, 497 {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, 498 {AUD_DCOC_PASS_IN, 0x00000003}, 499 {AUD_IIR3_0_SEL, 0x00000021}, 500 {AUD_DN2_AFC, 0x00000002}, 501 {AUD_DCOC_1_SRC, 0x0000001b}, 502 {AUD_DCOC1_SHIFT, 0x00000000}, 503 {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, 504 {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, 505 {AUD_IIR3_1_SEL, 0x00000023}, 506 {AUD_DN0_FREQ, 0x000035a3}, 507 {AUD_DN2_FREQ, 0x000029c7}, 508 {AUD_CRDC0_SRC_SEL, 0x00000511}, 509 {AUD_IIR1_0_SEL, 0x00000001}, 510 {AUD_IIR1_1_SEL, 0x00000000}, 511 {AUD_IIR3_2_SEL, 0x00000003}, 512 {AUD_IIR3_2_SHIFT, 0x00000000}, 513 {AUD_IIR3_0_SEL, 0x00000002}, 514 {AUD_IIR2_0_SEL, 0x00000021}, 515 {AUD_IIR2_0_SHIFT, 0x00000002}, 516 {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, 517 {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, 518 {AUD_POLYPH80SCALEFAC, 0x00000001}, 519 {AUD_START_TIMER, 0x00000000}, 520 { /* end of list */ }, 521 }; 522 523 static const struct rlist am_l[] = { 524 {AUD_ERRLOGPERIOD_R, 0x00000064}, 525 {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF}, 526 {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F}, 527 {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F}, 528 {AUD_PDF_DDS_CNST_BYTE2, 0x48}, 529 {AUD_PDF_DDS_CNST_BYTE1, 0x3D}, 530 {AUD_QAM_MODE, 0x00}, 531 {AUD_PDF_DDS_CNST_BYTE0, 0xf5}, 532 {AUD_PHACC_FREQ_8MSB, 0x3a}, 533 {AUD_PHACC_FREQ_8LSB, 0x4a}, 534 {AUD_DEEMPHGAIN_R, 0x00006680}, 535 {AUD_DEEMPHNUMER1_R, 0x000353DE}, 536 {AUD_DEEMPHNUMER2_R, 0x000001B1}, 537 {AUD_DEEMPHDENOM1_R, 0x0000F3D0}, 538 {AUD_DEEMPHDENOM2_R, 0x00000000}, 539 {AUD_FM_MODE_ENABLE, 0x00000007}, 540 {AUD_POLYPH80SCALEFAC, 0x00000003}, 541 {AUD_AFE_12DB_EN, 0x00000001}, 542 {AAGC_GAIN, 0x00000000}, 543 {AAGC_HYST, 0x00000018}, 544 {AAGC_DEF, 0x00000020}, 545 {AUD_DN0_FREQ, 0x00000000}, 546 {AUD_POLY0_DDS_CONSTANT, 0x000E4DB2}, 547 {AUD_DCOC_0_SRC, 0x00000021}, 548 {AUD_IIR1_0_SEL, 0x00000000}, 549 {AUD_IIR1_0_SHIFT, 0x00000007}, 550 {AUD_IIR1_1_SEL, 0x00000002}, 551 {AUD_IIR1_1_SHIFT, 0x00000000}, 552 {AUD_DCOC_1_SRC, 0x00000003}, 553 {AUD_DCOC1_SHIFT, 0x00000000}, 554 {AUD_DCOC_PASS_IN, 0x00000000}, 555 {AUD_IIR1_2_SEL, 0x00000023}, 556 {AUD_IIR1_2_SHIFT, 0x00000000}, 557 {AUD_IIR1_3_SEL, 0x00000004}, 558 {AUD_IIR1_3_SHIFT, 0x00000007}, 559 {AUD_IIR1_4_SEL, 0x00000005}, 560 {AUD_IIR1_4_SHIFT, 0x00000007}, 561 {AUD_IIR3_0_SEL, 0x00000007}, 562 {AUD_IIR3_0_SHIFT, 0x00000000}, 563 {AUD_DEEMPH0_SRC_SEL, 0x00000011}, 564 {AUD_DEEMPH0_SHIFT, 0x00000000}, 565 {AUD_DEEMPH0_G0, 0x00007000}, 566 {AUD_DEEMPH0_A0, 0x00000000}, 567 {AUD_DEEMPH0_B0, 0x00000000}, 568 {AUD_DEEMPH0_A1, 0x00000000}, 569 {AUD_DEEMPH0_B1, 0x00000000}, 570 {AUD_DEEMPH1_SRC_SEL, 0x00000011}, 571 {AUD_DEEMPH1_SHIFT, 0x00000000}, 572 {AUD_DEEMPH1_G0, 0x00007000}, 573 {AUD_DEEMPH1_A0, 0x00000000}, 574 {AUD_DEEMPH1_B0, 0x00000000}, 575 {AUD_DEEMPH1_A1, 0x00000000}, 576 {AUD_DEEMPH1_B1, 0x00000000}, 577 {AUD_OUT0_SEL, 0x0000003F}, 578 {AUD_OUT1_SEL, 0x0000003F}, 579 {AUD_DMD_RA_DDS, 0x00F5C285}, 580 {AUD_PLL_INT, 0x0000001E}, 581 {AUD_PLL_DDS, 0x00000000}, 582 {AUD_PLL_FRAC, 0x0000E542}, 583 {AUD_RATE_ADJ1, 0x00000100}, 584 {AUD_RATE_ADJ2, 0x00000200}, 585 {AUD_RATE_ADJ3, 0x00000300}, 586 {AUD_RATE_ADJ4, 0x00000400}, 587 {AUD_RATE_ADJ5, 0x00000500}, 588 {AUD_RATE_THRES_DMD, 0x000000C0}, 589 { /* end of list */ }, 590 }; 591 592 static const struct rlist a2_deemph50[] = { 593 {AUD_DEEMPH0_G0, 0x00000380}, 594 {AUD_DEEMPH1_G0, 0x00000380}, 595 {AUD_DEEMPHGAIN_R, 0x000011e1}, 596 {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, 597 {AUD_DEEMPHNUMER2_R, 0x0003023c}, 598 { /* end of list */ }, 599 }; 600 601 set_audio_start(core, SEL_A2); 602 switch (core->tvaudio) { 603 case WW_BG: 604 dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__); 605 set_audio_registers(core, a2_bgdk_common); 606 set_audio_registers(core, a2_bg); 607 set_audio_registers(core, a2_deemph50); 608 break; 609 case WW_DK: 610 dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__); 611 set_audio_registers(core, a2_bgdk_common); 612 set_audio_registers(core, a2_dk); 613 set_audio_registers(core, a2_deemph50); 614 break; 615 case WW_I: 616 dprintk("%s PAL-I A1 (status: known-good)\n", __func__); 617 set_audio_registers(core, a1_i); 618 set_audio_registers(core, a2_deemph50); 619 break; 620 case WW_L: 621 dprintk("%s AM-L (status: devel)\n", __func__); 622 set_audio_registers(core, am_l); 623 break; 624 default: 625 dprintk("%s Warning: wrong value\n", __func__); 626 return; 627 break; 628 }; 629 630 mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; 631 set_audio_finish(core, mode); 632} 633 634static void set_audio_standard_EIAJ(struct cx88_core *core) 635{ 636 static const struct rlist eiaj[] = { 637 /* TODO: eiaj register settings are not there yet ... */ 638 639 { /* end of list */ }, 640 }; 641 dprintk("%s (status: unknown)\n", __func__); 642 643 set_audio_start(core, SEL_EIAJ); 644 set_audio_registers(core, eiaj); 645 set_audio_finish(core, EN_EIAJ_AUTO_STEREO); 646} 647 648static void set_audio_standard_FM(struct cx88_core *core, 649 enum cx88_deemph_type deemph) 650{ 651 static const struct rlist fm_deemph_50[] = { 652 {AUD_DEEMPH0_G0, 0x0C45}, 653 {AUD_DEEMPH0_A0, 0x6262}, 654 {AUD_DEEMPH0_B0, 0x1C29}, 655 {AUD_DEEMPH0_A1, 0x3FC66}, 656 {AUD_DEEMPH0_B1, 0x399A}, 657 658 {AUD_DEEMPH1_G0, 0x0D80}, 659 {AUD_DEEMPH1_A0, 0x6262}, 660 {AUD_DEEMPH1_B0, 0x1C29}, 661 {AUD_DEEMPH1_A1, 0x3FC66}, 662 {AUD_DEEMPH1_B1, 0x399A}, 663 664 {AUD_POLYPH80SCALEFAC, 0x0003}, 665 { /* end of list */ }, 666 }; 667 static const struct rlist fm_deemph_75[] = { 668 {AUD_DEEMPH0_G0, 0x091B}, 669 {AUD_DEEMPH0_A0, 0x6B68}, 670 {AUD_DEEMPH0_B0, 0x11EC}, 671 {AUD_DEEMPH0_A1, 0x3FC66}, 672 {AUD_DEEMPH0_B1, 0x399A}, 673 674 {AUD_DEEMPH1_G0, 0x0AA0}, 675 {AUD_DEEMPH1_A0, 0x6B68}, 676 {AUD_DEEMPH1_B0, 0x11EC}, 677 {AUD_DEEMPH1_A1, 0x3FC66}, 678 {AUD_DEEMPH1_B1, 0x399A}, 679 680 {AUD_POLYPH80SCALEFAC, 0x0003}, 681 { /* end of list */ }, 682 }; 683 684 /* It is enough to leave default values? */ 685 /* No, it's not! The deemphasis registers are reset to the 75us 686 * values by default. Analyzing the spectrum of the decoded audio 687 * reveals that "no deemphasis" is the same as 75 us, while the 50 us 688 * setting results in less deemphasis. */ 689 static const struct rlist fm_no_deemph[] = { 690 691 {AUD_POLYPH80SCALEFAC, 0x0003}, 692 { /* end of list */ }, 693 }; 694 695 dprintk("%s (status: unknown)\n", __func__); 696 set_audio_start(core, SEL_FMRADIO); 697 698 switch (deemph) { 699 default: 700 case FM_NO_DEEMPH: 701 set_audio_registers(core, fm_no_deemph); 702 break; 703 704 case FM_DEEMPH_50: 705 set_audio_registers(core, fm_deemph_50); 706 break; 707 708 case FM_DEEMPH_75: 709 set_audio_registers(core, fm_deemph_75); 710 break; 711 } 712 713 set_audio_finish(core, EN_FMRADIO_AUTO_STEREO); 714} 715 716/* ----------------------------------------------------------- */ 717 718static int cx88_detect_nicam(struct cx88_core *core) 719{ 720 int i, j = 0; 721 722 dprintk("start nicam autodetect.\n"); 723 724 for (i = 0; i < 6; i++) { 725 /* if bit1=1 then nicam is detected */ 726 j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1); 727 728 if (j == 1) { 729 dprintk("nicam is detected.\n"); 730 return 1; 731 } 732 733 /* wait a little bit for next reading status */ 734 msleep(10); 735 } 736 737 dprintk("nicam is not detected.\n"); 738 return 0; 739} 740 741void cx88_set_tvaudio(struct cx88_core *core) 742{ 743 switch (core->tvaudio) { 744 case WW_BTSC: 745 set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); 746 break; 747 case WW_BG: 748 case WW_DK: 749 case WW_M: 750 case WW_I: 751 case WW_L: 752 /* prepare all dsp registers */ 753 set_audio_standard_A2(core, EN_A2_FORCE_MONO1); 754 755 /* set nicam mode - otherwise 756 AUD_NICAM_STATUS2 contains wrong values */ 757 set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO); 758 if (0 == cx88_detect_nicam(core)) { 759 /* fall back to fm / am mono */ 760 set_audio_standard_A2(core, EN_A2_FORCE_MONO1); 761 core->audiomode_current = V4L2_TUNER_MODE_MONO; 762 core->use_nicam = 0; 763 } else { 764 core->use_nicam = 1; 765 } 766 break; 767 case WW_EIAJ: 768 set_audio_standard_EIAJ(core); 769 break; 770 case WW_FM: 771 set_audio_standard_FM(core, radio_deemphasis); 772 break; 773 case WW_I2SADC: 774 set_audio_start(core, 0x01); 775 /* Slave/Philips/Autobaud */ 776 cx_write(AUD_I2SINPUTCNTL, 0); 777 /* Switch to "I2S ADC mode" */ 778 cx_write(AUD_I2SCNTL, 0x1); 779 set_audio_finish(core, EN_I2SIN_ENABLE); 780 break; 781 case WW_NONE: 782 default: 783 printk("%s/0: unknown tv audio mode [%d]\n", 784 core->name, core->tvaudio); 785 break; 786 } 787 return; 788} 789 790void cx88_newstation(struct cx88_core *core) 791{ 792 core->audiomode_manual = UNSET; 793 core->last_change = jiffies; 794} 795 796void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) 797{ 798 static char *m[] = { "stereo", "dual mono", "mono", "sap" }; 799 static char *p[] = { "no pilot", "pilot c1", "pilot c2", "?" }; 800 u32 reg, mode, pilot; 801 802 reg = cx_read(AUD_STATUS); 803 mode = reg & 0x03; 804 pilot = (reg >> 2) & 0x03; 805 806 if (core->astat != reg) 807 dprintk("AUD_STATUS: 0x%x [%s/%s] ctl=%s\n", 808 reg, m[mode], p[pilot], 809 aud_ctl_names[cx_read(AUD_CTL) & 63]); 810 core->astat = reg; 811 812 t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP | 813 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; 814 t->rxsubchans = UNSET; 815 t->audmode = V4L2_TUNER_MODE_MONO; 816 817 switch (mode) { 818 case 0: 819 t->audmode = V4L2_TUNER_MODE_STEREO; 820 break; 821 case 1: 822 t->audmode = V4L2_TUNER_MODE_LANG2; 823 break; 824 case 2: 825 t->audmode = V4L2_TUNER_MODE_MONO; 826 break; 827 case 3: 828 t->audmode = V4L2_TUNER_MODE_SAP; 829 break; 830 } 831 832 switch (core->tvaudio) { 833 case WW_BTSC: 834 case WW_BG: 835 case WW_DK: 836 case WW_M: 837 case WW_EIAJ: 838 if (!core->use_nicam) { 839 t->rxsubchans = cx88_dsp_detect_stereo_sap(core); 840 break; 841 } 842 break; 843 default: 844 /* nothing */ 845 break; 846 } 847 848 /* If software stereo detection is not supported... */ 849 if (UNSET == t->rxsubchans) { 850 t->rxsubchans = V4L2_TUNER_SUB_MONO; 851 /* If the hardware itself detected stereo, also return 852 stereo as an available subchannel */ 853 if (V4L2_TUNER_MODE_STEREO == t->audmode) 854 t->rxsubchans |= V4L2_TUNER_SUB_STEREO; 855 } 856 return; 857} 858 859void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) 860{ 861 u32 ctl = UNSET; 862 u32 mask = UNSET; 863 864 if (manual) { 865 core->audiomode_manual = mode; 866 } else { 867 if (UNSET != core->audiomode_manual) 868 return; 869 } 870 core->audiomode_current = mode; 871 872 switch (core->tvaudio) { 873 case WW_BTSC: 874 switch (mode) { 875 case V4L2_TUNER_MODE_MONO: 876 set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO); 877 break; 878 case V4L2_TUNER_MODE_LANG1: 879 set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); 880 break; 881 case V4L2_TUNER_MODE_LANG2: 882 set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP); 883 break; 884 case V4L2_TUNER_MODE_STEREO: 885 case V4L2_TUNER_MODE_LANG1_LANG2: 886 set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO); 887 break; 888 } 889 break; 890 case WW_BG: 891 case WW_DK: 892 case WW_M: 893 case WW_I: 894 case WW_L: 895 if (1 == core->use_nicam) { 896 switch (mode) { 897 case V4L2_TUNER_MODE_MONO: 898 case V4L2_TUNER_MODE_LANG1: 899 set_audio_standard_NICAM(core, 900 EN_NICAM_FORCE_MONO1); 901 break; 902 case V4L2_TUNER_MODE_LANG2: 903 set_audio_standard_NICAM(core, 904 EN_NICAM_FORCE_MONO2); 905 break; 906 case V4L2_TUNER_MODE_STEREO: 907 case V4L2_TUNER_MODE_LANG1_LANG2: 908 set_audio_standard_NICAM(core, 909 EN_NICAM_FORCE_STEREO); 910 break; 911 } 912 } else { 913 if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) { 914 /* fall back to fm / am mono */ 915 set_audio_standard_A2(core, EN_A2_FORCE_MONO1); 916 } else { 917 /* TODO: Add A2 autodection */ 918 mask = 0x3f; 919 switch (mode) { 920 case V4L2_TUNER_MODE_MONO: 921 case V4L2_TUNER_MODE_LANG1: 922 ctl = EN_A2_FORCE_MONO1; 923 break; 924 case V4L2_TUNER_MODE_LANG2: 925 ctl = EN_A2_FORCE_MONO2; 926 break; 927 case V4L2_TUNER_MODE_STEREO: 928 case V4L2_TUNER_MODE_LANG1_LANG2: 929 ctl = EN_A2_FORCE_STEREO; 930 break; 931 } 932 } 933 } 934 break; 935 case WW_FM: 936 switch (mode) { 937 case V4L2_TUNER_MODE_MONO: 938 ctl = EN_FMRADIO_FORCE_MONO; 939 mask = 0x3f; 940 break; 941 case V4L2_TUNER_MODE_STEREO: 942 ctl = EN_FMRADIO_AUTO_STEREO; 943 mask = 0x3f; 944 break; 945 } 946 break; 947 case WW_I2SADC: 948 /* DO NOTHING */ 949 break; 950 } 951 952 if (UNSET != ctl) { 953 dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x " 954 "[status=0x%x,ctl=0x%x,vol=0x%x]\n", 955 mask, ctl, cx_read(AUD_STATUS), 956 cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); 957 cx_andor(AUD_CTL, mask, ctl); 958 } 959 return; 960} 961 962int cx88_audio_thread(void *data) 963{ 964 struct cx88_core *core = data; 965 struct v4l2_tuner t; 966 u32 mode = 0; 967 968 dprintk("cx88: tvaudio thread started\n"); 969 set_freezable(); 970 for (;;) { 971 msleep_interruptible(1000); 972 if (kthread_should_stop()) 973 break; 974 try_to_freeze(); 975 976 switch (core->tvaudio) { 977 case WW_BG: 978 case WW_DK: 979 case WW_M: 980 case WW_I: 981 case WW_L: 982 if (core->use_nicam) 983 goto hw_autodetect; 984 985 /* just monitor the audio status for now ... */ 986 memset(&t, 0, sizeof(t)); 987 cx88_get_stereo(core, &t); 988 989 if (UNSET != core->audiomode_manual) 990 /* manually set, don't do anything. */ 991 continue; 992 993 /* monitor signal and set stereo if available */ 994 if (t.rxsubchans & V4L2_TUNER_SUB_STEREO) 995 mode = V4L2_TUNER_MODE_STEREO; 996 else 997 mode = V4L2_TUNER_MODE_MONO; 998 if (mode == core->audiomode_current) 999 continue; 1000 /* automatically switch to best available mode */ 1001 cx88_set_stereo(core, mode, 0); 1002 break; 1003 default: 1004hw_autodetect: 1005 /* stereo autodetection is supported by hardware so 1006 we don't need to do it manually. Do nothing. */ 1007 break; 1008 } 1009 } 1010 1011 dprintk("cx88: tvaudio thread exiting\n"); 1012 return 0; 1013} 1014 1015/* ----------------------------------------------------------- */ 1016 1017EXPORT_SYMBOL(cx88_set_tvaudio); 1018EXPORT_SYMBOL(cx88_newstation); 1019EXPORT_SYMBOL(cx88_set_stereo); 1020EXPORT_SYMBOL(cx88_get_stereo); 1021EXPORT_SYMBOL(cx88_audio_thread); 1022 1023/* 1024 * Local variables: 1025 * c-basic-offset: 8 1026 * End: 1027 * 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 1028 */ 1029