diff options
| author | Steven Toth <stoth@hauppauge.com> | 2007-10-24 20:05:51 -0400 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-11-04 18:41:19 -0500 |
| commit | dd7d5013cdad2efe7ddbb3f77728cfe0ce295e5b (patch) | |
| tree | 6fc4fe932e68f8066f3c6ff757658607d990aaed /drivers/media/dvb | |
| parent | bb8d56a4d8cad90825db0c12b55d66fde91dfa44 (diff) | |
V4L/DVB (6402): s5h1409: Fix broken QAM support
This patch enables QAM Annex-B support (US digital cable)
for the s5h1409 VSB/QAM demodulator.
Tested successfully with the mt2131 tuner,
present on the following supported boards:
Hauppauge WinTV-HVR-1250
Hauppauge WinTV-HVR-1800
Hauppauge WinTV-HVR-1800lp
This patch is also known to work with an upcoming XC5000 tuner driver.
Signed-off-by: Steven Toth <stoth@hauppauge.com>
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb')
| -rw-r--r-- | drivers/media/dvb/frontends/s5h1409.c | 96 |
1 files changed, 86 insertions, 10 deletions
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 30e8a705fa..8dee7ec945 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c | |||
| @@ -42,6 +42,9 @@ struct s5h1409_state { | |||
| 42 | fe_modulation_t current_modulation; | 42 | fe_modulation_t current_modulation; |
| 43 | 43 | ||
| 44 | u32 current_frequency; | 44 | u32 current_frequency; |
| 45 | |||
| 46 | u32 is_qam_locked; | ||
| 47 | u32 qam_state; | ||
| 45 | }; | 48 | }; |
| 46 | 49 | ||
| 47 | static int debug = 0; | 50 | static int debug = 0; |
| @@ -94,6 +97,7 @@ static struct init_tab { | |||
| 94 | { 0xac, 0x1003, }, | 97 | { 0xac, 0x1003, }, |
| 95 | { 0xad, 0x103f, }, | 98 | { 0xad, 0x103f, }, |
| 96 | { 0xe2, 0x0100, }, | 99 | { 0xe2, 0x0100, }, |
| 100 | { 0xe3, 0x0000, }, | ||
| 97 | { 0x28, 0x1010, }, | 101 | { 0x28, 0x1010, }, |
| 98 | { 0xb1, 0x000e, }, | 102 | { 0xb1, 0x000e, }, |
| 99 | }; | 103 | }; |
| @@ -335,6 +339,8 @@ static int s5h1409_softreset(struct dvb_frontend* fe) | |||
| 335 | 339 | ||
| 336 | s5h1409_writereg(state, 0xf5, 0); | 340 | s5h1409_writereg(state, 0xf5, 0); |
| 337 | s5h1409_writereg(state, 0xf5, 1); | 341 | s5h1409_writereg(state, 0xf5, 1); |
| 342 | state->is_qam_locked = 0; | ||
| 343 | state->qam_state = 0; | ||
| 338 | return 0; | 344 | return 0; |
| 339 | } | 345 | } |
| 340 | 346 | ||
| @@ -349,6 +355,11 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) | |||
| 349 | s5h1409_writereg(state, 0x87, 0x01be); | 355 | s5h1409_writereg(state, 0x87, 0x01be); |
| 350 | s5h1409_writereg(state, 0x88, 0x0436); | 356 | s5h1409_writereg(state, 0x88, 0x0436); |
| 351 | s5h1409_writereg(state, 0x89, 0x054d); | 357 | s5h1409_writereg(state, 0x89, 0x054d); |
| 358 | } else | ||
| 359 | if (KHz == 4000) { | ||
| 360 | s5h1409_writereg(state, 0x87, 0x014b); | ||
| 361 | s5h1409_writereg(state, 0x88, 0x0cb5); | ||
| 362 | s5h1409_writereg(state, 0x89, 0x03e2); | ||
| 352 | } else { | 363 | } else { |
| 353 | printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); | 364 | printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); |
| 354 | ret = -1; | 365 | ret = -1; |
| @@ -361,7 +372,7 @@ static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) | |||
| 361 | { | 372 | { |
| 362 | struct s5h1409_state* state = fe->demodulator_priv; | 373 | struct s5h1409_state* state = fe->demodulator_priv; |
| 363 | 374 | ||
| 364 | dprintk("%s()\n", __FUNCTION__); | 375 | dprintk("%s(%d)\n", __FUNCTION__, inverted); |
| 365 | 376 | ||
| 366 | if(inverted == 1) | 377 | if(inverted == 1) |
| 367 | return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ | 378 | return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ |
| @@ -382,14 +393,10 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, | |||
| 382 | s5h1409_writereg(state, 0xf4, 0); | 393 | s5h1409_writereg(state, 0xf4, 0); |
| 383 | break; | 394 | break; |
| 384 | case QAM_64: | 395 | case QAM_64: |
| 385 | dprintk("%s() QAM_64\n", __FUNCTION__); | ||
| 386 | s5h1409_writereg(state, 0xf4, 1); | ||
| 387 | s5h1409_writereg(state, 0x85, 0x100); | ||
| 388 | break; | ||
| 389 | case QAM_256: | 396 | case QAM_256: |
| 390 | dprintk("%s() QAM_256\n", __FUNCTION__); | 397 | dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__); |
| 391 | s5h1409_writereg(state, 0xf4, 1); | 398 | s5h1409_writereg(state, 0xf4, 1); |
| 392 | s5h1409_writereg(state, 0x85, 0x101); | 399 | s5h1409_writereg(state, 0x85, 0x110); |
| 393 | break; | 400 | break; |
| 394 | default: | 401 | default: |
| 395 | dprintk("%s() Invalid modulation\n", __FUNCTION__); | 402 | dprintk("%s() Invalid modulation\n", __FUNCTION__); |
| @@ -423,7 +430,7 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) | |||
| 423 | if (enable) | 430 | if (enable) |
| 424 | return s5h1409_writereg(state, 0xe3, 0x1100); | 431 | return s5h1409_writereg(state, 0xe3, 0x1100); |
| 425 | else | 432 | else |
| 426 | return s5h1409_writereg(state, 0xe3, 0); | 433 | return s5h1409_writereg(state, 0xe3, 0x1000); |
| 427 | } | 434 | } |
| 428 | 435 | ||
| 429 | static int s5h1409_sleep(struct dvb_frontend* fe, int enable) | 436 | static int s5h1409_sleep(struct dvb_frontend* fe, int enable) |
| @@ -444,6 +451,66 @@ static int s5h1409_register_reset(struct dvb_frontend* fe) | |||
| 444 | return s5h1409_writereg(state, 0xfa, 0); | 451 | return s5h1409_writereg(state, 0xfa, 0); |
| 445 | } | 452 | } |
| 446 | 453 | ||
| 454 | static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe) | ||
| 455 | { | ||
| 456 | struct s5h1409_state *state = fe->demodulator_priv; | ||
| 457 | u16 reg; | ||
| 458 | |||
| 459 | if (state->is_qam_locked) | ||
| 460 | return; | ||
| 461 | |||
| 462 | /* QAM EQ lock check */ | ||
| 463 | reg = s5h1409_readreg(state, 0xf0); | ||
| 464 | |||
| 465 | if ((reg >> 13) & 0x1) { | ||
| 466 | |||
| 467 | state->is_qam_locked = 1; | ||
| 468 | reg &= 0xff; | ||
| 469 | |||
| 470 | s5h1409_writereg(state, 0x96, 0x00c); | ||
| 471 | if ((reg < 0x38) || (reg > 0x68) ) { | ||
| 472 | s5h1409_writereg(state, 0x93, 0x3332); | ||
| 473 | s5h1409_writereg(state, 0x9e, 0x2c37); | ||
| 474 | } else { | ||
| 475 | s5h1409_writereg(state, 0x93, 0x3130); | ||
| 476 | s5h1409_writereg(state, 0x9e, 0x2836); | ||
| 477 | } | ||
| 478 | |||
| 479 | } else { | ||
| 480 | s5h1409_writereg(state, 0x96, 0x0008); | ||
| 481 | s5h1409_writereg(state, 0x93, 0x3332); | ||
| 482 | s5h1409_writereg(state, 0x9e, 0x2c37); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | |||
| 486 | static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) | ||
| 487 | { | ||
| 488 | struct s5h1409_state *state = fe->demodulator_priv; | ||
| 489 | u16 reg, reg1, reg2; | ||
| 490 | |||
| 491 | reg = s5h1409_readreg(state, 0xf1); | ||
| 492 | |||
| 493 | /* Master lock */ | ||
| 494 | if ((reg >> 15) & 0x1) { | ||
| 495 | if (state->qam_state != 2) { | ||
| 496 | state->qam_state = 2; | ||
| 497 | reg1 = s5h1409_readreg(state, 0xb2); | ||
| 498 | reg2 = s5h1409_readreg(state, 0xad); | ||
| 499 | |||
| 500 | s5h1409_writereg(state, 0x96, 0x20); | ||
| 501 | s5h1409_writereg(state, 0xad, | ||
| 502 | ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) ); | ||
| 503 | s5h1409_writereg(state, 0xab, 0x1100); | ||
| 504 | } | ||
| 505 | } else { | ||
| 506 | if (state->qam_state != 1) { | ||
| 507 | state->qam_state = 1; | ||
| 508 | s5h1409_writereg(state, 0x96, 0x08); | ||
| 509 | s5h1409_writereg(state, 0xab, 0x1101); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 447 | /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ | 514 | /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ |
| 448 | static int s5h1409_set_frontend (struct dvb_frontend* fe, | 515 | static int s5h1409_set_frontend (struct dvb_frontend* fe, |
| 449 | struct dvb_frontend_parameters *p) | 516 | struct dvb_frontend_parameters *p) |
| @@ -458,12 +525,21 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe, | |||
| 458 | 525 | ||
| 459 | s5h1409_enable_modulation(fe, p->u.vsb.modulation); | 526 | s5h1409_enable_modulation(fe, p->u.vsb.modulation); |
| 460 | 527 | ||
| 528 | /* Allow the demod to settle */ | ||
| 529 | msleep(100); | ||
| 530 | |||
| 461 | if (fe->ops.tuner_ops.set_params) { | 531 | if (fe->ops.tuner_ops.set_params) { |
| 462 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); | 532 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); |
| 463 | fe->ops.tuner_ops.set_params(fe, p); | 533 | fe->ops.tuner_ops.set_params(fe, p); |
| 464 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); | 534 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); |
| 465 | } | 535 | } |
| 466 | 536 | ||
| 537 | /* Optimize the demod for QAM */ | ||
| 538 | if (p->u.vsb.modulation != VSB_8) { | ||
| 539 | s5h1409_set_qam_amhum_mode(fe); | ||
| 540 | s5h1409_set_qam_interleave_mode(fe); | ||
| 541 | } | ||
| 542 | |||
| 467 | return 0; | 543 | return 0; |
| 468 | } | 544 | } |
| 469 | 545 | ||
| @@ -495,8 +571,8 @@ static int s5h1409_init (struct dvb_frontend* fe) | |||
| 495 | s5h1409_set_gpio(fe, state->config->gpio); | 571 | s5h1409_set_gpio(fe, state->config->gpio); |
| 496 | s5h1409_softreset(fe); | 572 | s5h1409_softreset(fe); |
| 497 | 573 | ||
| 498 | /* Note: Leaving the I2C gate open here. */ | 574 | /* Note: Leaving the I2C gate closed. */ |
| 499 | s5h1409_i2c_gate_ctrl(fe, 1); | 575 | s5h1409_i2c_gate_ctrl(fe, 0); |
| 500 | 576 | ||
| 501 | return 0; | 577 | return 0; |
| 502 | } | 578 | } |
