--- v4l-dvb/linux/drivers/media/dvb/frontends/tda1004x.c 2006-06-30 19:59:10.000000000 +0400 +++ mp-bc1/linux/drivers/media/dvb/frontends/tda1004x.c 2006-07-23 11:40:58.000000000 +0400 @@ -238,8 +238,8 @@ static int tda1004x_disable_tuner_i2c(st return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0); } -static int tda10045h_set_bandwidth(struct tda1004x_state *state, - fe_bandwidth_t bandwidth) +static int tda10045h_set_bandwidth_compat(struct tda1004x_state *state, + fe_bandwidth_t bandwidth) { static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; @@ -267,8 +267,37 @@ static int tda10045h_set_bandwidth(struc return 0; } -static int tda10046h_set_bandwidth(struct tda1004x_state *state, - fe_bandwidth_t bandwidth) +static int tda10045h_set_bandwidth(struct tda1004x_state *state, + enum dvbfe_bandwidth bandwidth) +{ + static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; + static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; + static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 }; + + switch (bandwidth) { + case DVBFE_BANDWIDTH_6_MHZ: + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); + break; + + case DVBFE_BANDWIDTH_7_MHZ: + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); + break; + + case DVBFE_BANDWIDTH_8_MHZ: + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); + break; + + default: + return -EINVAL; + } + + tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0); + + return 0; +} + +static int tda10046h_set_bandwidth_compat(struct tda1004x_state *state, + fe_bandwidth_t bandwidth) { static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; @@ -331,6 +360,70 @@ static int tda10046h_set_bandwidth(struc return 0; } +static int tda10046h_set_bandwidth(struct tda1004x_state *state, + enum dvbfe_bandwidth bandwidth) +{ + static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; + static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; + static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d }; + + static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 }; + static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab }; + static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 }; + int tda10046_clk53m; + + if ((state->config->if_freq == TDA10046_FREQ_045) || + (state->config->if_freq == TDA10046_FREQ_052)) + tda10046_clk53m = 0; + else + tda10046_clk53m = 1; + switch (bandwidth) { + case DVBFE_BANDWIDTH_6_MHZ: + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M, + sizeof(bandwidth_6mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M, + sizeof(bandwidth_6mhz_48M)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab); + } + break; + + case DVBFE_BANDWIDTH_7_MHZ: + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M, + sizeof(bandwidth_7mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M, + sizeof(bandwidth_7mhz_48M)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); + } + break; + + case DVBFE_BANDWIDTH_8_MHZ: + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M, + sizeof(bandwidth_8mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M, + sizeof(bandwidth_8mhz_48M)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + static int tda1004x_do_upload(struct tda1004x_state *state, unsigned char *mem, unsigned int len, u8 dspCodeCounterReg, u8 dspCodeInReg) @@ -424,7 +517,10 @@ static int tda10045_fwupload(struct dvb_ msleep(10); /* set parameters */ - tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); + if (fe->legacy) + tda10045h_set_bandwidth_compat(state, BANDWIDTH_8_MHZ); + else + tda10045h_set_bandwidth(state, DVBFE_BANDWIDTH_8_MHZ); ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); release_firmware(fw); @@ -488,7 +584,10 @@ static void tda10046_init_plls(struct dv tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f); break; } - tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz + if (fe->legacy) + tda10046h_set_bandwidth_compat(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz + else + tda10046h_set_bandwidth(state, DVBFE_BANDWIDTH_8_MHZ); // default bandwidth 8 MHz /* let the PLLs settle */ msleep(120); } @@ -694,9 +793,10 @@ static int tda1004x_set_fe(struct dvb_fr } // set frequency - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.tuner_ops.set_params_compat) { + fe->ops.tuner_ops.set_params_compat(fe, fe_params); + 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 @@ -775,11 +875,11 @@ static int tda1004x_set_fe(struct dvb_fr // set bandwidth switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: - tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); + tda10045h_set_bandwidth_compat(state, fe_params->u.ofdm.bandwidth); break; case TDA1004X_DEMOD_TDA10046: - tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); + tda10046h_set_bandwidth_compat(state, fe_params->u.ofdm.bandwidth); break; } @@ -871,6 +971,208 @@ static int tda1004x_set_fe(struct dvb_fr return 0; } +static int tda1004x_set_params(struct dvb_frontend* fe, + struct dvbfe_params *fe_params) +{ + struct tda1004x_state* state = fe->demodulator_priv; + int tmp; + int inversion; + + dprintk("%s\n", __FUNCTION__); + + if (state->demod_type == TDA1004X_DEMOD_TDA10046) { + // setup auto offset + tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0); + + // disable agc_conf[2] + tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0); + } + + // set frequency + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, fe_params); + 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->delsys.dvbt.code_rate_HP = DVBFE_FEC_AUTO; + fe_params->delsys.dvbt.guard_interval = DVBFE_GUARD_INTERVAL_AUTO; + fe_params->delsys.dvbt.transmission_mode = DVBFE_TRANSMISSION_MODE_AUTO; + } + + // Set standard params.. or put them to auto + if ((fe_params->delsys.dvbt.code_rate_HP == DVBFE_FEC_AUTO) || + (fe_params->delsys.dvbt.code_rate_LP == DVBFE_FEC_AUTO) || + (fe_params->delsys.dvbt.constellation == DVBFE_MOD_QAMAUTO) || + (fe_params->delsys.dvbt.hierarchy == DVBFE_HIERARCHY_AUTO)) { + + tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation 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->delsys.dvbt.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->delsys.dvbt.code_rate_LP); + if (tmp < 0) + return tmp; + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); + + // set constellation + switch (fe_params->delsys.dvbt.constellation) { + case DVBFE_MOD_QPSK: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); + break; + + case DVBFE_MOD_QAM16: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1); + break; + + case DVBFE_MOD_QAM64: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2); + break; + + default: + return -EINVAL; + } + + // set hierarchy + switch (fe_params->delsys.dvbt.hierarchy) { + case DVBFE_HIERARCHY_OFF: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); + break; + + case DVBFE_HIERARCHY_ON: + switch (fe_params->delsys.dvbt.alpha) { + case DVBFE_ALPHA_1: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5); + break; + + case DVBFE_ALPHA_2: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5); + break; + + case DVBFE_ALPHA_4: + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5); + break; + } + break; + default: + return -EINVAL; + } + } + + // set bandwidth + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + tda10045h_set_bandwidth(state, fe_params->delsys.dvbt.bandwidth); + break; + + case TDA1004X_DEMOD_TDA10046: + tda10046h_set_bandwidth(state, fe_params->delsys.dvbt.bandwidth); + 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->delsys.dvbt.guard_interval) { + case DVBFE_GUARD_INTERVAL_1_32: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); + break; + + case DVBFE_GUARD_INTERVAL_1_16: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2); + break; + + case DVBFE_GUARD_INTERVAL_1_8: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2); + break; + + case DVBFE_GUARD_INTERVAL_1_4: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2); + break; + + case DVBFE_GUARD_INTERVAL_AUTO: + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); + break; + + default: + return -EINVAL; + } + + // set transmission mode + switch (fe_params->delsys.dvbt.transmission_mode) { + case DVBFE_TRANSMISSION_MODE_2K: + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4); + break; + + case DVBFE_TRANSMISSION_MODE_8K: + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4); + break; + + case DVBFE_TRANSMISSION_MODE_AUTO: + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0); + break; + + default: + return -EINVAL; + } + + // start the lock + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); + break; + + case TDA1004X_DEMOD_TDA10046: + tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40); + msleep(1); + tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1); + break; + } + + msleep(10); + + return 0; +} + static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) { struct tda1004x_state* state = fe->demodulator_priv; @@ -976,6 +1278,114 @@ static int tda1004x_get_fe(struct dvb_fr return 0; } +static int tda1004x_get_params(struct dvb_frontend* fe, struct dvbfe_params *fe_params) +{ + struct tda1004x_state* state = fe->demodulator_priv; + + dprintk("%s\n", __FUNCTION__); + + // inversion status + fe_params->inversion = INVERSION_OFF; + if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) + fe_params->inversion = INVERSION_ON; + if (state->config->invert) + fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; + + // bandwidth + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) { + case 0x14: + fe_params->delsys.dvbt.bandwidth = DVBFE_BANDWIDTH_8_MHZ; + break; + case 0xdb: + fe_params->delsys.dvbt.bandwidth = DVBFE_BANDWIDTH_7_MHZ; + break; + case 0x4f: + fe_params->delsys.dvbt.bandwidth = DVBFE_BANDWIDTH_6_MHZ; + break; + } + break; + case TDA1004X_DEMOD_TDA10046: + switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { + case 0x5c: + case 0x54: + fe_params->delsys.dvbt.bandwidth = DVBFE_BANDWIDTH_8_MHZ; + break; + case 0x6a: + case 0x60: + fe_params->delsys.dvbt.bandwidth = DVBFE_BANDWIDTH_7_MHZ; + break; + case 0x7b: + case 0x70: + fe_params->delsys.dvbt.bandwidth = DVBFE_BANDWIDTH_6_MHZ; + break; + } + break; + } + + // FEC + fe_params->delsys.dvbt.code_rate_HP = + tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7); + fe_params->delsys.dvbt.code_rate_LP = + tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7); + + // constellation + switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) { + case 0: + fe_params->delsys.dvbt.constellation = DVBFE_MOD_QPSK; + break; + case 1: + fe_params->delsys.dvbt.constellation = DVBFE_MOD_QAM16; + break; + case 2: + fe_params->delsys.dvbt.constellation = DVBFE_MOD_QAM64; + break; + } + + // transmission mode + fe_params->delsys.dvbt.transmission_mode = DVBFE_TRANSMISSION_MODE_2K; + if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) + fe_params->delsys.dvbt.transmission_mode = DVBFE_TRANSMISSION_MODE_8K; + + // guard interval + switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { + case 0: + fe_params->delsys.dvbt.guard_interval = DVBFE_GUARD_INTERVAL_1_32; + break; + case 1: + fe_params->delsys.dvbt.guard_interval = DVBFE_GUARD_INTERVAL_1_16; + break; + case 2: + fe_params->delsys.dvbt.guard_interval = DVBFE_GUARD_INTERVAL_1_8; + break; + case 3: + fe_params->delsys.dvbt.guard_interval = DVBFE_GUARD_INTERVAL_1_4; + break; + } + + // hierarchy + switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { + case 0: + fe_params->delsys.dvbt.hierarchy = DVBFE_HIERARCHY_OFF; + break; + case 1: + fe_params->delsys.dvbt.hierarchy = DVBFE_HIERARCHY_ON; + fe_params->delsys.dvbt.alpha = DVBFE_ALPHA_1; + break; + case 2: + fe_params->delsys.dvbt.hierarchy = DVBFE_HIERARCHY_ON; + fe_params->delsys.dvbt.alpha = DVBFE_ALPHA_2; + break; + case 3: + fe_params->delsys.dvbt.hierarchy = DVBFE_HIERARCHY_ON; + fe_params->delsys.dvbt.alpha = DVBFE_ALPHA_4; + break; + } + + return 0; +} + static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status) { struct tda1004x_state* state = fe->demodulator_priv; @@ -1256,6 +1666,57 @@ struct dvb_frontend* tda10045_attach(con return &state->frontend; } +static struct dvbfe_info tda10045_info = { + .name = "Philips TDA10045 DVB-T", + .delivery = DVBFE_DELSYS_DVBT, + .delsys = { + .dvbt.modulation = DVBFE_MOD_OFDM, + .dvbt.stream_priority = DVBFE_STREAM_PRIORITY_HP | + DVBFE_STREAM_PRIORITY_LP + }, + + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_step = 166667, +}; + +static struct dvbfe_info tda10046_info = { + .name = "Philips TDA10046 DVB-T", + .delivery = DVBFE_DELSYS_DVBT, + .delsys = { + .dvbt.modulation = DVBFE_MOD_OFDM, + .dvbt.stream_priority = DVBFE_STREAM_PRIORITY_HP | + DVBFE_STREAM_PRIORITY_LP + }, + + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_step = 166667, +}; + +static int tda1004x_get_info(struct dvb_frontend *fe, struct dvbfe_info *fe_info) +{ + struct tda1004x_state *state = fe->demodulator_priv; + + switch (state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + memcpy(fe_info, &tda10045_info, sizeof (tda10045_info)); + break; + case TDA1004X_DEMOD_TDA10046: + memcpy(fe_info, &tda10046_info, sizeof (tda10046_info)); + break; + } + + return 0; +} + +static int tda1004x_get_delsys(struct dvb_frontend *fe, enum dvbfe_delsys *fe_delsys) +{ + *fe_delsys = DVBFE_DELSYS_DVBT; + + return 0; +} + static struct dvb_frontend_ops tda10046_ops = { .info = { .name = "Philips TDA10046H DVB-T", @@ -1285,6 +1746,11 @@ static struct dvb_frontend_ops tda10046_ .read_signal_strength = tda1004x_read_signal_strength, .read_snr = tda1004x_read_snr, .read_ucblocks = tda1004x_read_ucblocks, + + .set_params = tda1004x_set_params, + .get_params = tda1004x_get_params, + .get_info = tda1004x_get_info, + .get_delsys = tda1004x_get_delsys, }; struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
_______________________________________________ linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb