Commit 0eb3de20 authored by Hartmut Hackmann's avatar Hartmut Hackmann Committed by Mauro Carvalho Chehab

V4L/DVB (3304): TDA10046 Driver update

- Set outputs to tristate in sleep mode
- Reduce dangerously high firmware download speed with 16MHz xtal
- added tda827x configuration with GPIOs low
- added comments to stupid looking IIC reads that work around bugs in
  the tda10046.
- some minor updates
Signed-off-by: default avatarHartmut Hackmann <hartmut.hackmann@t-online.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 0157a9cc
...@@ -229,7 +229,7 @@ static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state) ...@@ -229,7 +229,7 @@ static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
dprintk("%s\n", __FUNCTION__); dprintk("%s\n", __FUNCTION__);
result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2); result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
msleep(1); msleep(20);
return result; return result;
} }
...@@ -502,7 +502,12 @@ static int tda10046_fwupload(struct dvb_frontend* fe) ...@@ -502,7 +502,12 @@ static int tda10046_fwupload(struct dvb_frontend* fe)
const struct firmware *fw; const struct firmware *fw;
/* reset + wake up chip */ /* reset + wake up chip */
if (state->config->xtal_freq == TDA10046_XTAL_4M) {
tda1004x_write_byteI(state, TDA1004X_CONFC4, 0); tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
} else {
dprintk("%s: 16MHz Xtal, reducing I2C speed\n", __FUNCTION__);
tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
}
tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
/* let the clocks recover from sleep */ /* let the clocks recover from sleep */
msleep(5); msleep(5);
...@@ -651,7 +656,7 @@ static int tda10046_init(struct dvb_frontend* fe) ...@@ -651,7 +656,7 @@ static int tda10046_init(struct dvb_frontend* fe)
// tda setup // tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream
tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88); // enable pulse killer
switch (state->config->agc_config) { switch (state->config->agc_config) {
case TDA10046_AGC_DEFAULT: case TDA10046_AGC_DEFAULT:
...@@ -672,6 +677,12 @@ static int tda10046_init(struct dvb_frontend* fe) ...@@ -672,6 +677,12 @@ static int tda10046_init(struct dvb_frontend* fe)
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
break; break;
case TDA10046_AGC_TDA827X_GPL:
tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
break;
} }
tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
...@@ -683,6 +694,7 @@ static int tda10046_init(struct dvb_frontend* fe) ...@@ -683,6 +694,7 @@ static int tda10046_init(struct dvb_frontend* fe)
tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
// tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes
tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
state->initialised = 1; state->initialised = 1;
...@@ -1027,6 +1039,7 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status ...@@ -1027,6 +1039,7 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status
if (status == -1) if (status == -1)
return -EIO; return -EIO;
cber |= (status << 8); cber |= (status << 8);
// The address 0x20 should be read to cope with a TDA10046 bug
tda1004x_read_byte(state, TDA1004X_CBER_RESET); tda1004x_read_byte(state, TDA1004X_CBER_RESET);
if (cber != 65535) if (cber != 65535)
...@@ -1047,7 +1060,8 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status ...@@ -1047,7 +1060,8 @@ static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status
status = tda1004x_read_byte(state, TDA1004X_VBER_MSB); status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
if (status == -1) if (status == -1)
return -EIO; return -EIO;
vber |= ((status << 16) & 0x0f); vber |= (status & 0x0f) << 16;
// The CVBER_LUT should be read to cope with TDA10046 hardware bug
tda1004x_read_byte(state, TDA1004X_CVBER_LUT); tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
// if RS has passed some valid TS packets, then we must be // if RS has passed some valid TS packets, then we must be
...@@ -1161,6 +1175,7 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) ...@@ -1161,6 +1175,7 @@ static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
if (tmp < 0) if (tmp < 0)
return -EIO; return -EIO;
*ber |= (tmp << 9); *ber |= (tmp << 9);
// The address 0x20 should be read to cope with a TDA10046 bug
tda1004x_read_byte(state, TDA1004X_CBER_RESET); tda1004x_read_byte(state, TDA1004X_CBER_RESET);
dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber); dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
...@@ -1187,6 +1202,8 @@ static int tda1004x_sleep(struct dvb_frontend* fe) ...@@ -1187,6 +1202,8 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
tda1004x_disable_tuner_i2c(state); tda1004x_disable_tuner_i2c(state);
} }
} }
/* set outputs to tristate */
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
break; break;
} }
......
...@@ -36,6 +36,7 @@ enum tda10046_agc { ...@@ -36,6 +36,7 @@ enum tda10046_agc {
TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */
TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */
TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */
TDA10046_AGC_TDA827X_GPL, /* same as above, but GPIOs 0 */
}; };
enum tda10046_if { enum tda10046_if {
......
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