📄 sp887x.c
字号:
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;}/** * estimates division of two 24bit numbers, * derived from the ves1820/stv0299 driver code */staticvoid divide (int n, int d, int *quotient_i, int *quotient_f){ unsigned int q, r; r = (n % d) << 8; q = (r / d); if (quotient_i) *quotient_i = q; if (quotient_f) { r = (r % d) << 8; q = (q << 8) | (r / d); r = (r % d) << 8; *quotient_f = (q << 8) | (r / d); }}staticvoid sp887x_correct_offsets (struct dvb_frontend *fe, struct dvb_frontend_parameters *p, int actual_freq){ static const u32 srate_correction [] = { 1879617, 4544878, 8098561 }; int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; int freq_offset = actual_freq - p->frequency; int sysclock = 61003; //[kHz] int ifreq = 36000000; int freq; int frequency_shift; if (p->inversion == INVERSION_ON) freq = ifreq - freq_offset; else freq = ifreq + freq_offset; divide(freq / 333, sysclock, NULL, &frequency_shift); if (p->inversion == INVERSION_ON) frequency_shift = -frequency_shift; /* sample rate correction */ sp887x_writereg(fe, 0x319, srate_correction[bw_index] >> 12); sp887x_writereg(fe, 0x31a, srate_correction[bw_index] & 0xfff); /* carrier offset correction */ sp887x_writereg(fe, 0x309, frequency_shift >> 12); sp887x_writereg(fe, 0x30a, frequency_shift & 0xfff);}staticint sp887x_setup_frontend_parameters (struct dvb_frontend *fe, struct dvb_frontend_parameters *p){ int actual_freq, err; u16 val, reg0xc05; if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ && p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ) return -EINVAL; if ((err = configure_reg0xc05(p, ®0xc05))) return err; sp887x_microcontroller_stop(fe); actual_freq = tsa5060_setup_pll(fe, p->frequency); /* read status reg in order to clear pending irqs */ sp887x_readreg(fe, 0x200); sp887x_correct_offsets(fe, p, actual_freq); /* filter for 6/7/8 Mhz channel */ if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) val = 2; else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) val = 1; else val = 0; sp887x_writereg(fe, 0x311, val); /* scan order: 2k first = 0, 8k first = 1 */ if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) sp887x_writereg(fe, 0x338, 0x000); else sp887x_writereg(fe, 0x338, 0x001); sp887x_writereg(fe, 0xc05, reg0xc05); if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) val = 2 << 3; else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) val = 3 << 3; else val = 0 << 3; /* enable OFDM and SAW bits as lock indicators in sync register 0xf17, * optimize algorithm for given bandwidth... */ sp887x_writereg(fe, 0xf14, 0x160 | val); sp887x_writereg(fe, 0xf15, 0x000); sp887x_microcontroller_start(fe); return 0;}staticint sp887x_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg){ switch (cmd) { case FE_GET_INFO: memcpy (arg, &sp887x_info, sizeof(struct dvb_frontend_info)); break; case FE_READ_STATUS: { u16 snr12 = sp887x_readreg(fe, 0xf16); u16 sync0x200 = sp887x_readreg(fe, 0x200); u16 sync0xf17 = sp887x_readreg(fe, 0xf17); fe_status_t *status = arg; *status = 0; if (snr12 > 0x00f) *status |= FE_HAS_SIGNAL; //if (sync0x200 & 0x004) // *status |= FE_HAS_SYNC | FE_HAS_CARRIER; //if (sync0x200 & 0x008) // *status |= FE_HAS_VITERBI; if ((sync0xf17 & 0x00f) == 0x002) { *status |= FE_HAS_LOCK; *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER; } if (sync0x200 & 0x001) { /* tuner adjustment requested...*/ int steps = (sync0x200 >> 4) & 0x00f; if (steps & 0x008) steps = -steps; dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n", steps); } break; } case FE_READ_BER: { u32* ber = arg; *ber = (sp887x_readreg(fe, 0xc08) & 0x3f) | (sp887x_readreg(fe, 0xc07) << 6); sp887x_writereg(fe, 0xc08, 0x000); sp887x_writereg(fe, 0xc07, 0x000); if (*ber >= 0x3fff0) *ber = ~0; break; } case FE_READ_SIGNAL_STRENGTH: // FIXME: correct registers ? { u16 snr12 = sp887x_readreg(fe, 0xf16); u32 signal = 3 * (snr12 << 4); *((u16*) arg) = (signal < 0xffff) ? signal : 0xffff; break; } case FE_READ_SNR: { u16 snr12 = sp887x_readreg(fe, 0xf16); *(u16*) arg = (snr12 << 4) | (snr12 >> 8); break; } case FE_READ_UNCORRECTED_BLOCKS: { u32 *ublocks = (u32 *) arg; *ublocks = sp887x_readreg(fe, 0xc0c); if (*ublocks == 0xfff) *ublocks = ~0; break; } case FE_SET_FRONTEND: return sp887x_setup_frontend_parameters(fe, arg); case FE_GET_FRONTEND: // FIXME: read known values back from Hardware... break; case FE_SLEEP: /* tristate TS output and disable interface pins */ sp887x_writereg(fe, 0xc18, 0x000); break; case FE_INIT: if (fe->data == NULL) { /* first time initialisation... */ fe->data = (void*) ~0; sp887x_initial_setup (fe); } /* enable TS output and interface pins */ sp887x_writereg(fe, 0xc18, 0x00d); break; case FE_GET_TUNE_SETTINGS: { struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; fesettings->min_delay_ms = 50; fesettings->step_size = 0; fesettings->max_drift = 0; return 0; } default: return -EOPNOTSUPP; }; return 0;}staticint sp887x_attach (struct dvb_i2c_bus *i2c, void **data){ struct i2c_msg msg = {.addr = 0x70, .flags = 0, .buf = NULL, .len = 0 }; dprintk ("%s\n", __FUNCTION__); if (i2c->xfer (i2c, &msg, 1) != 1) return -ENODEV; return dvb_register_frontend (sp887x_ioctl, i2c, NULL, &sp887x_info);}staticvoid sp887x_detach (struct dvb_i2c_bus *i2c, void *data){ dprintk ("%s\n", __FUNCTION__); dvb_unregister_frontend (sp887x_ioctl, i2c);}staticint __init init_sp887x (void){ dprintk ("%s\n", __FUNCTION__); return dvb_register_i2c_device (NULL, sp887x_attach, sp887x_detach);}staticvoid __exit exit_sp887x (void){ dprintk ("%s\n", __FUNCTION__); dvb_unregister_i2c_device (sp887x_attach);}module_init(init_sp887x);module_exit(exit_sp887x);MODULE_DESCRIPTION("sp887x DVB-T demodulator driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -