提交 dd7d5013 编写于 作者: S Steven Toth 提交者: Mauro Carvalho Chehab

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: NSteven Toth <stoth@hauppauge.com>
Signed-off-by: NMichael Krufky <mkrufky@linuxtv.org>
Signed-off-by: NMauro Carvalho Chehab <mchehab@infradead.org>
上级 bb8d56a4
...@@ -42,6 +42,9 @@ struct s5h1409_state { ...@@ -42,6 +42,9 @@ struct s5h1409_state {
fe_modulation_t current_modulation; fe_modulation_t current_modulation;
u32 current_frequency; u32 current_frequency;
u32 is_qam_locked;
u32 qam_state;
}; };
static int debug = 0; static int debug = 0;
...@@ -94,6 +97,7 @@ static struct init_tab { ...@@ -94,6 +97,7 @@ static struct init_tab {
{ 0xac, 0x1003, }, { 0xac, 0x1003, },
{ 0xad, 0x103f, }, { 0xad, 0x103f, },
{ 0xe2, 0x0100, }, { 0xe2, 0x0100, },
{ 0xe3, 0x0000, },
{ 0x28, 0x1010, }, { 0x28, 0x1010, },
{ 0xb1, 0x000e, }, { 0xb1, 0x000e, },
}; };
...@@ -335,6 +339,8 @@ static int s5h1409_softreset(struct dvb_frontend* fe) ...@@ -335,6 +339,8 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
s5h1409_writereg(state, 0xf5, 0); s5h1409_writereg(state, 0xf5, 0);
s5h1409_writereg(state, 0xf5, 1); s5h1409_writereg(state, 0xf5, 1);
state->is_qam_locked = 0;
state->qam_state = 0;
return 0; return 0;
} }
...@@ -349,6 +355,11 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) ...@@ -349,6 +355,11 @@ static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
s5h1409_writereg(state, 0x87, 0x01be); s5h1409_writereg(state, 0x87, 0x01be);
s5h1409_writereg(state, 0x88, 0x0436); s5h1409_writereg(state, 0x88, 0x0436);
s5h1409_writereg(state, 0x89, 0x054d); 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 { } else {
printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
ret = -1; ret = -1;
...@@ -361,7 +372,7 @@ static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) ...@@ -361,7 +372,7 @@ static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
{ {
struct s5h1409_state* state = fe->demodulator_priv; struct s5h1409_state* state = fe->demodulator_priv;
dprintk("%s()\n", __FUNCTION__); dprintk("%s(%d)\n", __FUNCTION__, inverted);
if(inverted == 1) if(inverted == 1)
return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */ return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
...@@ -382,14 +393,10 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, ...@@ -382,14 +393,10 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
s5h1409_writereg(state, 0xf4, 0); s5h1409_writereg(state, 0xf4, 0);
break; break;
case QAM_64: case QAM_64:
dprintk("%s() QAM_64\n", __FUNCTION__);
s5h1409_writereg(state, 0xf4, 1);
s5h1409_writereg(state, 0x85, 0x100);
break;
case QAM_256: 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, 0xf4, 1);
s5h1409_writereg(state, 0x85, 0x101); s5h1409_writereg(state, 0x85, 0x110);
break; break;
default: default:
dprintk("%s() Invalid modulation\n", __FUNCTION__); dprintk("%s() Invalid modulation\n", __FUNCTION__);
...@@ -423,7 +430,7 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) ...@@ -423,7 +430,7 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
if (enable) if (enable)
return s5h1409_writereg(state, 0xe3, 0x1100); return s5h1409_writereg(state, 0xe3, 0x1100);
else else
return s5h1409_writereg(state, 0xe3, 0); return s5h1409_writereg(state, 0xe3, 0x1000);
} }
static int s5h1409_sleep(struct dvb_frontend* fe, int enable) static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
...@@ -444,6 +451,66 @@ static int s5h1409_register_reset(struct dvb_frontend* fe) ...@@ -444,6 +451,66 @@ static int s5h1409_register_reset(struct dvb_frontend* fe)
return s5h1409_writereg(state, 0xfa, 0); 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 */ /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
static int s5h1409_set_frontend (struct dvb_frontend* fe, static int s5h1409_set_frontend (struct dvb_frontend* fe,
struct dvb_frontend_parameters *p) struct dvb_frontend_parameters *p)
...@@ -458,12 +525,21 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe, ...@@ -458,12 +525,21 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
s5h1409_enable_modulation(fe, p->u.vsb.modulation); 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.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
fe->ops.tuner_ops.set_params(fe, p); fe->ops.tuner_ops.set_params(fe, p);
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 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; return 0;
} }
...@@ -495,8 +571,8 @@ static int s5h1409_init (struct dvb_frontend* fe) ...@@ -495,8 +571,8 @@ static int s5h1409_init (struct dvb_frontend* fe)
s5h1409_set_gpio(fe, state->config->gpio); s5h1409_set_gpio(fe, state->config->gpio);
s5h1409_softreset(fe); s5h1409_softreset(fe);
/* Note: Leaving the I2C gate open here. */ /* Note: Leaving the I2C gate closed. */
s5h1409_i2c_gate_ctrl(fe, 1); s5h1409_i2c_gate_ctrl(fe, 0);
return 0; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册