aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDevin Heitmueller <dheitmueller@kernellabs.com>2009-10-28 00:26:05 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-12-05 15:41:22 -0500
commitf0cd44b4a1a7465230dfbe1e645d9dc73f83cb13 (patch)
tree0066fc7da4223edb9e3e00d9af22685a4f221a7c
parentaf5c8e1523edf792f57ec938aef9423783af25e1 (diff)
V4L/DVB (13330): s5h1409: properly handle QAM optimization after lock achieved
The sh51409 driver was only doing the QAM optimization a single time, and it would only occur if you received a lock instantaneously after the tuning request. Restructure the code so that the optimization occurs once you reach a signal lock. Note that this depends on the caller polling for status, but we don't have much choice at this point without an independent thread monitoring the lock status. Also, at this point pretty much every application polls for status lock after doing the tune, so the likelihood of the optimization not occurring in the real world is pretty low. The state machine has also been reworked such that setting the interleave mode is now a dependency of doing the QAM optimization. Before both were mutually exclusive, which was not consistent with the Windows driver. We now have a single state machine that controls both. The changes as-is are only enabled for the HVR-1600. Once the changes are tested with some of the other boards, this change should be made generic and the "_legacy" functions should be removed. This work was sponsored by ONELAN Limited. Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c136
1 files changed, 128 insertions, 8 deletions
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 85fba581c5ab..5507159a23b1 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -44,7 +44,15 @@ struct s5h1409_state {
44 int if_freq; 44 int if_freq;
45 45
46 u32 is_qam_locked; 46 u32 is_qam_locked;
47 u32 qam_state; 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;
48}; 56};
49 57
50static int debug; 58static int debug;
@@ -347,7 +355,7 @@ static int s5h1409_softreset(struct dvb_frontend *fe)
347 s5h1409_writereg(state, 0xf5, 0); 355 s5h1409_writereg(state, 0xf5, 0);
348 s5h1409_writereg(state, 0xf5, 1); 356 s5h1409_writereg(state, 0xf5, 1);
349 state->is_qam_locked = 0; 357 state->is_qam_locked = 0;
350 state->qam_state = 0; 358 state->qam_state = QAM_STATE_UNTUNED;
351 return 0; 359 return 0;
352} 360}
353 361
@@ -474,6 +482,59 @@ static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
474 struct s5h1409_state *state = fe->demodulator_priv; 482 struct s5h1409_state *state = fe->demodulator_priv;
475 u16 reg; 483 u16 reg;
476 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
533static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe)
534{
535 struct s5h1409_state *state = fe->demodulator_priv;
536 u16 reg;
537
477 if (state->is_qam_locked) 538 if (state->is_qam_locked)
478 return; 539 return;
479 540
@@ -506,6 +567,46 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
506 struct s5h1409_state *state = fe->demodulator_priv; 567 struct s5h1409_state *state = fe->demodulator_priv;
507 u16 reg, reg1, reg2; 568 u16 reg, reg1, reg2;
508 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 s5h1409_writereg(state, 0xab,
590 s5h1409_readreg(state, 0xab) & 0xeffe);
591 state->qam_state = QAM_STATE_INTERLEAVE_SET;
592 }
593 } else {
594 if (state->qam_state == QAM_STATE_UNTUNED) {
595 dprintk("%s() setting QAM state to TUNING_STARTED\n",
596 __func__);
597 s5h1409_writereg(state, 0x96, 0x08);
598 s5h1409_writereg(state, 0xab,
599 s5h1409_readreg(state, 0xab) | 0x1001);
600 state->qam_state = QAM_STATE_TUNING_STARTED;
601 }
602 }
603}
604
605static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
606{
607 struct s5h1409_state *state = fe->demodulator_priv;
608 u16 reg, reg1, reg2;
609
509 reg = s5h1409_readreg(state, 0xf1); 610 reg = s5h1409_readreg(state, 0xf1);
510 611
511 /* Master lock */ 612 /* Master lock */
@@ -553,16 +654,24 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe,
553 fe->ops.i2c_gate_ctrl(fe, 0); 654 fe->ops.i2c_gate_ctrl(fe, 0);
554 } 655 }
555 656
556 /* Optimize the demod for QAM */
557 if (p->u.vsb.modulation != VSB_8) {
558 s5h1409_set_qam_amhum_mode(fe);
559 s5h1409_set_qam_interleave_mode(fe);
560 }
561
562 /* Issue a reset to the demod so it knows to resync against the 657 /* Issue a reset to the demod so it knows to resync against the
563 newly tuned frequency */ 658 newly tuned frequency */
564 s5h1409_softreset(fe); 659 s5h1409_softreset(fe);
565 660
661 /* Optimize the demod for QAM */
662 if (state->current_modulation != VSB_8) {
663 /* This almost certainly applies to all boards, but for now
664 only do it for the HVR-1600. Once the other boards are
665 tested, the "legacy" versions can just go away */
666 if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
667 s5h1409_set_qam_amhum_mode(fe);
668 s5h1409_set_qam_interleave_mode(fe);
669 } else {
670 s5h1409_set_qam_amhum_mode_legacy(fe);
671 s5h1409_set_qam_interleave_mode_legacy(fe);
672 }
673 }
674
566 return 0; 675 return 0;
567} 676}
568 677
@@ -656,6 +765,17 @@ static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
656 765
657 *status = 0; 766 *status = 0;
658 767
768 /* Optimize the demod for QAM */
769 if (state->current_modulation != VSB_8) {
770 /* This almost certainly applies to all boards, but for now
771 only do it for the HVR-1600. Once the other boards are
772 tested, the "legacy" versions can just go away */
773 if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
774 s5h1409_set_qam_amhum_mode(fe);
775 s5h1409_set_qam_interleave_mode(fe);
776 }
777 }
778
659 /* Get the demodulator status */ 779 /* Get the demodulator status */
660 reg = s5h1409_readreg(state, 0xf1); 780 reg = s5h1409_readreg(state, 0xf1);
661 if (reg & 0x1000) 781 if (reg & 0x1000)