diff options
author | Michael Krufky <devnull@localhost> | 2005-08-07 09:26:42 +0000 |
---|---|---|
committer | Michael Krufky <devnull@localhost> | 2005-08-07 09:26:42 +0000 |
commit | e837424b7588e90eecf1d316b9f22a781838d6f7 (patch) | |
tree | b899d404761c67ec31c5ee3a0b7c7fd49fd00909 /linux/drivers/media/dvb/frontends/lgdt330x.c | |
parent | 152e8a05cd1c10a664e5b9ced2f26463ff0b8e6a (diff) | |
download | mediapointer-dvb-s2-e837424b7588e90eecf1d316b9f22a781838d6f7.tar.gz mediapointer-dvb-s2-e837424b7588e90eecf1d316b9f22a781838d6f7.tar.bz2 |
- Enable ATSC support for DViCO FusionHDTV5 Gold.
From: Mac Michaels <wmichaels1@earthlink.net>
Signed-off-by: Michael Krufky <mkrufky@m1k.net>
- Enable ATSC support for DViCO FusionHDTV5 Gold.
From: Mac Michaels <wmichaels1@earthlink.net>
Signed-off-by: Michael Krufky <mkrufky@m1k.net>
Diffstat (limited to 'linux/drivers/media/dvb/frontends/lgdt330x.c')
-rw-r--r-- | linux/drivers/media/dvb/frontends/lgdt330x.c | 278 |
1 files changed, 186 insertions, 92 deletions
diff --git a/linux/drivers/media/dvb/frontends/lgdt330x.c b/linux/drivers/media/dvb/frontends/lgdt330x.c index 028102b91..181c7859f 100644 --- a/linux/drivers/media/dvb/frontends/lgdt330x.c +++ b/linux/drivers/media/dvb/frontends/lgdt330x.c @@ -93,24 +93,6 @@ static int i2c_write_demod_bytes (struct lgdt330x_state* state, return 0; } -#if 0 -static int i2c_readbytes (struct lgdt330x_state* state, - u8 addr, /* demod_address or pll_address */ - u8 *buf, /* holds data bytes read */ - int len /* number of bytes to read */ ) -{ - struct i2c_msg msg = - { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; - int err; - - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt330x: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err); - return -EREMOTEIO; - } - return 0; -} -#endif - /* * This routine writes the register (reg) to the demod bus * then reads the data returned for (len) bytes. @@ -137,7 +119,7 @@ static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, } /* Software reset */ -int lgdt330x_SwReset(struct lgdt330x_state* state) +static int lgdt3302_SwReset(struct lgdt330x_state* state) { u8 ret; u8 reset[] = { @@ -149,18 +131,80 @@ int lgdt330x_SwReset(struct lgdt330x_state* state) ret = i2c_write_demod_bytes(state, reset, sizeof(reset)); if (ret == 0) { - /* spec says reset takes 100 ns why wait */ - /* mdelay(100); */ /* keep low for 100mS */ - reset[1] = 0x7f; /* force reset high (inactive) - * and unmask interrupts */ + + /* force reset high (inactive) and unmask interrupts */ + reset[1] = 0x7f; ret = i2c_write_demod_bytes(state, reset, sizeof(reset)); } - /* Spec does not indicate a need for this either */ - /*mdelay(5); */ /* wait 5 msec before doing more */ return ret; } +static int lgdt3303_SwReset(struct lgdt330x_state* state) +{ + u8 ret; + u8 reset[] = { + 0x02, + 0x00 /* bit 0 is active low software reset */ + }; + + ret = i2c_write_demod_bytes(state, + reset, sizeof(reset)); + if (ret == 0) { + + /* force reset high (inactive) */ + reset[1] = 0x01; + ret = i2c_write_demod_bytes(state, + reset, sizeof(reset)); + } + return ret; +} + +static int lgdt330x_SwReset(struct lgdt330x_state* state) +{ + switch (state->config->demod_chip) { + case LGDT3302: + return lgdt3302_SwReset(state); + case LGDT3303: + return lgdt3303_SwReset(state); + default: + return -ENODEV; + } +} + +#ifdef MUTE_TDA9887 +static int i2c_write_ntsc_demod (struct lgdt330x_state* state, u8 buf[2]) +{ + struct i2c_msg msg = + { .addr = 0x43, + .flags = 0, + .buf = buf, + .len = 2 }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, msg.buf[0], msg.buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + return 0; +} + +static void fiddle_with_ntsc_if_demod(struct lgdt330x_state* state) +{ + // Experimental code + u8 buf0[] = {0x00, 0x20}; + u8 buf1[] = {0x01, 0x00}; + u8 buf2[] = {0x02, 0x00}; + + i2c_write_ntsc_demod(state, buf0); + i2c_write_ntsc_demod(state, buf1); + i2c_write_ntsc_demod(state, buf2); +} +#endif + static int lgdt330x_init(struct dvb_frontend* fe) { /* Hardware reset is done using gpio[0] of cx23880x chip. @@ -174,6 +218,7 @@ static int lgdt330x_init(struct dvb_frontend* fe) * to initialize each different chip */ static u8 lgdt3302_init_data[] = { + /* Use 50MHz parameter values from spec sheet since xtal is 50 */ /* Change the value of NCOCTFV[25:0] of carrier recovery center frequency register */ VSB_CARRIER_FREQ0, 0x00, @@ -211,26 +256,8 @@ static int lgdt330x_init(struct dvb_frontend* fe) struct lgdt330x_state* state = fe->demodulator_priv; char *chip_name; int err; -#if 0 - u8 buf[1]; - - if (state->config->chip == UNDEFINED) { - /* Figure out which chip is on the card */ - err = i2c_read_demod_bytes(state, IRQ_MASK, buf, sizeof(buf)); - if (err != 1) - return err; - /* Test LGDT3302 software reset bit. It is unused in LGDT3303 */ - if ((buf[0] & 0x40) == 0x40) - state->config->chip = LGDT3302; - - /* Test LGDT3303 factory and test bits. - At startup they are set to 0 in LGDT3302 */ - else if ((buf[0] & 0x0f) == 0x02) - state->config->chip = LGDT3303; - } -#endif - switch (state->config->chip) { + switch (state->config->demod_chip) { case LGDT3302: chip_name = "LGDT3302"; err = i2c_write_demod_bytes(state, lgdt3302_init_data, @@ -240,6 +267,9 @@ static int lgdt330x_init(struct dvb_frontend* fe) chip_name = "LGDT3303"; err = i2c_write_demod_bytes(state, lgdt3303_init_data, sizeof(lgdt3303_init_data)); +#ifdef MUTE_TDA9887 + fiddle_with_ntsc_if_demod(state); +#endif break; default: chip_name = "undefined"; @@ -264,7 +294,7 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) int err; u8 buf[2]; - switch (state->config->chip) { + switch (state->config->demod_chip) { case LGDT3302: err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, buf, sizeof(buf)); @@ -290,7 +320,8 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, * Array of byte pairs <address, value> * to initialize 8VSB for lgdt3303 chip 50 MHz IF */ - static u8 lgdt3303_8vsb_50_data[] = { + static u8 lgdt3303_8vsb_44_data[] = { + 0x04, 0x00, 0x0d, 0x40, 0x0e, 0x87, 0x0f, 0x8e, @@ -302,6 +333,7 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, * to initialize QAM for lgdt3303 chip */ static u8 lgdt3303_qam_data[] = { + 0x04, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, @@ -315,7 +347,6 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, struct lgdt330x_state* state = fe->demodulator_priv; - /* Use 50MHz parameter values from spec sheet since xtal is 50 */ static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; int err; @@ -332,9 +363,9 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, if (state->config->pll_rf_set) state->config->pll_rf_set(fe, 1); - if (state->config->chip == LGDT3303) { - err = i2c_write_demod_bytes(state, lgdt3303_8vsb_50_data, - sizeof(lgdt3303_8vsb_50_data)); + if (state->config->demod_chip == LGDT3303) { + err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data, + sizeof(lgdt3303_8vsb_44_data)); } break; @@ -348,7 +379,7 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, if (state->config->pll_rf_set) state->config->pll_rf_set(fe, 0); - if (state->config->chip == LGDT3303) { + if (state->config->demod_chip == LGDT3303) { err = i2c_write_demod_bytes(state, lgdt3303_qam_data, sizeof(lgdt3303_qam_data)); } @@ -364,7 +395,7 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, if (state->config->pll_rf_set) state->config->pll_rf_set(fe, 0); - if (state->config->chip == LGDT3303) { + if (state->config->demod_chip == LGDT3303) { err = i2c_write_demod_bytes(state, lgdt3303_qam_data, sizeof(lgdt3303_qam_data)); } @@ -373,9 +404,12 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation); return -1; } - - /* select serial or parallel MPEG harware interface */ - top_ctrl_cfg[1] |= state->config->serial_mpeg << 2; + /* + * select serial or parallel MPEG harware interface + * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 + * Parallel: 0x00 + */ + top_ctrl_cfg[1] |= state->config->serial_mpeg; /* Select the requested mode */ i2c_write_demod_bytes(state, top_ctrl_cfg, @@ -403,10 +437,13 @@ static int lgdt330x_get_frontend(struct dvb_frontend* fe, return 0; } -static int lgdt3302_read_status(struct lgdt330x_state* state, fe_status_t* status) +static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) { + struct lgdt330x_state* state = fe->demodulator_priv; u8 buf[3]; + *status = 0; /* Reset status result */ + /* AGC status register */ i2c_read_demod_bytes(state, AGC_STATUS, buf, 1); dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); @@ -467,10 +504,13 @@ static int lgdt3302_read_status(struct lgdt330x_state* state, fe_status_t* statu return 0; } -static int lgdt3303_read_status(struct lgdt330x_state* state, fe_status_t* status) +static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) { - u8 buf[3]; + struct lgdt330x_state* state = fe->demodulator_priv; int err; + u8 buf[3]; + + *status = 0; /* Reset status result */ /* lgdt3303 AGC status register */ err = i2c_read_demod_bytes(state, 0x58, buf, 1); @@ -496,6 +536,8 @@ static int lgdt3303_read_status(struct lgdt330x_state* state, fe_status_t* statu /* Need to undestand why there are 3 lock levels here */ if ((buf[0] & 0x07) == 0x07) *status |= FE_HAS_CARRIER; + else + break; i2c_read_demod_bytes(state, 0x8a, buf, 1); if ((buf[0] & 0x04) == 0x04) *status |= FE_HAS_SYNC; @@ -507,8 +549,10 @@ static int lgdt3303_read_status(struct lgdt330x_state* state, fe_status_t* statu case VSB_8: if ((buf[0] & 0x80) == 0x80) *status |= FE_HAS_CARRIER; + else + break; i2c_read_demod_bytes(state, 0x38, buf, 1); - if ((buf[0] & 0x02) == 0x02) + if ((buf[0] & 0x02) == 0x00) *status |= FE_HAS_SYNC; if ((buf[0] & 0x01) == 0x01) { *status |= FE_HAS_LOCK; @@ -521,28 +565,6 @@ static int lgdt3303_read_status(struct lgdt330x_state* state, fe_status_t* statu return 0; } -static int lgdt330x_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - struct lgdt330x_state* state = fe->demodulator_priv; - int err; - - *status = 0; /* Reset status result */ - - switch (state->config->chip) { - case LGDT3302: - err = lgdt3302_read_status(state, status); - break; - case LGDT3303: - err = lgdt3303_read_status(state, status); - break; - default: - printk(KERN_WARNING - "Only LGDT3302 and LGDT3303 are supported chips.\n"); - err = -ENODEV; - } - return err; -} - static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) { /* not directly available. */ @@ -550,7 +572,7 @@ static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) return 0; } -static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) +static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) { #ifdef SNR_IN_DB /* @@ -607,7 +629,7 @@ static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) static u32 snr_db; /* index into SNR_EQ[] */ struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; - /* read both equalizer and pase tracker noise data */ + /* read both equalizer and phase tracker noise data */ i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf)); if (state->current_modulation == VSB_8) { @@ -647,16 +669,22 @@ static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf)); if (state->current_modulation == VSB_8) { +#if 0 /* Equalizer Mean-Square Error Register for VSB */ noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; - } else { - /* Phase Tracker Mean-Square Error Register for QAM */ +#else + /* Phase Tracker Mean-Square Error Register for VSB */ noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; +#endif + } else { + + /* Carrier Recovery Mean-Square Error for QAM */ + i2c_read_demod_bytes(state, 0x1a, buf, 2); + noise = ((buf[0] & 3) << 8) | buf[1]; } /* Small values for noise mean signal is better so invert noise */ - /* Noise is 19 bit value so discard 3 LSB*/ - *snr = ~noise>>3; + *snr = ~noise; #endif dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); @@ -664,6 +692,37 @@ static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) return 0; } +static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) +{ + /* Return the raw noise value */ + static u8 buf[5];/* read data buffer */ + static u32 noise; /* noise value */ + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; + + if (state->current_modulation == VSB_8) { + +#if 0 + /* Equalizer Mean-Square Error Register for VSB */ + noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2]; +#else + /* Phase Tracker Mean-Square Error Register for VSB */ + noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; +#endif + } else { + + /* Carrier Recovery Mean-Square Error for QAM */ + i2c_read_demod_bytes(state, 0x1a, buf, 2); + noise = (buf[0] << 8) | buf[1]; + } + + /* Small values for noise mean signal is better so invert noise */ + *snr = ~noise; + + dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); + + return 0; +} + static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) { /* I have no idea about this - it may not be needed */ @@ -679,7 +738,8 @@ static void lgdt330x_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops lgdt330x_ops; +static struct dvb_frontend_ops lgdt3302_ops; +static struct dvb_frontend_ops lgdt3303_ops; struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, struct i2c_adapter* i2c) @@ -696,7 +756,17 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, /* Setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &lgdt330x_ops, sizeof(struct dvb_frontend_ops)); + switch (config->demod_chip) { + case LGDT3302: + memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); + break; + case LGDT3303: + memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops)); + break; + default: + goto error; + } + /* Verify communication with demod chip */ if (i2c_read_demod_bytes(state, 2, buf, 1)) goto error; @@ -716,7 +786,7 @@ error: return NULL; } -static struct dvb_frontend_ops lgdt330x_ops = { +static struct dvb_frontend_ops lgdt3302_ops = { .info = { .name= "LG Electronics LGDT3302/LGDT3303 VSB/QAM Frontend", .type = FE_ATSC, @@ -732,10 +802,34 @@ static struct dvb_frontend_ops lgdt330x_ops = { .set_frontend = lgdt330x_set_parameters, .get_frontend = lgdt330x_get_frontend, .get_tune_settings = lgdt330x_get_tune_settings, - .read_status = lgdt330x_read_status, + .read_status = lgdt3302_read_status, + .read_ber = lgdt330x_read_ber, + .read_signal_strength = lgdt330x_read_signal_strength, + .read_snr = lgdt3302_read_snr, + .read_ucblocks = lgdt330x_read_ucblocks, + .release = lgdt330x_release, +}; + +static struct dvb_frontend_ops lgdt3303_ops = { + .info = { + .name= "LG Electronics LGDT3303 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min= 54000000, + .frequency_max= 858000000, + .frequency_stepsize= 62500, + /* Symbol rate is for all VSB modes need to check QAM */ + .symbol_rate_min = 10762000, + .symbol_rate_max = 10762000, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt330x_init, + .set_frontend = lgdt330x_set_parameters, + .get_frontend = lgdt330x_get_frontend, + .get_tune_settings = lgdt330x_get_tune_settings, + .read_status = lgdt3303_read_status, .read_ber = lgdt330x_read_ber, .read_signal_strength = lgdt330x_read_signal_strength, - .read_snr = lgdt330x_read_snr, + .read_snr = lgdt3303_read_snr, .read_ucblocks = lgdt330x_read_ucblocks, .release = lgdt330x_release, }; |