diff options
Diffstat (limited to 'drivers/media/dvb/frontends/s5h1409.c')
-rw-r--r-- | drivers/media/dvb/frontends/s5h1409.c | 149 |
1 files changed, 141 insertions, 8 deletions
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index fb3011518427..0e2f61a8978f 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,44 @@ 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 | 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 | |||
509 | reg = s5h1409_readreg(state, 0xf1); | 608 | reg = s5h1409_readreg(state, 0xf1); |
510 | 609 | ||
511 | /* Master lock */ | 610 | /* Master lock */ |
@@ -553,16 +652,24 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe, | |||
553 | fe->ops.i2c_gate_ctrl(fe, 0); | 652 | fe->ops.i2c_gate_ctrl(fe, 0); |
554 | } | 653 | } |
555 | 654 | ||
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 | 655 | /* Issue a reset to the demod so it knows to resync against the |
563 | newly tuned frequency */ | 656 | newly tuned frequency */ |
564 | s5h1409_softreset(fe); | 657 | s5h1409_softreset(fe); |
565 | 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 | |||
566 | return 0; | 673 | return 0; |
567 | } | 674 | } |
568 | 675 | ||
@@ -614,6 +721,21 @@ static int s5h1409_init(struct dvb_frontend *fe) | |||
614 | /* The datasheet says that after initialisation, VSB is default */ | 721 | /* The datasheet says that after initialisation, VSB is default */ |
615 | state->current_modulation = VSB_8; | 722 | state->current_modulation = VSB_8; |
616 | 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 | |||
617 | if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) | 739 | if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) |
618 | s5h1409_writereg(state, 0xab, | 740 | s5h1409_writereg(state, 0xab, |
619 | s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ | 741 | s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ |
@@ -641,6 +763,17 @@ static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status) | |||
641 | 763 | ||
642 | *status = 0; | 764 | *status = 0; |
643 | 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 | |||
644 | /* Get the demodulator status */ | 777 | /* Get the demodulator status */ |
645 | reg = s5h1409_readreg(state, 0xf1); | 778 | reg = s5h1409_readreg(state, 0xf1); |
646 | if (reg & 0x1000) | 779 | if (reg & 0x1000) |