i2c_lock_bus(state->i2c, I2C_LOCK_SEGMENT);
buf[0] = dspCodeInReg; while (pos != len) { // work out how much to send this time
tx_size = len - pos; if (tx_size > 0x10)
tx_size = 0x10;
// send the chunk
memcpy(buf + 1, mem + pos, tx_size);
fw_msg.len = tx_size + 1; if (__i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
printk(KERN_ERR "tda1004x: Error during firmware upload\n");
i2c_unlock_bus(state->i2c, I2C_LOCK_SEGMENT); return -EIO;
}
pos += tx_size;
// check upload was OK
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);
/* request the firmware, this will block until someone uploads it */
printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); if (ret) {
printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); return ret;
}
ItshouldalsobenoticedthatnootherI2Ctransfershould beincoursewhilebootingfromeeprom,otherwise,tda10046 goesintoaninstablestate.So,properlockingareneeded atthei2cbusmaster.
*/
printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
tda1004x_write_byteI(state, TDA1004X_CONFC4, 4);
msleep(300);
tda1004x_write_byteI(state, TDA1004X_CONFC4, confc4);
/* Checks if eeprom firmware went without troubles */ if (tda1004x_check_upload_ok(state) == 0) return0;
/* eeprom firmware didn't work. Load one manually. */
if (state->config->request_firmware != NULL) { /* request the firmware, this will block until someone uploads it */
printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); if (ret) { /* remain compatible to old bug: try to load with tda10045 image name */
ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); if (ret) {
printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); return ret;
} else {
printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
TDA10046_DEFAULT_FIRMWARE);
}
}
} else {
printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n"); return -EIO;
}
tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
release_firmware(fw); return tda1004x_check_upload_ok(state);
}
staticint tda1004x_encode_fec(int fec)
{ // convert known FEC values switch (fec) { case FEC_1_2: return0; case FEC_2_3: return1; case FEC_3_4: return2; case FEC_5_6: return3; case FEC_7_8: return4;
}
// set 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);
}
// Hardcoded to use auto as much as possible on the TDA10045 as it // is very unreliable if AUTO mode is _not_ used. if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
fe_params->code_rate_HP = FEC_AUTO;
fe_params->guard_interval = GUARD_INTERVAL_AUTO;
fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
}
// Set standard params.. or put them to auto if ((fe_params->code_rate_HP == FEC_AUTO) ||
(fe_params->code_rate_LP == FEC_AUTO) ||
(fe_params->modulation == QAM_AUTO) ||
(fe_params->hierarchy == HIERARCHY_AUTO)) {
tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); /* turn off modulation bits */
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits
} else {
tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto
// set HP FEC
tmp = tda1004x_encode_fec(fe_params->code_rate_HP); if (tmp < 0) return tmp;
tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
// set LP FEC
tmp = tda1004x_encode_fec(fe_params->code_rate_LP); if (tmp < 0) return tmp;
tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
/* set modulation */ switch (fe_params->modulation) { case QPSK:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); break;
case QAM_16:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1); break;
case QAM_64:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2); break;
default: return -EINVAL;
}
// set hierarchy switch (fe_params->hierarchy) { case HIERARCHY_NONE:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); break;
case HIERARCHY_1:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5); break;
case HIERARCHY_2:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5); break;
case HIERARCHY_4:
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5); break;
default: return -EINVAL;
}
}
// set bandwidth switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045:
tda10045h_set_bandwidth(state, fe_params->bandwidth_hz); break;
case TDA1004X_DEMOD_TDA10046:
tda10046h_set_bandwidth(state, fe_params->bandwidth_hz); break;
}
// set inversion
inversion = fe_params->inversion; if (state->config->invert)
inversion = inversion ? INVERSION_OFF : INVERSION_ON; switch (inversion) { case INVERSION_OFF:
tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0); break;
case INVERSION_ON:
tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20); break;
default: return -EINVAL;
}
// set guard interval switch (fe_params->guard_interval) { case GUARD_INTERVAL_1_32:
tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); break;
staticint tda1004x_read_status(struct dvb_frontend *fe, enum fe_status *fe_status)
{ struct tda1004x_state* state = fe->demodulator_priv; int status; int cber; int vber;
dprintk("%s\n", __func__);
// read status
status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); if (status == -1) return -EIO;
// decode
*fe_status = 0; if (status & 4)
*fe_status |= FE_HAS_SIGNAL; if (status & 2)
*fe_status |= FE_HAS_CARRIER; if (status & 8)
*fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
// if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi // is getting anything valid if (!(*fe_status & FE_HAS_VITERBI)) { // read the CBER
cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB); if (cber == -1) return -EIO;
status = tda1004x_read_byte(state, TDA1004X_CBER_MSB); if (status == -1) return -EIO;
cber |= (status << 8); // The address 0x20 should be read to cope with a TDA10046 bug
tda1004x_read_byte(state, TDA1004X_CBER_RESET);
if (cber != 65535)
*fe_status |= FE_HAS_VITERBI;
}
// if we DO have some valid VITERBI output, but don't already have SYNC // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid. if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { // read the VBER
vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB); if (vber == -1) return -EIO;
status = tda1004x_read_byte(state, TDA1004X_VBER_MID); if (status == -1) return -EIO;
vber |= (status << 8);
status = tda1004x_read_byte(state, TDA1004X_VBER_MSB); if (status == -1) return -EIO;
vber |= (status & 0x0f) << 16; // The CVBER_LUT should be read to cope with TDA10046 hardware bug
tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
// if RS has passed some valid TS packets, then we must be // getting some SYNC bytes if (vber < 16632)
*fe_status |= FE_HAS_SYNC;
}
staticint tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{ struct tda1004x_state* state = fe->demodulator_priv; int tmp; int tmp2; int counter;
dprintk("%s\n", __func__);
// read the UCBLOCKS and reset
counter = 0;
tmp = tda1004x_read_byte(state, TDA1004X_UNCOR); if (tmp < 0) return -EIO;
tmp &= 0x7f; while (counter++ < 5) {
tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
staticint tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
{ struct tda1004x_state* state = fe->demodulator_priv; int tmp;
dprintk("%s\n", __func__);
// read it in
tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB); if (tmp < 0) return -EIO;
*ber = tmp << 1;
tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB); if (tmp < 0) return -EIO;
*ber |= (tmp << 9); // The address 0x20 should be read to cope with a TDA10046 bug
tda1004x_read_byte(state, TDA1004X_CBER_RESET);
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); if (!state) {
printk(KERN_ERR "Can't allocate memory for tda10045 state\n"); return NULL;
}
/* setup the state */
state->config = config;
state->i2c = i2c;
state->demod_type = TDA1004X_DEMOD_TDA10045;
/* check if the demod is there */
id = tda1004x_read_byte(state, TDA1004X_CHIPID); if (id < 0) {
printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n");
kfree(state); return NULL;
}
if (id != 0x25) {
printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
kfree(state); return NULL;
}
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); if (!state) {
printk(KERN_ERR "Can't allocate memory for tda10046 state\n"); return NULL;
}
/* setup the state */
state->config = config;
state->i2c = i2c;
state->demod_type = TDA1004X_DEMOD_TDA10046;
/* check if the demod is there */
id = tda1004x_read_byte(state, TDA1004X_CHIPID); if (id < 0) {
printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n");
kfree(state); return NULL;
} if (id != 0x46) {
printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
kfree(state); return NULL;
}
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.