V4L/DVB (6402): s5h1409: Fix broken QAM support
This patch enables QAM Annex-B support (US digital cable) for the s5h1409 VSB/QAM demodulator. Tested successfully with the mt2131 tuner, present on the following supported boards: Hauppauge WinTV-HVR-1250 Hauppauge WinTV-HVR-1800 Hauppauge WinTV-HVR-1800lp This patch is also known to work with an upcoming XC5000 tuner driver. Signed-off-by: Steven Toth <stoth@hauppauge.com> Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
bb8d56a4d8
commit
dd7d5013cd
|
@ -42,6 +42,9 @@ struct s5h1409_state {
|
|||
fe_modulation_t current_modulation;
|
||||
|
||||
u32 current_frequency;
|
||||
|
||||
u32 is_qam_locked;
|
||||
u32 qam_state;
|
||||
};
|
||||
|
||||
static int debug = 0;
|
||||
|
@ -94,6 +97,7 @@ static struct init_tab {
|
|||
{ 0xac, 0x1003, },
|
||||
{ 0xad, 0x103f, },
|
||||
{ 0xe2, 0x0100, },
|
||||
{ 0xe3, 0x0000, },
|
||||
{ 0x28, 0x1010, },
|
||||
{ 0xb1, 0x000e, },
|
||||
};
|
||||
|
@ -335,6 +339,8 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
|
|||
|
||||
s5h1409_writereg(state, 0xf5, 0);
|
||||
s5h1409_writereg(state, 0xf5, 1);
|
||||
state->is_qam_locked = 0;
|
||||
state->qam_state = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -349,6 +355,11 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
|
|||
s5h1409_writereg(state, 0x87, 0x01be);
|
||||
s5h1409_writereg(state, 0x88, 0x0436);
|
||||
s5h1409_writereg(state, 0x89, 0x054d);
|
||||
} else
|
||||
if (KHz == 4000) {
|
||||
s5h1409_writereg(state, 0x87, 0x014b);
|
||||
s5h1409_writereg(state, 0x88, 0x0cb5);
|
||||
s5h1409_writereg(state, 0x89, 0x03e2);
|
||||
} else {
|
||||
printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
|
||||
ret = -1;
|
||||
|
@ -361,7 +372,7 @@ static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
|
|||
{
|
||||
struct s5h1409_state* state = fe->demodulator_priv;
|
||||
|
||||
dprintk("%s()\n", __FUNCTION__);
|
||||
dprintk("%s(%d)\n", __FUNCTION__, inverted);
|
||||
|
||||
if(inverted == 1)
|
||||
return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
|
||||
|
@ -382,14 +393,10 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
|
|||
s5h1409_writereg(state, 0xf4, 0);
|
||||
break;
|
||||
case QAM_64:
|
||||
dprintk("%s() QAM_64\n", __FUNCTION__);
|
||||
s5h1409_writereg(state, 0xf4, 1);
|
||||
s5h1409_writereg(state, 0x85, 0x100);
|
||||
break;
|
||||
case QAM_256:
|
||||
dprintk("%s() QAM_256\n", __FUNCTION__);
|
||||
dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
|
||||
s5h1409_writereg(state, 0xf4, 1);
|
||||
s5h1409_writereg(state, 0x85, 0x101);
|
||||
s5h1409_writereg(state, 0x85, 0x110);
|
||||
break;
|
||||
default:
|
||||
dprintk("%s() Invalid modulation\n", __FUNCTION__);
|
||||
|
@ -423,7 +430,7 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
|
|||
if (enable)
|
||||
return s5h1409_writereg(state, 0xe3, 0x1100);
|
||||
else
|
||||
return s5h1409_writereg(state, 0xe3, 0);
|
||||
return s5h1409_writereg(state, 0xe3, 0x1000);
|
||||
}
|
||||
|
||||
static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
|
||||
|
@ -444,6 +451,66 @@ static int s5h1409_register_reset(struct dvb_frontend* fe)
|
|||
return s5h1409_writereg(state, 0xfa, 0);
|
||||
}
|
||||
|
||||
static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
|
||||
{
|
||||
struct s5h1409_state *state = fe->demodulator_priv;
|
||||
u16 reg;
|
||||
|
||||
if (state->is_qam_locked)
|
||||
return;
|
||||
|
||||
/* QAM EQ lock check */
|
||||
reg = s5h1409_readreg(state, 0xf0);
|
||||
|
||||
if ((reg >> 13) & 0x1) {
|
||||
|
||||
state->is_qam_locked = 1;
|
||||
reg &= 0xff;
|
||||
|
||||
s5h1409_writereg(state, 0x96, 0x00c);
|
||||
if ((reg < 0x38) || (reg > 0x68) ) {
|
||||
s5h1409_writereg(state, 0x93, 0x3332);
|
||||
s5h1409_writereg(state, 0x9e, 0x2c37);
|
||||
} else {
|
||||
s5h1409_writereg(state, 0x93, 0x3130);
|
||||
s5h1409_writereg(state, 0x9e, 0x2836);
|
||||
}
|
||||
|
||||
} else {
|
||||
s5h1409_writereg(state, 0x96, 0x0008);
|
||||
s5h1409_writereg(state, 0x93, 0x3332);
|
||||
s5h1409_writereg(state, 0x9e, 0x2c37);
|
||||
}
|
||||
}
|
||||
|
||||
static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
|
||||
{
|
||||
struct s5h1409_state *state = fe->demodulator_priv;
|
||||
u16 reg, reg1, reg2;
|
||||
|
||||
reg = s5h1409_readreg(state, 0xf1);
|
||||
|
||||
/* Master lock */
|
||||
if ((reg >> 15) & 0x1) {
|
||||
if (state->qam_state != 2) {
|
||||
state->qam_state = 2;
|
||||
reg1 = s5h1409_readreg(state, 0xb2);
|
||||
reg2 = s5h1409_readreg(state, 0xad);
|
||||
|
||||
s5h1409_writereg(state, 0x96, 0x20);
|
||||
s5h1409_writereg(state, 0xad,
|
||||
( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
|
||||
s5h1409_writereg(state, 0xab, 0x1100);
|
||||
}
|
||||
} else {
|
||||
if (state->qam_state != 1) {
|
||||
state->qam_state = 1;
|
||||
s5h1409_writereg(state, 0x96, 0x08);
|
||||
s5h1409_writereg(state, 0xab, 0x1101);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
|
||||
static int s5h1409_set_frontend (struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *p)
|
||||
|
@ -458,12 +525,21 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
|
|||
|
||||
s5h1409_enable_modulation(fe, p->u.vsb.modulation);
|
||||
|
||||
/* Allow the demod to settle */
|
||||
msleep(100);
|
||||
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
fe->ops.tuner_ops.set_params(fe, p);
|
||||
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
/* Optimize the demod for QAM */
|
||||
if (p->u.vsb.modulation != VSB_8) {
|
||||
s5h1409_set_qam_amhum_mode(fe);
|
||||
s5h1409_set_qam_interleave_mode(fe);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -495,8 +571,8 @@ static int s5h1409_init (struct dvb_frontend* fe)
|
|||
s5h1409_set_gpio(fe, state->config->gpio);
|
||||
s5h1409_softreset(fe);
|
||||
|
||||
/* Note: Leaving the I2C gate open here. */
|
||||
s5h1409_i2c_gate_ctrl(fe, 1);
|
||||
/* Note: Leaving the I2C gate closed. */
|
||||
s5h1409_i2c_gate_ctrl(fe, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue