Commit 4966c0c5 authored by Brad Love's avatar Brad Love Committed by Mauro Carvalho Chehab

media: lgdt3306a: Add QAM AUTO support

As configured currently, modulation in the driver is set to auto detect,
no matter what the user sets modulation to. This leads to both QAM64
and QAM256 having the same effect. QAM AUTO is explicitly added here for
compatibility with scanning software who can use AUTO instead of doing
essentially the same scan twice.
Also included is a module option to enforce a specific QAM modulation if
desired. The true modulation is read before calculating the snr.
Changes are backwards compatible with current behaviour.
Signed-off-by: default avatarBrad Love <brad@nextdimension.cc>
Reviewed-by: default avatarMichael Ira Krufky <mkrufky@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 4c7c3f9b
...@@ -30,6 +30,17 @@ static int debug; ...@@ -30,6 +30,17 @@ static int debug;
module_param(debug, int, 0644); module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
/*
* Older drivers treated QAM64 and QAM256 the same; that is the HW always
* used "Auto" mode during detection. Setting "forced_manual"=1 allows
* the user to treat these modes as separate. For backwards compatibility,
* it's off by default. QAM_AUTO can now be specified to achive that
* effect even if "forced_manual"=1
*/
static int forced_manual;
module_param(forced_manual, int, 0644);
MODULE_PARM_DESC(forced_manual, "if set, QAM64 and QAM256 will only lock to modulation specified");
#define DBG_INFO 1 #define DBG_INFO 1
#define DBG_REG 2 #define DBG_REG 2
#define DBG_DUMP 4 /* FGR - comment out to remove dump code */ #define DBG_DUMP 4 /* FGR - comment out to remove dump code */
...@@ -566,7 +577,12 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation) ...@@ -566,7 +577,12 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation)
/* 3. : 64QAM/256QAM detection(manual, auto) */ /* 3. : 64QAM/256QAM detection(manual, auto) */
ret = lgdt3306a_read_reg(state, 0x0009, &val); ret = lgdt3306a_read_reg(state, 0x0009, &val);
val &= 0xfc; val &= 0xfc;
val |= 0x02; /* STDOPDETCMODE[1:0]=1=Manual 2=Auto */ /* Check for forced Manual modulation modes; otherwise always "auto" */
if(forced_manual && (modulation != QAM_AUTO)){
val |= 0x01; /* STDOPDETCMODE[1:0]= 1=Manual */
} else {
val |= 0x02; /* STDOPDETCMODE[1:0]= 2=Auto */
}
ret = lgdt3306a_write_reg(state, 0x0009, val); ret = lgdt3306a_write_reg(state, 0x0009, val);
if (lg_chkerr(ret)) if (lg_chkerr(ret))
goto fail; goto fail;
...@@ -642,10 +658,9 @@ static int lgdt3306a_set_modulation(struct lgdt3306a_state *state, ...@@ -642,10 +658,9 @@ static int lgdt3306a_set_modulation(struct lgdt3306a_state *state,
ret = lgdt3306a_set_vsb(state); ret = lgdt3306a_set_vsb(state);
break; break;
case QAM_64: case QAM_64:
ret = lgdt3306a_set_qam(state, QAM_64);
break;
case QAM_256: case QAM_256:
ret = lgdt3306a_set_qam(state, QAM_256); case QAM_AUTO:
ret = lgdt3306a_set_qam(state, p->modulation);
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -672,6 +687,7 @@ static int lgdt3306a_agc_setup(struct lgdt3306a_state *state, ...@@ -672,6 +687,7 @@ static int lgdt3306a_agc_setup(struct lgdt3306a_state *state,
break; break;
case QAM_64: case QAM_64:
case QAM_256: case QAM_256:
case QAM_AUTO:
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -726,6 +742,7 @@ static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state, ...@@ -726,6 +742,7 @@ static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state,
break; break;
case QAM_64: case QAM_64:
case QAM_256: case QAM_256:
case QAM_AUTO:
/* Auto ok for QAM */ /* Auto ok for QAM */
ret = lgdt3306a_set_inversion_auto(state, 1); ret = lgdt3306a_set_inversion_auto(state, 1);
break; break;
...@@ -749,6 +766,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state, ...@@ -749,6 +766,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state,
break; break;
case QAM_64: case QAM_64:
case QAM_256: case QAM_256:
case QAM_AUTO:
if_freq_khz = state->cfg->qam_if_khz; if_freq_khz = state->cfg->qam_if_khz;
break; break;
default: default:
...@@ -1607,6 +1625,7 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe, ...@@ -1607,6 +1625,7 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe,
switch (state->current_modulation) { switch (state->current_modulation) {
case QAM_256: case QAM_256:
case QAM_64: case QAM_64:
case QAM_AUTO:
if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) { if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) {
*status |= FE_HAS_VITERBI; *status |= FE_HAS_VITERBI;
*status |= FE_HAS_SYNC; *status |= FE_HAS_SYNC;
...@@ -1650,6 +1669,7 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, ...@@ -1650,6 +1669,7 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
* Calculate some sort of "strength" from SNR * Calculate some sort of "strength" from SNR
*/ */
struct lgdt3306a_state *state = fe->demodulator_priv; struct lgdt3306a_state *state = fe->demodulator_priv;
u8 val;
u16 snr; /* snr_x10 */ u16 snr; /* snr_x10 */
int ret; int ret;
u32 ref_snr; /* snr*100 */ u32 ref_snr; /* snr*100 */
...@@ -1662,10 +1682,14 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, ...@@ -1662,10 +1682,14 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
ref_snr = 1600; /* 16dB */ ref_snr = 1600; /* 16dB */
break; break;
case QAM_64: case QAM_64:
ref_snr = 2200; /* 22dB */
break;
case QAM_256: case QAM_256:
ref_snr = 2800; /* 28dB */ case QAM_AUTO:
/* need to know actual modulation to set proper SNR baseline */
lgdt3306a_read_reg(state, 0x00a6, &val);
if(val & 0x04)
ref_snr = 2800; /* QAM-256 28dB */
else
ref_snr = 2200; /* QAM-64 22dB */
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -2136,7 +2160,7 @@ static const struct dvb_frontend_ops lgdt3306a_ops = { ...@@ -2136,7 +2160,7 @@ static const struct dvb_frontend_ops lgdt3306a_ops = {
.frequency_min = 54000000, .frequency_min = 54000000,
.frequency_max = 858000000, .frequency_max = 858000000,
.frequency_stepsize = 62500, .frequency_stepsize = 62500,
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB .caps = FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
}, },
.i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl, .i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl,
.init = lgdt3306a_init, .init = lgdt3306a_init,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment