// SPDX-License-Identifier: GPL-2.0-or-later /* Driver for Philips tda1004xh OFDM Demodulator
(c) 2003, 2004 Andrew de Quincey & Robert Schlabbach
*/ /* * This driver needs external firmware. Please use the commands * "<kerneldir>/scripts/get_dvb_firmware tda10045", * "<kerneldir>/scripts/get_dvb_firmware tda10046" to * download/extract them, and then copy them to /usr/lib/hotplug/firmware * or /lib/firmware (depending on configuration of firmware hotplug).
*/ #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw" #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw"
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;
}
/* For i2c normal work, we need to slow down the bus speed. However, the slow down breaks the eeprom firmware load. So, use normal speed for eeprom booting and then restore the i2c speed after that. Tested with MSI TV @nyware A/D board, that comes with firmware version 29 inside their eeprom.
It should also be noticed that no other I2C transfer should be in course while booting from eeprom, otherwise, tda10046 goes into an instable state. So, proper locking are needed at the i2c bus master.
*/
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) return 0;
/* 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: return 0; case FEC_2_3: return 1; case FEC_3_4: return 2; case FEC_5_6: return 3; case FEC_7_8: return 4;
}
// unsupported return -EINVAL;
}
staticint tda1004x_decode_fec(int tdafec)
{ // convert known FEC values switch (tdafec) { case 0: return FEC_1_2; case 1: return FEC_2_3; case 2: return FEC_3_4; case 3: return FEC_5_6; case 4: return FEC_7_8;
}
// unsupported return -1;
}
staticint tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
{ struct tda1004x_state* state = fe->demodulator_priv;
// 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;
// guard interval switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { case 0:
fe_params->guard_interval = GUARD_INTERVAL_1_32; break; case 1:
fe_params->guard_interval = GUARD_INTERVAL_1_16; break; case 2:
fe_params->guard_interval = GUARD_INTERVAL_1_8; break; case 3:
fe_params->guard_interval = GUARD_INTERVAL_1_4; break;
}
// hierarchy switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { case 0:
fe_params->hierarchy = HIERARCHY_NONE; break; case 1:
fe_params->hierarchy = HIERARCHY_1; break; case 2:
fe_params->hierarchy = HIERARCHY_2; break; case 3:
fe_params->hierarchy = HIERARCHY_4; break;
}
return 0;
}
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.