|
@@ -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;
|
|
|
}
|