aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.c190
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.h6
2 files changed, 187 insertions, 9 deletions
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
index d69c775f864..d329d6abef8 100644
--- a/drivers/media/dvb/frontends/lgdt3305.c
+++ b/drivers/media/dvb/frontends/lgdt3305.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Support for LGDT3305 - VSB/QAM 2 * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
3 * 3 *
4 * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org> 4 * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
5 * 5 *
@@ -358,7 +358,10 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
358 case QAM_256: 358 case QAM_256:
359 agcdelay = 0x046b; 359 agcdelay = 0x046b;
360 rfbw = 0x8889; 360 rfbw = 0x8889;
361 ifbw = 0x8888; 361 if (state->cfg->demod_chip == LGDT3305)
362 ifbw = 0x8888;
363 else
364 ifbw = 0x6666;
362 break; 365 break;
363 default: 366 default:
364 return -EINVAL; 367 return -EINVAL;
@@ -410,8 +413,18 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state,
410 lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen); 413 lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
411 414
412 /* control agc function */ 415 /* control agc function */
413 lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1); 416 switch (state->cfg->demod_chip) {
414 lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen); 417 case LGDT3304:
418 lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
419 lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
420 break;
421 case LGDT3305:
422 lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
423 lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
424 break;
425 default:
426 return -EINVAL;
427 }
415 428
416 return lgdt3305_rfagc_loop(state, param); 429 return lgdt3305_rfagc_loop(state, param);
417} 430}
@@ -544,6 +557,11 @@ static int lgdt3305_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
544 enable ? 0 : 1); 557 enable ? 0 : 1);
545} 558}
546 559
560static int lgdt3304_sleep(struct dvb_frontend *fe)
561{
562 return 0;
563}
564
547static int lgdt3305_sleep(struct dvb_frontend *fe) 565static int lgdt3305_sleep(struct dvb_frontend *fe)
548{ 566{
549 struct lgdt3305_state *state = fe->demodulator_priv; 567 struct lgdt3305_state *state = fe->demodulator_priv;
@@ -572,6 +590,55 @@ static int lgdt3305_sleep(struct dvb_frontend *fe)
572 return 0; 590 return 0;
573} 591}
574 592
593static int lgdt3304_init(struct dvb_frontend *fe)
594{
595 struct lgdt3305_state *state = fe->demodulator_priv;
596 int ret;
597
598 static struct lgdt3305_reg lgdt3304_init_data[] = {
599 { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, },
600 { .reg = 0x000d, .val = 0x02, },
601 { .reg = 0x000e, .val = 0x02, },
602 { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, },
603 { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, },
604 { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, },
605 { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, },
606 { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, },
607 { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, },
608 { .reg = LGDT3305_CR_CTRL_7, .val = 0xf9, },
609 { .reg = 0x0112, .val = 0x17, },
610 { .reg = 0x0113, .val = 0x15, },
611 { .reg = 0x0114, .val = 0x18, },
612 { .reg = 0x0115, .val = 0xff, },
613 { .reg = 0x0116, .val = 0x3c, },
614 { .reg = 0x0214, .val = 0x67, },
615 { .reg = 0x0424, .val = 0x8d, },
616 { .reg = 0x0427, .val = 0x12, },
617 { .reg = 0x0428, .val = 0x4f, },
618 { .reg = LGDT3305_IFBW_1, .val = 0x80, },
619 { .reg = LGDT3305_IFBW_2, .val = 0x00, },
620 { .reg = 0x030a, .val = 0x08, },
621 { .reg = 0x030b, .val = 0x9b, },
622 { .reg = 0x030d, .val = 0x00, },
623 { .reg = 0x030e, .val = 0x1c, },
624 { .reg = 0x0314, .val = 0xe1, },
625 { .reg = 0x000d, .val = 0x82, },
626 { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, },
627 { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, },
628 };
629
630 lg_dbg("\n");
631
632 ret = lgdt3305_write_regs(state, lgdt3304_init_data,
633 ARRAY_SIZE(lgdt3304_init_data));
634 if (lg_fail(ret))
635 goto fail;
636
637 ret = lgdt3305_soft_reset(state);
638fail:
639 return ret;
640}
641
575static int lgdt3305_init(struct dvb_frontend *fe) 642static int lgdt3305_init(struct dvb_frontend *fe)
576{ 643{
577 struct lgdt3305_state *state = fe->demodulator_priv; 644 struct lgdt3305_state *state = fe->demodulator_priv;
@@ -640,6 +707,76 @@ fail:
640 return ret; 707 return ret;
641} 708}
642 709
710static int lgdt3304_set_parameters(struct dvb_frontend *fe,
711 struct dvb_frontend_parameters *param)
712{
713 struct lgdt3305_state *state = fe->demodulator_priv;
714 int ret;
715
716 lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
717
718 if (fe->ops.tuner_ops.set_params) {
719 ret = fe->ops.tuner_ops.set_params(fe, param);
720 if (fe->ops.i2c_gate_ctrl)
721 fe->ops.i2c_gate_ctrl(fe, 0);
722 if (lg_fail(ret))
723 goto fail;
724 state->current_frequency = param->frequency;
725 }
726
727 ret = lgdt3305_set_modulation(state, param);
728 if (lg_fail(ret))
729 goto fail;
730
731 ret = lgdt3305_passband_digital_agc(state, param);
732 if (lg_fail(ret))
733 goto fail;
734
735 ret = lgdt3305_agc_setup(state, param);
736 if (lg_fail(ret))
737 goto fail;
738
739 /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
740 switch (param->u.vsb.modulation) {
741 case VSB_8:
742 lgdt3305_write_reg(state, 0x030d, 0x00);
743 lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
744 lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
745 lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
746 lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
747 break;
748 case QAM_64:
749 case QAM_256:
750 lgdt3305_write_reg(state, 0x030d, 0x14);
751 ret = lgdt3305_set_if(state, param);
752 if (lg_fail(ret))
753 goto fail;
754 break;
755 default:
756 return -EINVAL;
757 }
758
759
760 ret = lgdt3305_spectral_inversion(state, param,
761 state->cfg->spectral_inversion
762 ? 1 : 0);
763 if (lg_fail(ret))
764 goto fail;
765
766 state->current_modulation = param->u.vsb.modulation;
767
768 ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
769 if (lg_fail(ret))
770 goto fail;
771
772 /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
773 ret = lgdt3305_mpeg_mode_polarity(state,
774 state->cfg->tpclk_edge,
775 state->cfg->tpvalid_polarity);
776fail:
777 return ret;
778}
779
643static int lgdt3305_set_parameters(struct dvb_frontend *fe, 780static int lgdt3305_set_parameters(struct dvb_frontend *fe,
644 struct dvb_frontend_parameters *param) 781 struct dvb_frontend_parameters *param)
645{ 782{
@@ -993,6 +1130,7 @@ static void lgdt3305_release(struct dvb_frontend *fe)
993 kfree(state); 1130 kfree(state);
994} 1131}
995 1132
1133static struct dvb_frontend_ops lgdt3304_ops;
996static struct dvb_frontend_ops lgdt3305_ops; 1134static struct dvb_frontend_ops lgdt3305_ops;
997 1135
998struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, 1136struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
@@ -1013,11 +1151,21 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
1013 state->cfg = config; 1151 state->cfg = config;
1014 state->i2c_adap = i2c_adap; 1152 state->i2c_adap = i2c_adap;
1015 1153
1016 memcpy(&state->frontend.ops, &lgdt3305_ops, 1154 switch (config->demod_chip) {
1017 sizeof(struct dvb_frontend_ops)); 1155 case LGDT3304:
1156 memcpy(&state->frontend.ops, &lgdt3304_ops,
1157 sizeof(struct dvb_frontend_ops));
1158 break;
1159 case LGDT3305:
1160 memcpy(&state->frontend.ops, &lgdt3305_ops,
1161 sizeof(struct dvb_frontend_ops));
1162 break;
1163 default:
1164 goto fail;
1165 }
1018 state->frontend.demodulator_priv = state; 1166 state->frontend.demodulator_priv = state;
1019 1167
1020 /* verify that we're talking to a lg dt3305 */ 1168 /* verify that we're talking to a lg dt3304/5 */
1021 ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val); 1169 ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
1022 if ((lg_fail(ret)) | (val == 0)) 1170 if ((lg_fail(ret)) | (val == 0))
1023 goto fail; 1171 goto fail;
@@ -1036,12 +1184,36 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
1036 1184
1037 return &state->frontend; 1185 return &state->frontend;
1038fail: 1186fail:
1039 lg_warn("unable to detect LGDT3305 hardware\n"); 1187 lg_warn("unable to detect %s hardware\n",
1188 config->demod_chip ? "LGDT3304" : "LGDT3305");
1040 kfree(state); 1189 kfree(state);
1041 return NULL; 1190 return NULL;
1042} 1191}
1043EXPORT_SYMBOL(lgdt3305_attach); 1192EXPORT_SYMBOL(lgdt3305_attach);
1044 1193
1194static struct dvb_frontend_ops lgdt3304_ops = {
1195 .info = {
1196 .name = "LG Electronics LGDT3304 VSB/QAM Frontend",
1197 .type = FE_ATSC,
1198 .frequency_min = 54000000,
1199 .frequency_max = 858000000,
1200 .frequency_stepsize = 62500,
1201 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
1202 },
1203 .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl,
1204 .init = lgdt3304_init,
1205 .sleep = lgdt3304_sleep,
1206 .set_frontend = lgdt3304_set_parameters,
1207 .get_frontend = lgdt3305_get_frontend,
1208 .get_tune_settings = lgdt3305_get_tune_settings,
1209 .read_status = lgdt3305_read_status,
1210 .read_ber = lgdt3305_read_ber,
1211 .read_signal_strength = lgdt3305_read_signal_strength,
1212 .read_snr = lgdt3305_read_snr,
1213 .read_ucblocks = lgdt3305_read_ucblocks,
1214 .release = lgdt3305_release,
1215};
1216
1045static struct dvb_frontend_ops lgdt3305_ops = { 1217static struct dvb_frontend_ops lgdt3305_ops = {
1046 .info = { 1218 .info = {
1047 .name = "LG Electronics LGDT3305 VSB/QAM Frontend", 1219 .name = "LG Electronics LGDT3305 VSB/QAM Frontend",
@@ -1065,7 +1237,7 @@ static struct dvb_frontend_ops lgdt3305_ops = {
1065 .release = lgdt3305_release, 1237 .release = lgdt3305_release,
1066}; 1238};
1067 1239
1068MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver"); 1240MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
1069MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); 1241MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
1070MODULE_LICENSE("GPL"); 1242MODULE_LICENSE("GPL");
1071MODULE_VERSION("0.1"); 1243MODULE_VERSION("0.1");
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
index 9cb11c9cae5..a7f30c2ed14 100644
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ b/drivers/media/dvb/frontends/lgdt3305.h
@@ -41,6 +41,11 @@ enum lgdt3305_tp_valid_polarity {
41 LGDT3305_TP_VALID_HIGH = 1, 41 LGDT3305_TP_VALID_HIGH = 1,
42}; 42};
43 43
44enum lgdt_demod_chip_type {
45 LGDT3305 = 0,
46 LGDT3304 = 1,
47};
48
44struct lgdt3305_config { 49struct lgdt3305_config {
45 u8 i2c_addr; 50 u8 i2c_addr;
46 51
@@ -65,6 +70,7 @@ struct lgdt3305_config {
65 enum lgdt3305_mpeg_mode mpeg_mode; 70 enum lgdt3305_mpeg_mode mpeg_mode;
66 enum lgdt3305_tp_clock_edge tpclk_edge; 71 enum lgdt3305_tp_clock_edge tpclk_edge;
67 enum lgdt3305_tp_valid_polarity tpvalid_polarity; 72 enum lgdt3305_tp_valid_polarity tpvalid_polarity;
73 enum lgdt_demod_chip_type demod_chip;
68}; 74};
69 75
70#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \ 76#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \