📄 alps_tdlb7.c
字号:
if (ret < 0) return -EIO; tmp |= ret; if (tmp) *signal = 0xFFFF - tmp; return 0;}static int sp8870_read_snr(struct dvb_i2c_bus *i2c, u32* snr){ *snr = 0; return -EOPNOTSUPP;}static int sp8870_read_uncorrected_blocks (struct dvb_i2c_bus *i2c, u32* ublocks){ int ret; *ublocks = 0; ret = sp8870_readreg(i2c, 0xC0C); if (ret < 0) return -EIO; if (ret == 0xFFFF) ret = ~0; *ublocks = ret; return 0;}static int sp8870_read_data_valid_signal(struct dvb_i2c_bus *i2c){ return (sp8870_readreg(i2c, 0x0D02) > 0);}staticint configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05){ int known_parameters = 1; *reg0xc05 = 0x000; switch (p->u.ofdm.constellation) { case QPSK: break; case QAM_16: *reg0xc05 |= (1 << 10); break; case QAM_64: *reg0xc05 |= (2 << 10); break; case QAM_AUTO: known_parameters = 0; break; default: return -EINVAL; }; switch (p->u.ofdm.hierarchy_information) { case HIERARCHY_NONE: break; case HIERARCHY_1: *reg0xc05 |= (1 << 7); break; case HIERARCHY_2: *reg0xc05 |= (2 << 7); break; case HIERARCHY_4: *reg0xc05 |= (3 << 7); break; case HIERARCHY_AUTO: known_parameters = 0; break; default: return -EINVAL; }; switch (p->u.ofdm.code_rate_HP) { case FEC_1_2: break; case FEC_2_3: *reg0xc05 |= (1 << 3); break; case FEC_3_4: *reg0xc05 |= (2 << 3); break; case FEC_5_6: *reg0xc05 |= (3 << 3); break; case FEC_7_8: *reg0xc05 |= (4 << 3); break; case FEC_AUTO: known_parameters = 0; break; default: return -EINVAL; }; if (known_parameters) *reg0xc05 |= (2 << 1); /* use specified parameters */ else *reg0xc05 |= (1 << 1); /* enable autoprobing */ return 0;}static int sp8870_set_frontend_parameters (struct dvb_i2c_bus *i2c, struct dvb_frontend_parameters *p){ int err; u16 reg0xc05; if ((err = configure_reg0xc05(p, ®0xc05))) return err; // system controller stop sp8870_microcontroller_stop(i2c); // set tuner parameters sp5659_set_tv_freq (i2c, p->frequency); // sample rate correction bit [23..17] sp8870_writereg(i2c, 0x0319, 0x000A); // sample rate correction bit [16..0] sp8870_writereg(i2c, 0x031A, 0x0AAB); // integer carrier offset sp8870_writereg(i2c, 0x0309, 0x0400); // fractional carrier offset sp8870_writereg(i2c, 0x030A, 0x0000); // filter for 6/7/8 Mhz channel if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) sp8870_writereg(i2c, 0x0311, 0x0002); else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) sp8870_writereg(i2c, 0x0311, 0x0001); else sp8870_writereg(i2c, 0x0311, 0x0000); // scan order: 2k first = 0x0000, 8k first = 0x0001 if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) sp8870_writereg(i2c, 0x0338, 0x0000); else sp8870_writereg(i2c, 0x0338, 0x0001); sp8870_writereg(i2c, 0xc05, reg0xc05); // read status reg in order to clear pending irqs sp8870_readreg(i2c, 0x200); // system controller start sp8870_microcontroller_start(i2c); return 0;}// number of trials to recover from lockup#define MAXTRIALS 5// maximum checks for data valid signal#define MAXCHECKS 100// only for debugging: counter for detected lockupsstatic int lockups = 0;// only for debugging: counter for channel switchesstatic int switches = 0;static int sp8870_set_frontend (struct dvb_i2c_bus *i2c, struct dvb_frontend_parameters *p){ /* The firmware of the sp8870 sometimes locks up after setting frontend parameters. We try to detect this by checking the data valid signal. If it is not set after MAXCHECKS we try to recover the lockup by setting the frontend parameters again. */ int err = 0; int valid = 0; int trials = 0; int check_count = 0; dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency); for (trials = 1; trials <= MAXTRIALS; trials++) { if ((err = sp8870_set_frontend_parameters(i2c, p))) return err; for (check_count = 0; check_count < MAXCHECKS; check_count++) {// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0); valid = sp8870_read_data_valid_signal(i2c); if (valid) { dprintk("%s: delay = %i usec\n", __FUNCTION__, check_count * 10); break; } udelay(10); } if (valid) break; } if (!valid) { printk("%s: firmware crash!!!!!!\n", __FUNCTION__); return -EIO; } if (debug) { if (valid) { if (trials > 1) { printk("%s: firmware lockup!!!\n", __FUNCTION__); printk("%s: recovered after %i trial(s))\n", __FUNCTION__, trials - 1); lockups++; } } switches++; printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups); } return 0;}static int sp8870_sleep(struct dvb_i2c_bus *i2c){ // tristate TS output and disable interface pins return sp8870_writereg(i2c, 0xC18, 0x000);}static int sp8870_wake_up(struct dvb_i2c_bus *i2c){ // enable TS output and interface pins return sp8870_writereg(i2c, 0xC18, 0x00D);}static int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg){ struct dvb_i2c_bus *i2c = fe->i2c; switch (cmd) { case FE_GET_INFO: memcpy (arg, &tdlb7_info, sizeof(struct dvb_frontend_info)); break; case FE_READ_STATUS: return sp8870_read_status(i2c, (fe_status_t *) arg); case FE_READ_BER: return sp8870_read_ber(i2c, (u32 *) arg); case FE_READ_SIGNAL_STRENGTH: return sp8870_read_signal_strength(i2c, (u16 *) arg); case FE_READ_SNR: // not supported by hardware? return sp8870_read_snr(i2c, (u32 *) arg); case FE_READ_UNCORRECTED_BLOCKS: return sp8870_read_uncorrected_blocks(i2c, (u32 *) arg); case FE_SET_FRONTEND: return sp8870_set_frontend(i2c, (struct dvb_frontend_parameters*) arg); case FE_RESET: return -EOPNOTSUPP; case FE_GET_FRONTEND: // FIXME: read known values back from Hardware... return -EOPNOTSUPP; case FE_SLEEP: return sp8870_sleep(i2c); case FE_INIT: sp8870_wake_up(i2c); if (fe->data == NULL) { // first time initialisation... fe->data = (void*) ~0; sp8870_init (i2c); } break; default: return -EOPNOTSUPP; }; return 0;}static int tdlb7_attach (struct dvb_i2c_bus *i2c, void **data){ u8 b0 [] = { 0x02 , 0x00 }; u8 b1 [] = { 0, 0 }; struct i2c_msg msg [] = { { addr: 0x71, flags: 0, buf: b0, len: 2 }, { addr: 0x71, flags: I2C_M_RD, buf: b1, len: 2 } }; dprintk ("%s\n", __FUNCTION__); if (i2c->xfer (i2c, msg, 2) != 2) return -ENODEV; sp8870_firmware_upload(i2c); return dvb_register_frontend (tdlb7_ioctl, i2c, NULL, &tdlb7_info);}static void tdlb7_detach (struct dvb_i2c_bus *i2c, void *data){ dprintk ("%s\n", __FUNCTION__); dvb_unregister_frontend (tdlb7_ioctl, i2c);}static int __init init_tdlb7 (void){ dprintk ("%s\n", __FUNCTION__); return dvb_register_i2c_device (THIS_MODULE, tdlb7_attach, tdlb7_detach);}static void __exit exit_tdlb7 (void){ dprintk ("%s\n", __FUNCTION__); dvb_unregister_i2c_device (tdlb7_attach);}module_init(init_tdlb7);module_exit(exit_tdlb7);MODULE_PARM(debug,"i");MODULE_PARM_DESC(debug, "enable verbose debug messages");MODULE_PARM(firmware_file,"s");MODULE_PARM_DESC(firmware_file, "where to find the firmware file");MODULE_DESCRIPTION("TDLB7 DVB-T Frontend");MODULE_AUTHOR("Juergen Peitz");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -