/* Demodulator private data */ enum fe_modulation current_modulation;
u32 snr; /* Result of last SNR calculation */
u16 ucblocks; unsignedlong last_stats_time;
/* Tuner private data */
u32 current_frequency;
};
staticint i2c_write_demod_bytes(struct lgdt330x_state *state, const u8 *buf, /* data bytes to send */ int len /* number of bytes to send */)
{ int i; int err;
for (i = 0; i < len - 1; i += 2) {
err = i2c_master_send(state->client, buf, 2); if (err != 2) {
dev_warn(&state->client->dev, "%s: error (addr %02x <- %02x, err = %i)\n",
__func__, buf[0], buf[1], err); if (err < 0) return err; else return -EREMOTEIO;
}
buf += 2;
} return 0;
}
/* * This routine writes the register (reg) to the demod bus * then reads the data returned for (len) bytes.
*/ staticint i2c_read_demod_bytes(struct lgdt330x_state *state, enum I2C_REG reg, u8 *buf, int len)
{
u8 wr[] = { reg }; struct i2c_msg msg[] = {
{
.addr = state->client->addr,
.flags = 0,
.buf = wr,
.len = 1
}, {
.addr = state->client->addr,
.flags = I2C_M_RD,
.buf = buf,
.len = len
},
}; int ret;
ret = i2c_transfer(state->client->adapter, msg, 2); if (ret != 2) {
dev_warn(&state->client->dev, "%s: addr 0x%02x select 0x%02x error (ret == %i)\n",
__func__, state->client->addr, reg, ret); if (ret >= 0)
ret = -EIO;
} else {
ret = 0;
} return ret;
}
/* Software reset */ staticint lgdt3302_sw_reset(struct lgdt330x_state *state)
{
u8 ret;
u8 reset[] = {
IRQ_MASK, /* * bit 6 is active low software reset * bits 5-0 are 1 to mask interrupts
*/
0x00
};
ret = i2c_write_demod_bytes(state,
reset, sizeof(reset)); if (ret == 0) { /* force reset high (inactive) and unmask interrupts */
reset[1] = 0x7f;
ret = i2c_write_demod_bytes(state,
reset, sizeof(reset));
} return ret;
}
staticint lgdt3303_sw_reset(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;
}
staticint lgdt330x_init(struct dvb_frontend *fe)
{ struct lgdt330x_state *state = fe->demodulator_priv; struct dtv_frontend_properties *p = &fe->dtv_property_cache; char *chip_name; int err; /* * Array of byte pairs <address, value> * to initialize each different chip
*/ staticconst u8 lgdt3302_init_data[] = { /* Use 50MHz param 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,
VSB_CARRIER_FREQ1, 0x87,
VSB_CARRIER_FREQ2, 0x8e,
VSB_CARRIER_FREQ3, 0x01, /* * Change the TPCLK pin polarity * data is valid on falling clock
*/
DEMUX_CONTROL, 0xfb, /* * Change the value of IFBW[11:0] of * AGC IF/RF loop filter bandwidth register
*/
AGC_RF_BANDWIDTH0, 0x40,
AGC_RF_BANDWIDTH1, 0x93,
AGC_RF_BANDWIDTH2, 0x00, /* * Change the value of bit 6, 'nINAGCBY' and * 'NSSEL[1:0] of ACG function control register 2
*/
AGC_FUNC_CTRL2, 0xc6, /* * Change the value of bit 6 'RFFIX' * of AGC function control register 3
*/
AGC_FUNC_CTRL3, 0x40, /* * Set the value of 'INLVTHD' register 0x2a/0x2c * to 0x7fe
*/
AGC_DELAY0, 0x07,
AGC_DELAY2, 0xfe, /* * Change the value of IAGCBW[15:8] * of inner AGC loop filter bandwidth
*/
AGC_LOOP_BANDWIDTH0, 0x08,
AGC_LOOP_BANDWIDTH1, 0x9a
}; staticconst u8 lgdt3303_init_data[] = {
0x4c, 0x14
}; staticconst u8 flip_1_lgdt3303_init_data[] = {
0x4c, 0x14,
0x87, 0xf3
}; staticconst u8 flip_2_lgdt3303_init_data[] = {
0x4c, 0x14,
0x87, 0xda
};
/* * Hardware reset is done using gpio[0] of cx23880x chip. * I'd like to do it here, but don't know how to find chip address. * cx88-cards.c arranges for the reset bit to be inactive (high). * Maybe there needs to be a callable function in cx88-core or * the caller of this function needs to do it.
*/
switch (state->config.demod_chip) { case LGDT3302:
chip_name = "LGDT3302";
err = i2c_write_demod_bytes(state, lgdt3302_init_data, sizeof(lgdt3302_init_data)); break; case LGDT3303:
chip_name = "LGDT3303"; switch (state->config.clock_polarity_flip) { case 2:
err = i2c_write_demod_bytes(state,
flip_2_lgdt3303_init_data, sizeof(flip_2_lgdt3303_init_data)); break; case 1:
err = i2c_write_demod_bytes(state,
flip_1_lgdt3303_init_data, sizeof(flip_1_lgdt3303_init_data)); break; case 0: default:
err = i2c_write_demod_bytes(state, lgdt3303_init_data, sizeof(lgdt3303_init_data));
} break; default:
chip_name = "undefined";
dev_warn(&state->client->dev, "Only LGDT3302 and LGDT3303 are supported chips.\n");
err = -ENODEV;
}
dprintk(state, "Initialized the %s chip\n", chip_name); if (err < 0) return err;
int err = 0; /* Change only if we are actually changing the modulation */ if (state->current_modulation != p->modulation) { switch (p->modulation) { case VSB_8:
dprintk(state, "VSB_8 MODE\n");
/* Select VSB mode */
top_ctrl_cfg[1] = 0x03;
/* Select ANT connector if supported by card */ if (state->config.pll_rf_set)
state->config.pll_rf_set(fe, 1);
/* Select CABLE connector if supported by card */ if (state->config.pll_rf_set)
state->config.pll_rf_set(fe, 0);
if (state->config.demod_chip == LGDT3303) {
err = i2c_write_demod_bytes(state,
lgdt3303_qam_data, sizeof(lgdt3303_qam_data));
} break; default:
dev_warn(&state->client->dev, "%s: Modulation type(%d) UNSUPPORTED\n",
__func__, p->modulation); return -1;
} if (err < 0)
dev_warn(&state->client->dev, "%s: error blasting bytes to lgdt3303 for modulation type(%d)\n",
__func__, p->modulation);
/* * select serial or parallel MPEG hardware 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, sizeof(top_ctrl_cfg)); if (state->config.set_ts_params)
state->config.set_ts_params(fe, 0);
state->current_modulation = p->modulation;
}
/* Tune to the specified frequency */ if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
/* Keep track of the new frequency */ /* * FIXME this is the wrong way to do this... * The tuner is shared with the video4linux analog API
*/
state->current_frequency = p->frequency;
/* * Calculate SNR estimation (scaled by 2^24) * * 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM * equations from LGDT3303 datasheet. VSB is the same between the '02 * and '03, so maybe QAM is too? Perhaps someone with a newer datasheet * that has QAM information could verify? * * For 8-VSB: (two ways, take your pick) * LGDT3302: * SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE) * LGDT3303: * SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE) * LGDT3302 & LGDT3303: * SNR_PT = 10 * log10(25 * 32^2 / PT_MSE) (we use this one) * For 64-QAM: * SNR = 10 * log10( 688128 / MSEQAM) * For 256-QAM: * SNR = 10 * log10( 696320 / MSEQAM) * * We re-write the snr equation as: * SNR * 2^24 = 10*(c - intlog10(MSE)) * Where for 256-QAM, c = log10(696320) * 2^24, and so on.
*/ static u32 calculate_snr(u32 mse, u32 c)
{ if (mse == 0) /* No signal */ return 0;
mse = intlog10(mse); if (mse > c) { /* * Negative SNR, which is possible, but realisticly the * demod will lose lock before the signal gets this bad. * The API only allows for unsigned values, so just return 0
*/ return 0;
} return 10 * (c - mse);
}
*snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */
return 0;
}
staticint lgdt330x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{ /* Calculate Strength from SNR up to 35dB */ /* * Even though the SNR can go higher than 35dB, there is some comfort * factor in having a range of strong signals that can show at 100%
*/ struct lgdt330x_state *state = fe->demodulator_priv;
u16 snr; int ret;
ret = fe->ops.read_snr(fe, &snr); if (ret != 0) return ret; /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ /* scale the range 0 - 35*2^24 into 0 - 65535 */ if (state->snr >= 8960 * 0x10000)
*strength = 0xffff; else
*strength = state->snr / 8960;
/* AGC status register */
i2c_read_demod_bytes(state, AGC_STATUS, buf, 1);
dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]); if ((buf[0] & 0x0c) == 0x8) { /* * Test signal does not exist flag * as well as the AGC lock flag.
*/
*status |= FE_HAS_SIGNAL;
}
/* * You must set the Mask bits to 1 in the IRQ_MASK in order * to see that status bit in the IRQ_STATUS register. * This is done in SwReset();
*/
/* lgdt3303 AGC status register */
err = i2c_read_demod_bytes(state, 0x58, buf, 1); if (err < 0) return err;
dprintk(state, "AGC_STATUS = 0x%02x\n", buf[0]); if ((buf[0] & 0x21) == 0x01) { /* * Test input signal does not exist flag * as well as the AGC lock flag.
*/
*status |= FE_HAS_SIGNAL;
}
/* Carrier Recovery Lock Status Register */
i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1);
dprintk(state, "CARRIER_LOCK = 0x%02x\n", buf[0]); switch (state->current_modulation) { case QAM_256: case QAM_64: /* Need to understand 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);
dprintk(state, "QAM LOCK = 0x%02x\n", buf[0]);
staticint
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 */
fe_tune_settings->min_delay_ms = 500;
fe_tune_settings->step_size = 0;
fe_tune_settings->max_drift = 0; return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.