aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorSteven Toth <stoth@hauppauge.com>2007-10-24 20:05:51 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-11-04 18:41:19 -0500
commitdd7d5013cdad2efe7ddbb3f77728cfe0ce295e5b (patch)
tree6fc4fe932e68f8066f3c6ff757658607d990aaed /drivers/media
parentbb8d56a4d8cad90825db0c12b55d66fde91dfa44 (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')
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c96
1 files changed, 86 insertions, 10 deletions
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 30e8a705fad4..8dee7ec9456a 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
47static int debug = 0; 50static 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
429static int s5h1409_sleep(struct dvb_frontend* fe, int enable) 436static 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
454static 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
486static 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 */
448static int s5h1409_set_frontend (struct dvb_frontend* fe, 515static 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}