📄 stv0299.c
字号:
stv0299_writereg (i2c, 0x1a, 0x1d); stv0299_writereg (i2c, 0x1c, 0x12); stv0299_writereg (i2c, 0x2d, 0x05); } stv0299_writereg (i2c, 0x0e, 0x23); stv0299_writereg (i2c, 0x0f, 0x94); stv0299_writereg (i2c, 0x10, 0x39); stv0299_writereg (i2c, 0x15, 0xc9); stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff); stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff); stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0); break; case PHILIPS_SU1278_TSA: aclk = 0xb5; if (srate < 2000000) bclk = 0x86; else if (srate < 5000000) bclk = 0x89; else if (srate < 15000000) bclk = 0x8f; else if (srate < 45000000) bclk = 0x95; m1 = 0x14; if (srate < 4000000) m1 = 0x10; stv0299_writereg (i2c, 0x13, aclk); stv0299_writereg (i2c, 0x14, bclk); stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff); stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff); stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0); stv0299_writereg (i2c, 0x0f, (stv0299_readreg(i2c, 0x0f) & 0xc0) | m1); break; case ALPS_BSRU6: default: if (srate <= 1500000) { aclk = 0xb7; bclk = 0x87; } else if (srate <= 3000000) { aclk = 0xb7; bclk = 0x8b; } else if (srate <= 7000000) { aclk = 0xb7; bclk = 0x8f; } else if (srate <= 14000000) { aclk = 0xb7; bclk = 0x93; } else if (srate <= 30000000) { aclk = 0xb6; bclk = 0x93; } else if (srate <= 45000000) { aclk = 0xb4; bclk = 0x91; } m1 = 0x12; stv0299_writereg (i2c, 0x13, aclk); stv0299_writereg (i2c, 0x14, bclk); stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff); stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff); stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0); stv0299_writereg (i2c, 0x0f, (stv0299_readreg(i2c, 0x0f) & 0xc0) | m1); break; } return 0;}static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c, int tuner_type){ u32 Mclk = M_CLK / 4096L; u32 srate; s32 offset; u8 sfr[3]; s8 rtf; dprintk ("%s\n", __FUNCTION__); if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT / 4096L; stv0299_readregs (i2c, 0x1f, sfr, 3); stv0299_readregs (i2c, 0x1a, &rtf, 1); srate = (sfr[0] << 8) | sfr[1]; srate *= Mclk; srate /= 16; srate += (sfr[2] >> 4) * Mclk / 256; offset = (s32) rtf * (srate / 4096L); offset /= 128; dprintk ("%s : srate = %i\n", __FUNCTION__, srate); dprintk ("%s : ofset = %i\n", __FUNCTION__, offset); srate += offset; srate += 1000; srate /= 2000; srate *= 2000; return srate;}static int stv0299_check_inversion (struct dvb_i2c_bus *i2c){ dprintk ("%s\n", __FUNCTION__); if ((stv0299_readreg (i2c, 0x1b) & 0x98) != 0x98) { dvb_delay(30); if ((stv0299_readreg (i2c, 0x1b) & 0x98) != 0x98) { u8 val = stv0299_readreg (i2c, 0x0c); return stv0299_writereg (i2c, 0x0c, val ^ 0x01); } } return 0;}static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg){ struct dvb_i2c_bus *i2c = fe->i2c; struct stv0299_state *state = (struct stv0299_state *) fe->data; dprintk ("%s\n", __FUNCTION__); switch (cmd) { case FE_GET_INFO: { struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) arg; memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info)); if (state->tuner_type == PHILIPS_SU1278_TSA_TT) { tmp->frequency_tolerance = M_CLK_SU1278_TSA_TT / 2000; } break; } case FE_READ_STATUS: { fe_status_t *status = (fe_status_t *) arg; u8 signal = 0xff - stv0299_readreg (i2c, 0x18); u8 sync = stv0299_readreg (i2c, 0x1b); dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync); *status = 0; if (signal > 10) *status |= FE_HAS_SIGNAL; if (sync & 0x80) *status |= FE_HAS_CARRIER; if (sync & 0x10) *status |= FE_HAS_VITERBI; if (sync & 0x08) *status |= FE_HAS_SYNC; if ((sync & 0x98) == 0x98) *status |= FE_HAS_LOCK; break; } case FE_READ_BER: if (stv0299_status == STATUS_BER) { *((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8) | stv0299_readreg (i2c, 0x1e); } else { *((u32*) arg) = 0; } break; case FE_READ_SIGNAL_STRENGTH: { s32 signal = 0xffff - ((stv0299_readreg (i2c, 0x18) << 8) | stv0299_readreg (i2c, 0x19)); dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__, stv0299_readreg (i2c, 0x18), stv0299_readreg (i2c, 0x19), (int) signal); signal = signal * 5 / 4; *((u16*) arg) = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; break; } case FE_READ_SNR: { s32 snr = 0xffff - ((stv0299_readreg (i2c, 0x24) << 8) | stv0299_readreg (i2c, 0x25)); snr = 3 * (snr - 0xa100); *((u16*) arg) = (snr > 0xffff) ? 0xffff : (snr < 0) ? 0 : snr; break; } case FE_READ_UNCORRECTED_BLOCKS: if (stv0299_status == STATUS_UCBLOCKS) { *((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8) | stv0299_readreg (i2c, 0x1e); } else { *((u32*) arg) = 0; } break; case FE_SET_FRONTEND: { struct dvb_frontend_parameters *p = arg; dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); if (p->inversion == INVERSION_OFF) { stv0299_writereg(i2c, 0x0c, stv0299_readreg(i2c, 0x0c) & 0xfe); } else if (p->inversion == INVERSION_ON) { stv0299_writereg(i2c, 0x0c, stv0299_readreg(i2c, 0x0c) | 1); } else { // temporary hack until the new dvb_frontend.c becomes mainline stv0299_check_inversion(i2c); // printk("stv0299 does not support auto-inversion\n");// return -EINVAL; } if (state->tuner_type == PHILIPS_SU1278_TSA_TT) { /* check if we should do a finetune */ int frequency_delta = p->frequency - state->tuner_frequency; int minmax = p->u.qpsk.symbol_rate / 2000; if (minmax < 5000) minmax = 5000; if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) && (state->fec_inner == p->u.qpsk.fec_inner) && (state->symbol_rate == p->u.qpsk.symbol_rate)) { int Drot_freq = (frequency_delta << 16) / (M_CLK_SU1278_TSA_TT / 1000); // zap the derotator registers first stv0299_writereg (i2c, 0x22, 0x00); stv0299_writereg (i2c, 0x23, 0x00); // now set them as we want stv0299_writereg (i2c, 0x22, Drot_freq >> 8); stv0299_writereg (i2c, 0x23, Drot_freq); break; } } /* A "normal" tune is requested */ stv0299_writereg (i2c, 0x32, 0x80); stv0299_writereg (i2c, 0x22, 0x00); stv0299_writereg (i2c, 0x23, 0x00); stv0299_writereg (i2c, 0x32, 0x19); stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type); stv0299_set_FEC (i2c, p->u.qpsk.fec_inner); pll_set_tv_freq (i2c, p->frequency, state->tuner_type, p->u.qpsk.symbol_rate); dvb_delay(50); stv0299_writereg (i2c, 0x22, 0x00); stv0299_writereg (i2c, 0x23, 0x00); pll_set_tv_freq (i2c, p->frequency, state->tuner_type, p->u.qpsk.symbol_rate); state->tuner_frequency = p->frequency; state->fec_inner = p->u.qpsk.fec_inner; state->symbol_rate = p->u.qpsk.symbol_rate; break; } case FE_GET_FRONTEND: { struct dvb_frontend_parameters *p = arg; s32 derot_freq; int Mclk = M_CLK; if (state->tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT; derot_freq = (s32)(s16) ((stv0299_readreg (i2c, 0x22) << 8) | stv0299_readreg (i2c, 0x23)); derot_freq *= (Mclk >> 16); derot_freq += 500; derot_freq /= 1000; p->frequency += derot_freq; p->inversion = (stv0299_readreg (i2c, 0x0c) & 1) ? INVERSION_OFF : INVERSION_ON; p->u.qpsk.fec_inner = stv0299_get_fec (i2c); p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, state->tuner_type); break; } case FE_SLEEP: stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */ stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */ stv0299_writereg (i2c, 0x02, 0x80); state->initialised = 0; break; case FE_INIT: state->tuner_frequency = 0; if (!state->initialised) { state->initialised = 1; return stv0299_init (i2c, state->tuner_type); } break; case FE_DISEQC_SEND_MASTER_CMD: return stv0299_send_diseqc_msg (i2c, arg); case FE_DISEQC_SEND_BURST: return stv0299_send_diseqc_burst (i2c, (fe_sec_mini_cmd_t) arg); case FE_SET_TONE: return stv0299_set_tone (i2c, (fe_sec_tone_mode_t) arg); case FE_SET_VOLTAGE: return stv0299_set_voltage (i2c, (fe_sec_voltage_t) arg); default: return -EOPNOTSUPP; }; return 0;}static long probe_tuner (struct dvb_i2c_bus *i2c){ struct dvb_adapter * adapter = (struct dvb_adapter *) i2c->adapter; /* read the status register of TSA5059 */ u8 rpt[] = { 0x05, 0xb5 }; u8 stat [] = { 0 }; u8 tda6100_buf [] = { 0, 0 }; int ret; struct i2c_msg msg1 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; struct i2c_msg msg2 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, { .addr = 0x61, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; struct i2c_msg msg3 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 }, { .addr = 0x60, .flags = 0, .buf = tda6100_buf, .len = 2 }}; stv0299_writereg (i2c, 0x01, 0x15); stv0299_writereg (i2c, 0x02, 0x30); stv0299_writereg (i2c, 0x03, 0x00); printk ("%s: try to attach to %s\n", __FUNCTION__, adapter->name); if ( strcmp(adapter->name, "Technisat SkyStar2 driver") == 0 ) { printk ("%s: setup for tuner Samsung TBMU24112IMB\n", __FILE__); return SAMSUNG_TBMU24112IMB; } if ((ret = i2c->xfer(i2c, msg1, 2)) == 2) { if ( strcmp(adapter->name, "TT-Budget/WinTV-NOVA-CI PCI") == 0 ) { // technotrend cards require non-datasheet settings printk ("%s: setup for tuner SU1278 (TSA5059 synth) on TechnoTrend hardware\n", __FILE__); return PHILIPS_SU1278_TSA_TT; } else { // fall back to datasheet-recommended settings printk ("%s: setup for tuner SU1278 (TSA5059 synth)\n", __FILE__); return PHILIPS_SU1278_TSA; } } if ((ret = i2c->xfer(i2c, msg2, 2)) == 2) { //if ((stat[0] & 0x3f) == 0) { if (0) { printk ("%s: setup for tuner TDQF-S001F\n", __FILE__); return LG_TDQF_S001F; } else { printk ("%s: setup for tuner BSRU6, TDQB-S00x\n", __FILE__); return ALPS_BSRU6; } } /** * setup i2c timing for SU1278... */ stv0299_writereg (i2c, 0x02, 0x00); if ((ret = i2c->xfer(i2c, msg3, 2)) == 2) { printk ("%s: setup for tuner Philips SU1278 (TUA6100 synth)\n", __FILE__); return PHILIPS_SU1278_TUA; } printk ("%s: unknown PLL synthesizer (ret == %i), " "please report to <linuxdvb@linuxtv.org>!!\n", __FILE__, ret); return UNKNOWN_FRONTEND;}static int uni0299_attach (struct dvb_i2c_bus *i2c, void **data){ struct stv0299_state* state; int tuner_type; u8 id; stv0299_writereg (i2c, 0x02, 0x00); /* standby off */ id = stv0299_readreg (i2c, 0x00); dprintk ("%s: id == 0x%02x\n", __FUNCTION__, id); /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ /* register 0x00 might contain 0x80 when returning from standby */ if (id != 0xa1 && id != 0x80) return -ENODEV; if ((tuner_type = probe_tuner(i2c)) < 0) return -ENODEV; if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) { return -ENOMEM; } *data = state; state->tuner_type = tuner_type; state->tuner_frequency = 0; state->initialised = 0; return dvb_register_frontend (uni0299_ioctl, i2c, (void *) state, &uni0299_info);}static void uni0299_detach (struct dvb_i2c_bus *i2c, void *data){ dprintk ("%s\n", __FUNCTION__); kfree(data); dvb_unregister_frontend (uni0299_ioctl, i2c);}static int __init init_uni0299 (void){ dprintk ("%s\n", __FUNCTION__); return dvb_register_i2c_device (NULL, uni0299_attach, uni0299_detach);}static void __exit exit_uni0299 (void){ dprintk ("%s\n", __FUNCTION__); dvb_unregister_i2c_device (uni0299_attach);}module_init (init_uni0299);module_exit (exit_uni0299);MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver");MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey");MODULE_LICENSE("GPL");MODULE_PARM(stv0299_status, "i");MODULE_PARM_DESC(stv0299_status, "Which status value to support (0: BER, 1: UCBLOCKS)");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -