diff options
Diffstat (limited to 'drivers/media/dvb/frontends/s5h1409.c')
-rw-r--r-- | drivers/media/dvb/frontends/s5h1409.c | 136 |
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 | ||
50 | static int debug; | 58 | static 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 | |||
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 | |||
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 | |||
605 | static 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) |