1 /* 2 Samsung S5H1409 VSB/QAM demodulator driver 3 4 Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20 */ 21 22 #include <linux/kernel.h> 23 #include <linux/init.h> 24 #include <linux/module.h> 25 #include <linux/string.h> 26 #include <linux/slab.h> 27 #include <linux/delay.h> 28 #include "dvb_frontend.h" 29 #include "s5h1409.h" 30 31 struct s5h1409_state { 32 33 struct i2c_adapter *i2c; 34 35 /* configuration settings */ 36 const struct s5h1409_config *config; 37 38 struct dvb_frontend frontend; 39 40 /* previous uncorrected block counter */ 41 fe_modulation_t current_modulation; 42 43 u32 current_frequency; 44 int if_freq; 45 46 u32 is_qam_locked; 47 48 /* QAM tuning state goes through the following state transitions */ 49 #define QAM_STATE_UNTUNED 0 50 #define QAM_STATE_TUNING_STARTED 1 51 #define QAM_STATE_INTERLEAVE_SET 2 52 #define QAM_STATE_QAM_OPTIMIZED_L1 3 53 #define QAM_STATE_QAM_OPTIMIZED_L2 4 54 #define QAM_STATE_QAM_OPTIMIZED_L3 5 55 u8 qam_state; 56 }; 57 58 static int debug; 59 module_param(debug, int, 0644); 60 MODULE_PARM_DESC(debug, "Enable verbose debug messages"); 61 62 #define dprintk if (debug) printk 63 64 /* Register values to initialise the demod, this will set VSB by default */ 65 static struct init_tab { 66 u8 reg; 67 u16 data; 68 } init_tab[] = { 69 { 0x00, 0x0071, }, 70 { 0x01, 0x3213, }, 71 { 0x09, 0x0025, }, 72 { 0x1c, 0x001d, }, 73 { 0x1f, 0x002d, }, 74 { 0x20, 0x001d, }, 75 { 0x22, 0x0022, }, 76 { 0x23, 0x0020, }, 77 { 0x29, 0x110f, }, 78 { 0x2a, 0x10b4, }, 79 { 0x2b, 0x10ae, }, 80 { 0x2c, 0x0031, }, 81 { 0x31, 0x010d, }, 82 { 0x32, 0x0100, }, 83 { 0x44, 0x0510, }, 84 { 0x54, 0x0104, }, 85 { 0x58, 0x2222, }, 86 { 0x59, 0x1162, }, 87 { 0x5a, 0x3211, }, 88 { 0x5d, 0x0370, }, 89 { 0x5e, 0x0296, }, 90 { 0x61, 0x0010, }, 91 { 0x63, 0x4a00, }, 92 { 0x65, 0x0800, }, 93 { 0x71, 0x0003, }, 94 { 0x72, 0x0470, }, 95 { 0x81, 0x0002, }, 96 { 0x82, 0x0600, }, 97 { 0x86, 0x0002, }, 98 { 0x8a, 0x2c38, }, 99 { 0x8b, 0x2a37, }, 100 { 0x92, 0x302f, }, 101 { 0x93, 0x3332, }, 102 { 0x96, 0x000c, }, 103 { 0x99, 0x0101, }, 104 { 0x9c, 0x2e37, }, 105 { 0x9d, 0x2c37, }, 106 { 0x9e, 0x2c37, }, 107 { 0xab, 0x0100, }, 108 { 0xac, 0x1003, }, 109 { 0xad, 0x103f, }, 110 { 0xe2, 0x0100, }, 111 { 0xe3, 0x1000, }, 112 { 0x28, 0x1010, }, 113 { 0xb1, 0x000e, }, 114 }; 115 116 /* VSB SNR lookup table */ 117 static struct vsb_snr_tab { 118 u16 val; 119 u16 data; 120 } vsb_snr_tab[] = { 121 { 924, 300, }, 122 { 923, 300, }, 123 { 918, 295, }, 124 { 915, 290, }, 125 { 911, 285, }, 126 { 906, 280, }, 127 { 901, 275, }, 128 { 896, 270, }, 129 { 891, 265, }, 130 { 885, 260, }, 131 { 879, 255, }, 132 { 873, 250, }, 133 { 864, 245, }, 134 { 858, 240, }, 135 { 850, 235, }, 136 { 841, 230, }, 137 { 832, 225, }, 138 { 823, 220, }, 139 { 812, 215, }, 140 { 802, 210, }, 141 { 788, 205, }, 142 { 778, 200, }, 143 { 767, 195, }, 144 { 753, 190, }, 145 { 740, 185, }, 146 { 725, 180, }, 147 { 707, 175, }, 148 { 689, 170, }, 149 { 671, 165, }, 150 { 656, 160, }, 151 { 637, 155, }, 152 { 616, 150, }, 153 { 542, 145, }, 154 { 519, 140, }, 155 { 507, 135, }, 156 { 497, 130, }, 157 { 492, 125, }, 158 { 474, 120, }, 159 { 300, 111, }, 160 { 0, 0, }, 161 }; 162 163 /* QAM64 SNR lookup table */ 164 static struct qam64_snr_tab { 165 u16 val; 166 u16 data; 167 } qam64_snr_tab[] = { 168 { 1, 0, }, 169 { 12, 300, }, 170 { 15, 290, }, 171 { 18, 280, }, 172 { 22, 270, }, 173 { 23, 268, }, 174 { 24, 266, }, 175 { 25, 264, }, 176 { 27, 262, }, 177 { 28, 260, }, 178 { 29, 258, }, 179 { 30, 256, }, 180 { 32, 254, }, 181 { 33, 252, }, 182 { 34, 250, }, 183 { 35, 249, }, 184 { 36, 248, }, 185 { 37, 247, }, 186 { 38, 246, }, 187 { 39, 245, }, 188 { 40, 244, }, 189 { 41, 243, }, 190 { 42, 241, }, 191 { 43, 240, }, 192 { 44, 239, }, 193 { 45, 238, }, 194 { 46, 237, }, 195 { 47, 236, }, 196 { 48, 235, }, 197 { 49, 234, }, 198 { 50, 233, }, 199 { 51, 232, }, 200 { 52, 231, }, 201 { 53, 230, }, 202 { 55, 229, }, 203 { 56, 228, }, 204 { 57, 227, }, 205 { 58, 226, }, 206 { 59, 225, }, 207 { 60, 224, }, 208 { 62, 223, }, 209 { 63, 222, }, 210 { 65, 221, }, 211 { 66, 220, }, 212 { 68, 219, }, 213 { 69, 218, }, 214 { 70, 217, }, 215 { 72, 216, }, 216 { 73, 215, }, 217 { 75, 214, }, 218 { 76, 213, }, 219 { 78, 212, }, 220 { 80, 211, }, 221 { 81, 210, }, 222 { 83, 209, }, 223 { 84, 208, }, 224 { 85, 207, }, 225 { 87, 206, }, 226 { 89, 205, }, 227 { 91, 204, }, 228 { 93, 203, }, 229 { 95, 202, }, 230 { 96, 201, }, 231 { 104, 200, }, 232 { 255, 0, }, 233 }; 234 235 /* QAM256 SNR lookup table */ 236 static struct qam256_snr_tab { 237 u16 val; 238 u16 data; 239 } qam256_snr_tab[] = { 240 { 1, 0, }, 241 { 12, 400, }, 242 { 13, 390, }, 243 { 15, 380, }, 244 { 17, 360, }, 245 { 19, 350, }, 246 { 22, 348, }, 247 { 23, 346, }, 248 { 24, 344, }, 249 { 25, 342, }, 250 { 26, 340, }, 251 { 27, 336, }, 252 { 28, 334, }, 253 { 29, 332, }, 254 { 30, 330, }, 255 { 31, 328, }, 256 { 32, 326, }, 257 { 33, 325, }, 258 { 34, 322, }, 259 { 35, 320, }, 260 { 37, 318, }, 261 { 39, 316, }, 262 { 40, 314, }, 263 { 41, 312, }, 264 { 42, 310, }, 265 { 43, 308, }, 266 { 46, 306, }, 267 { 47, 304, }, 268 { 49, 302, }, 269 { 51, 300, }, 270 { 53, 298, }, 271 { 54, 297, }, 272 { 55, 296, }, 273 { 56, 295, }, 274 { 57, 294, }, 275 { 59, 293, }, 276 { 60, 292, }, 277 { 61, 291, }, 278 { 63, 290, }, 279 { 64, 289, }, 280 { 65, 288, }, 281 { 66, 287, }, 282 { 68, 286, }, 283 { 69, 285, }, 284 { 71, 284, }, 285 { 72, 283, }, 286 { 74, 282, }, 287 { 75, 281, }, 288 { 76, 280, }, 289 { 77, 279, }, 290 { 78, 278, }, 291 { 81, 277, }, 292 { 83, 276, }, 293 { 84, 275, }, 294 { 86, 274, }, 295 { 87, 273, }, 296 { 89, 272, }, 297 { 90, 271, }, 298 { 92, 270, }, 299 { 93, 269, }, 300 { 95, 268, }, 301 { 96, 267, }, 302 { 98, 266, }, 303 { 100, 265, }, 304 { 102, 264, }, 305 { 104, 263, }, 306 { 105, 262, }, 307 { 106, 261, }, 308 { 110, 260, }, 309 { 255, 0, }, 310 }; 311 312 /* 8 bit registers, 16 bit values */ 313 static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data) 314 { 315 int ret; 316 u8 buf[] = { reg, data >> 8, data & 0xff }; 317 318 struct i2c_msg msg = { .addr = state->config->demod_address, 319 .flags = 0, .buf = buf, .len = 3 }; 320 321 ret = i2c_transfer(state->i2c, &msg, 1); 322 323 if (ret != 1) 324 printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, " 325 "ret == %i)\n", __func__, reg, data, ret); 326 327 return (ret != 1) ? -1 : 0; 328 } 329 330 static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg) 331 { 332 int ret; 333 u8 b0[] = { reg }; 334 u8 b1[] = { 0, 0 }; 335 336 struct i2c_msg msg[] = { 337 { .addr = state->config->demod_address, .flags = 0, 338 .buf = b0, .len = 1 }, 339 { .addr = state->config->demod_address, .flags = I2C_M_RD, 340 .buf = b1, .len = 2 } }; 341 342 ret = i2c_transfer(state->i2c, msg, 2); 343 344 if (ret != 2) 345 printk("%s: readreg error (ret == %i)\n", __func__, ret); 346 return (b1[0] << 8) | b1[1]; 347 } 348 349 static int s5h1409_softreset(struct dvb_frontend *fe) 350 { 351 struct s5h1409_state *state = fe->demodulator_priv; 352 353 dprintk("%s()\n", __func__); 354 355 s5h1409_writereg(state, 0xf5, 0); 356 s5h1409_writereg(state, 0xf5, 1); 357 state->is_qam_locked = 0; 358 state->qam_state = QAM_STATE_UNTUNED; 359 return 0; 360 } 361 362 #define S5H1409_VSB_IF_FREQ 5380 363 #define S5H1409_QAM_IF_FREQ (state->config->qam_if) 364 365 static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz) 366 { 367 struct s5h1409_state *state = fe->demodulator_priv; 368 369 dprintk("%s(%d KHz)\n", __func__, KHz); 370 371 switch (KHz) { 372 case 4000: 373 s5h1409_writereg(state, 0x87, 0x014b); 374 s5h1409_writereg(state, 0x88, 0x0cb5); 375 s5h1409_writereg(state, 0x89, 0x03e2); 376 break; 377 case 5380: 378 case 44000: 379 default: 380 s5h1409_writereg(state, 0x87, 0x01be); 381 s5h1409_writereg(state, 0x88, 0x0436); 382 s5h1409_writereg(state, 0x89, 0x054d); 383 break; 384 } 385 state->if_freq = KHz; 386 387 return 0; 388 } 389 390 static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted) 391 { 392 struct s5h1409_state *state = fe->demodulator_priv; 393 394 dprintk("%s(%d)\n", __func__, inverted); 395 396 if (inverted == 1) 397 return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ 398 else 399 return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */ 400 } 401 402 static int s5h1409_enable_modulation(struct dvb_frontend *fe, 403 fe_modulation_t m) 404 { 405 struct s5h1409_state *state = fe->demodulator_priv; 406 407 dprintk("%s(0x%08x)\n", __func__, m); 408 409 switch (m) { 410 case VSB_8: 411 dprintk("%s() VSB_8\n", __func__); 412 if (state->if_freq != S5H1409_VSB_IF_FREQ) 413 s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ); 414 s5h1409_writereg(state, 0xf4, 0); 415 break; 416 case QAM_64: 417 case QAM_256: 418 case QAM_AUTO: 419 dprintk("%s() QAM_AUTO (64/256)\n", __func__); 420 if (state->if_freq != S5H1409_QAM_IF_FREQ) 421 s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); 422 s5h1409_writereg(state, 0xf4, 1); 423 s5h1409_writereg(state, 0x85, 0x110); 424 break; 425 default: 426 dprintk("%s() Invalid modulation\n", __func__); 427 return -EINVAL; 428 } 429 430 state->current_modulation = m; 431 s5h1409_softreset(fe); 432 433 return 0; 434 } 435 436 static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 437 { 438 struct s5h1409_state *state = fe->demodulator_priv; 439 440 dprintk("%s(%d)\n", __func__, enable); 441 442 if (enable) 443 return s5h1409_writereg(state, 0xf3, 1); 444 else 445 return s5h1409_writereg(state, 0xf3, 0); 446 } 447 448 static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable) 449 { 450 struct s5h1409_state *state = fe->demodulator_priv; 451 452 dprintk("%s(%d)\n", __func__, enable); 453 454 if (enable) 455 return s5h1409_writereg(state, 0xe3, 456 s5h1409_readreg(state, 0xe3) | 0x1100); 457 else 458 return s5h1409_writereg(state, 0xe3, 459 s5h1409_readreg(state, 0xe3) & 0xfeff); 460 } 461 462 static int s5h1409_sleep(struct dvb_frontend *fe, int enable) 463 { 464 struct s5h1409_state *state = fe->demodulator_priv; 465 466 dprintk("%s(%d)\n", __func__, enable); 467 468 return s5h1409_writereg(state, 0xf2, enable); 469 } 470 471 static int s5h1409_register_reset(struct dvb_frontend *fe) 472 { 473 struct s5h1409_state *state = fe->demodulator_priv; 474 475 dprintk("%s()\n", __func__); 476 477 return s5h1409_writereg(state, 0xfa, 0); 478 } 479 480 static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe) 481 { 482 struct s5h1409_state *state = fe->demodulator_priv; 483 u16 reg; 484 485 if (state->qam_state < QAM_STATE_INTERLEAVE_SET) { 486 /* We should not perform amhum optimization until 487 the interleave mode has been configured */ 488 return; 489 } 490 491 if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) { 492 /* We've already reached the maximum optimization level, so 493 dont bother banging on the status registers */ 494 return; 495 } 496 497 /* QAM EQ lock check */ 498 reg = s5h1409_readreg(state, 0xf0); 499 500 if ((reg >> 13) & 0x1) { 501 reg &= 0xff; 502 503 s5h1409_writereg(state, 0x96, 0x000c); 504 if (reg < 0x68) { 505 if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) { 506 dprintk("%s() setting QAM state to OPT_L3\n", 507 __func__); 508 s5h1409_writereg(state, 0x93, 0x3130); 509 s5h1409_writereg(state, 0x9e, 0x2836); 510 state->qam_state = QAM_STATE_QAM_OPTIMIZED_L3; 511 } 512 } else { 513 if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) { 514 dprintk("%s() setting QAM state to OPT_L2\n", 515 __func__); 516 s5h1409_writereg(state, 0x93, 0x3332); 517 s5h1409_writereg(state, 0x9e, 0x2c37); 518 state->qam_state = QAM_STATE_QAM_OPTIMIZED_L2; 519 } 520 } 521 522 } else { 523 if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) { 524 dprintk("%s() setting QAM state to OPT_L1\n", __func__); 525 s5h1409_writereg(state, 0x96, 0x0008); 526 s5h1409_writereg(state, 0x93, 0x3332); 527 s5h1409_writereg(state, 0x9e, 0x2c37); 528 state->qam_state = QAM_STATE_QAM_OPTIMIZED_L1; 529 } 530 } 531 } 532 533 static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe) 534 { 535 struct s5h1409_state *state = fe->demodulator_priv; 536 u16 reg; 537 538 if (state->is_qam_locked) 539 return; 540 541 /* QAM EQ lock check */ 542 reg = s5h1409_readreg(state, 0xf0); 543 544 if ((reg >> 13) & 0x1) { 545 546 state->is_qam_locked = 1; 547 reg &= 0xff; 548 549 s5h1409_writereg(state, 0x96, 0x00c); 550 if ((reg < 0x38) || (reg > 0x68)) { 551 s5h1409_writereg(state, 0x93, 0x3332); 552 s5h1409_writereg(state, 0x9e, 0x2c37); 553 } else { 554 s5h1409_writereg(state, 0x93, 0x3130); 555 s5h1409_writereg(state, 0x9e, 0x2836); 556 } 557 558 } else { 559 s5h1409_writereg(state, 0x96, 0x0008); 560 s5h1409_writereg(state, 0x93, 0x3332); 561 s5h1409_writereg(state, 0x9e, 0x2c37); 562 } 563 } 564 565 static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) 566 { 567 struct s5h1409_state *state = fe->demodulator_priv; 568 u16 reg, reg1, reg2; 569 570 if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) { 571 /* We've done the optimization already */ 572 return; 573 } 574 575 reg = s5h1409_readreg(state, 0xf1); 576 577 /* Master lock */ 578 if ((reg >> 15) & 0x1) { 579 if (state->qam_state == QAM_STATE_UNTUNED || 580 state->qam_state == QAM_STATE_TUNING_STARTED) { 581 dprintk("%s() setting QAM state to INTERLEAVE_SET\n", 582 __func__); 583 reg1 = s5h1409_readreg(state, 0xb2); 584 reg2 = s5h1409_readreg(state, 0xad); 585 586 s5h1409_writereg(state, 0x96, 0x0020); 587 s5h1409_writereg(state, 0xad, 588 (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff))); 589 state->qam_state = QAM_STATE_INTERLEAVE_SET; 590 } 591 } else { 592 if (state->qam_state == QAM_STATE_UNTUNED) { 593 dprintk("%s() setting QAM state to TUNING_STARTED\n", 594 __func__); 595 s5h1409_writereg(state, 0x96, 0x08); 596 s5h1409_writereg(state, 0xab, 597 s5h1409_readreg(state, 0xab) | 0x1001); 598 state->qam_state = QAM_STATE_TUNING_STARTED; 599 } 600 } 601 } 602 603 static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe) 604 { 605 struct s5h1409_state *state = fe->demodulator_priv; 606 u16 reg, reg1, reg2; 607 608 reg = s5h1409_readreg(state, 0xf1); 609 610 /* Master lock */ 611 if ((reg >> 15) & 0x1) { 612 if (state->qam_state != 2) { 613 state->qam_state = 2; 614 reg1 = s5h1409_readreg(state, 0xb2); 615 reg2 = s5h1409_readreg(state, 0xad); 616 617 s5h1409_writereg(state, 0x96, 0x20); 618 s5h1409_writereg(state, 0xad, 619 (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff))); 620 s5h1409_writereg(state, 0xab, 621 s5h1409_readreg(state, 0xab) & 0xeffe); 622 } 623 } else { 624 if (state->qam_state != 1) { 625 state->qam_state = 1; 626 s5h1409_writereg(state, 0x96, 0x08); 627 s5h1409_writereg(state, 0xab, 628 s5h1409_readreg(state, 0xab) | 0x1001); 629 } 630 } 631 } 632 633 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ 634 static int s5h1409_set_frontend(struct dvb_frontend *fe) 635 { 636 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 637 struct s5h1409_state *state = fe->demodulator_priv; 638 639 dprintk("%s(frequency=%d)\n", __func__, p->frequency); 640 641 s5h1409_softreset(fe); 642 643 state->current_frequency = p->frequency; 644 645 s5h1409_enable_modulation(fe, p->modulation); 646 647 if (fe->ops.tuner_ops.set_params) { 648 if (fe->ops.i2c_gate_ctrl) 649 fe->ops.i2c_gate_ctrl(fe, 1); 650 fe->ops.tuner_ops.set_params(fe); 651 if (fe->ops.i2c_gate_ctrl) 652 fe->ops.i2c_gate_ctrl(fe, 0); 653 } 654 655 /* Issue a reset to the demod so it knows to resync against the 656 newly tuned frequency */ 657 s5h1409_softreset(fe); 658 659 /* Optimize the demod for QAM */ 660 if (state->current_modulation != VSB_8) { 661 /* This almost certainly applies to all boards, but for now 662 only do it for the HVR-1600. Once the other boards are 663 tested, the "legacy" versions can just go away */ 664 if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { 665 s5h1409_set_qam_interleave_mode(fe); 666 s5h1409_set_qam_amhum_mode(fe); 667 } else { 668 s5h1409_set_qam_amhum_mode_legacy(fe); 669 s5h1409_set_qam_interleave_mode_legacy(fe); 670 } 671 } 672 673 return 0; 674 } 675 676 static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) 677 { 678 struct s5h1409_state *state = fe->demodulator_priv; 679 u16 val; 680 681 dprintk("%s(%d)\n", __func__, mode); 682 683 val = s5h1409_readreg(state, 0xac) & 0xcfff; 684 switch (mode) { 685 case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: 686 val |= 0x0000; 687 break; 688 case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: 689 dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode); 690 val |= 0x1000; 691 break; 692 case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: 693 val |= 0x2000; 694 break; 695 case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: 696 val |= 0x3000; 697 break; 698 default: 699 return -EINVAL; 700 } 701 702 /* Configure MPEG Signal Timing charactistics */ 703 return s5h1409_writereg(state, 0xac, val); 704 } 705 706 /* Reset the demod hardware and reset all of the configuration registers 707 to a default state. */ 708 static int s5h1409_init(struct dvb_frontend *fe) 709 { 710 int i; 711 712 struct s5h1409_state *state = fe->demodulator_priv; 713 dprintk("%s()\n", __func__); 714 715 s5h1409_sleep(fe, 0); 716 s5h1409_register_reset(fe); 717 718 for (i = 0; i < ARRAY_SIZE(init_tab); i++) 719 s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data); 720 721 /* The datasheet says that after initialisation, VSB is default */ 722 state->current_modulation = VSB_8; 723 724 /* Optimize for the HVR-1600 if appropriate. Note that some of these 725 may get folded into the generic case after testing with other 726 devices */ 727 if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { 728 /* VSB AGC REF */ 729 s5h1409_writereg(state, 0x09, 0x0050); 730 731 /* Unknown but Windows driver does it... */ 732 s5h1409_writereg(state, 0x21, 0x0001); 733 s5h1409_writereg(state, 0x50, 0x030e); 734 735 /* QAM AGC REF */ 736 s5h1409_writereg(state, 0x82, 0x0800); 737 } 738 739 if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) 740 s5h1409_writereg(state, 0xab, 741 s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ 742 else 743 s5h1409_writereg(state, 0xab, 744 s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */ 745 746 s5h1409_set_spectralinversion(fe, state->config->inversion); 747 s5h1409_set_if_freq(fe, state->if_freq); 748 s5h1409_set_gpio(fe, state->config->gpio); 749 s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing); 750 s5h1409_softreset(fe); 751 752 /* Note: Leaving the I2C gate closed. */ 753 s5h1409_i2c_gate_ctrl(fe, 0); 754 755 return 0; 756 } 757 758 static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status) 759 { 760 struct s5h1409_state *state = fe->demodulator_priv; 761 u16 reg; 762 u32 tuner_status = 0; 763 764 *status = 0; 765 766 /* Optimize the demod for QAM */ 767 if (state->current_modulation != VSB_8) { 768 /* This almost certainly applies to all boards, but for now 769 only do it for the HVR-1600. Once the other boards are 770 tested, the "legacy" versions can just go away */ 771 if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) { 772 s5h1409_set_qam_interleave_mode(fe); 773 s5h1409_set_qam_amhum_mode(fe); 774 } 775 } 776 777 /* Get the demodulator status */ 778 reg = s5h1409_readreg(state, 0xf1); 779 if (reg & 0x1000) 780 *status |= FE_HAS_VITERBI; 781 if (reg & 0x8000) 782 *status |= FE_HAS_LOCK | FE_HAS_SYNC; 783 784 switch (state->config->status_mode) { 785 case S5H1409_DEMODLOCKING: 786 if (*status & FE_HAS_VITERBI) 787 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 788 break; 789 case S5H1409_TUNERLOCKING: 790 /* Get the tuner status */ 791 if (fe->ops.tuner_ops.get_status) { 792 if (fe->ops.i2c_gate_ctrl) 793 fe->ops.i2c_gate_ctrl(fe, 1); 794 795 fe->ops.tuner_ops.get_status(fe, &tuner_status); 796 797 if (fe->ops.i2c_gate_ctrl) 798 fe->ops.i2c_gate_ctrl(fe, 0); 799 } 800 if (tuner_status) 801 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 802 break; 803 } 804 805 dprintk("%s() status 0x%08x\n", __func__, *status); 806 807 return 0; 808 } 809 810 static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) 811 { 812 int i, ret = -EINVAL; 813 dprintk("%s()\n", __func__); 814 815 for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) { 816 if (v < qam256_snr_tab[i].val) { 817 *snr = qam256_snr_tab[i].data; 818 ret = 0; 819 break; 820 } 821 } 822 return ret; 823 } 824 825 static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) 826 { 827 int i, ret = -EINVAL; 828 dprintk("%s()\n", __func__); 829 830 for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) { 831 if (v < qam64_snr_tab[i].val) { 832 *snr = qam64_snr_tab[i].data; 833 ret = 0; 834 break; 835 } 836 } 837 return ret; 838 } 839 840 static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v) 841 { 842 int i, ret = -EINVAL; 843 dprintk("%s()\n", __func__); 844 845 for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) { 846 if (v > vsb_snr_tab[i].val) { 847 *snr = vsb_snr_tab[i].data; 848 ret = 0; 849 break; 850 } 851 } 852 dprintk("%s() snr=%d\n", __func__, *snr); 853 return ret; 854 } 855 856 static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr) 857 { 858 struct s5h1409_state *state = fe->demodulator_priv; 859 u16 reg; 860 dprintk("%s()\n", __func__); 861 862 switch (state->current_modulation) { 863 case QAM_64: 864 reg = s5h1409_readreg(state, 0xf0) & 0xff; 865 return s5h1409_qam64_lookup_snr(fe, snr, reg); 866 case QAM_256: 867 reg = s5h1409_readreg(state, 0xf0) & 0xff; 868 return s5h1409_qam256_lookup_snr(fe, snr, reg); 869 case VSB_8: 870 reg = s5h1409_readreg(state, 0xf1) & 0x3ff; 871 return s5h1409_vsb_lookup_snr(fe, snr, reg); 872 default: 873 break; 874 } 875 876 return -EINVAL; 877 } 878 879 static int s5h1409_read_signal_strength(struct dvb_frontend *fe, 880 u16 *signal_strength) 881 { 882 /* borrowed from lgdt330x.c 883 * 884 * Calculate strength from SNR up to 35dB 885 * Even though the SNR can go higher than 35dB, 886 * there is some comfort factor in having a range of 887 * strong signals that can show at 100% 888 */ 889 u16 snr; 890 u32 tmp; 891 int ret = s5h1409_read_snr(fe, &snr); 892 893 *signal_strength = 0; 894 895 if (0 == ret) { 896 /* The following calculation method was chosen 897 * purely for the sake of code re-use from the 898 * other demod drivers that use this method */ 899 900 /* Convert from SNR in dB * 10 to 8.24 fixed-point */ 901 tmp = (snr * ((1 << 24) / 10)); 902 903 /* Convert from 8.24 fixed-point to 904 * scale the range 0 - 35*2^24 into 0 - 65535*/ 905 if (tmp >= 8960 * 0x10000) 906 *signal_strength = 0xffff; 907 else 908 *signal_strength = tmp / 8960; 909 } 910 911 return ret; 912 } 913 914 static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 915 { 916 struct s5h1409_state *state = fe->demodulator_priv; 917 918 *ucblocks = s5h1409_readreg(state, 0xb5); 919 920 return 0; 921 } 922 923 static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber) 924 { 925 return s5h1409_read_ucblocks(fe, ber); 926 } 927 928 static int s5h1409_get_frontend(struct dvb_frontend *fe) 929 { 930 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 931 struct s5h1409_state *state = fe->demodulator_priv; 932 933 p->frequency = state->current_frequency; 934 p->modulation = state->current_modulation; 935 936 return 0; 937 } 938 939 static int s5h1409_get_tune_settings(struct dvb_frontend *fe, 940 struct dvb_frontend_tune_settings *tune) 941 { 942 tune->min_delay_ms = 1000; 943 return 0; 944 } 945 946 static void s5h1409_release(struct dvb_frontend *fe) 947 { 948 struct s5h1409_state *state = fe->demodulator_priv; 949 kfree(state); 950 } 951 952 static struct dvb_frontend_ops s5h1409_ops; 953 954 struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, 955 struct i2c_adapter *i2c) 956 { 957 struct s5h1409_state *state = NULL; 958 u16 reg; 959 960 /* allocate memory for the internal state */ 961 state = kzalloc(sizeof(struct s5h1409_state), GFP_KERNEL); 962 if (state == NULL) 963 goto error; 964 965 /* setup the state */ 966 state->config = config; 967 state->i2c = i2c; 968 state->current_modulation = 0; 969 state->if_freq = S5H1409_VSB_IF_FREQ; 970 971 /* check if the demod exists */ 972 reg = s5h1409_readreg(state, 0x04); 973 if ((reg != 0x0066) && (reg != 0x007f)) 974 goto error; 975 976 /* create dvb_frontend */ 977 memcpy(&state->frontend.ops, &s5h1409_ops, 978 sizeof(struct dvb_frontend_ops)); 979 state->frontend.demodulator_priv = state; 980 981 if (s5h1409_init(&state->frontend) != 0) { 982 printk(KERN_ERR "%s: Failed to initialize correctly\n", 983 __func__); 984 goto error; 985 } 986 987 /* Note: Leaving the I2C gate open here. */ 988 s5h1409_i2c_gate_ctrl(&state->frontend, 1); 989 990 return &state->frontend; 991 992 error: 993 kfree(state); 994 return NULL; 995 } 996 EXPORT_SYMBOL(s5h1409_attach); 997 998 static struct dvb_frontend_ops s5h1409_ops = { 999 .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, 1000 .info = { 1001 .name = "Samsung S5H1409 QAM/8VSB Frontend", 1002 .frequency_min = 54000000, 1003 .frequency_max = 858000000, 1004 .frequency_stepsize = 62500, 1005 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB 1006 }, 1007 1008 .init = s5h1409_init, 1009 .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl, 1010 .set_frontend = s5h1409_set_frontend, 1011 .get_frontend = s5h1409_get_frontend, 1012 .get_tune_settings = s5h1409_get_tune_settings, 1013 .read_status = s5h1409_read_status, 1014 .read_ber = s5h1409_read_ber, 1015 .read_signal_strength = s5h1409_read_signal_strength, 1016 .read_snr = s5h1409_read_snr, 1017 .read_ucblocks = s5h1409_read_ucblocks, 1018 .release = s5h1409_release, 1019 }; 1020 1021 MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); 1022 MODULE_AUTHOR("Steven Toth"); 1023 MODULE_LICENSE("GPL"); 1024