📄 dib7000p.c
字号:
/* * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC). * * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. */#include <linux/kernel.h>#include <linux/i2c.h>#include "compat.h"#include "dvb_frontend.h"#include "dib7000p.h"static int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");static int buggy_sfn_workaround;module_param(buggy_sfn_workaround, int, 0644);MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)struct dib7000p_state { struct dvb_frontend demod; struct dib7000p_config cfg; u8 i2c_addr; struct i2c_adapter *i2c_adap; struct dibx000_i2c_master i2c_master; u16 wbd_ref; u8 current_band; u32 current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; u8 div_force_off : 1; u8 div_state : 1; u16 div_sync_wait; u8 agc_state; u16 gpio_dir; u16 gpio_val; u8 sfn_workaround_active :1;};enum dib7000p_power_mode { DIB7000P_POWER_ALL = 0, DIB7000P_POWER_ANALOG_ADC, DIB7000P_POWER_INTERFACE_ONLY,};static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg){ u8 wb[2] = { reg >> 8, reg & 0xff }; u8 rb[2]; struct i2c_msg msg[2] = { { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 }, { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 }, }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) dprintk("i2c read error on %d",reg); return (rb[0] << 8) | rb[1];}static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val){ u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff, }; struct i2c_msg msg = { .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;}static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf){ u16 l = 0, r, *n; n = buf; l = *n++; while (l) { r = *n++; do { dib7000p_write_word(state, r, *n++); r++; } while (--l); l = *n++; }}static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode){ int ret = 0; u16 outreg, fifo_threshold, smo_mode; outreg = 0; fifo_threshold = 1792; smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1); dprintk( "setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock outreg = (1 << 10); /* 0x0400 */ break; case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock outreg = (1 << 10) | (1 << 6); /* 0x0440 */ break; case OUTMODE_MPEG2_SERIAL: // STBs with serial input outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */ break; case OUTMODE_DIVERSITY: if (state->cfg.hostbus_diversity) outreg = (1 << 10) | (4 << 6); /* 0x0500 */ else outreg = (1 << 11); break; case OUTMODE_MPEG2_FIFO: // e.g. USB feeding smo_mode |= (3 << 1); fifo_threshold = 512; outreg = (1 << 10) | (5 << 6); break; case OUTMODE_ANALOG_ADC: outreg = (1 << 10) | (3 << 6); break; case OUTMODE_HIGH_Z: // disable outreg = 0; break; default: dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); break; } if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5) ; ret |= dib7000p_write_word(state, 235, smo_mode); ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */ return ret;}static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff){ struct dib7000p_state *state = demod->demodulator_priv; if (state->div_force_off) { dprintk( "diversity combination deactivated - forced by COFDM parameters"); onoff = 0; } state->div_state = (u8)onoff; if (onoff) { dib7000p_write_word(state, 204, 6); dib7000p_write_word(state, 205, 16); /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); } else { dib7000p_write_word(state, 204, 1); dib7000p_write_word(state, 205, 0); dib7000p_write_word(state, 207, 0); } return 0;}static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode){ /* by default everything is powered off */ u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff); /* now, depending on the requested mode, we power on */ switch (mode) { /* power up everything in the demod */ case DIB7000P_POWER_ALL: reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff; break; case DIB7000P_POWER_ANALOG_ADC: /* dem, cfg, iqc, sad, agc */ reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); /* nud */ reg_776 &= ~((1 << 0)); /* Dout */ reg_1280 &= ~((1 << 11)); /* fall through wanted to enable the interfaces */ /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); break;/* TODO following stuff is just converted from the dib7000-driver - check when is used what */#if 0 case DIB7000_POWER_LEVEL_INTERF_ANALOG_AGC: /* dem, cfg, iqc, sad, agc */ reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); /* sdio, i2c, gpio */ reg_1280 &= ~((1 << 13) | (1 << 12) | (1 << 10)); break; case DIB7000_POWER_LEVEL_DOWN_COR4_DINTLV_ICIRM_EQUAL_CFROD: reg_774 = 0; /* power down: cor4 dintlv equal */ reg_775 = (1 << 15) | (1 << 6) | (1 << 5); reg_776 = 0; reg_899 = 0; reg_1280 &= 0x01ff; break; case DIB7000_POWER_LEVEL_DOWN_COR4_CRY_ESRAM_MOUT_NUD: reg_774 = 0; /* power down: cor4 */ reg_775 = (1 << 15); /* nud */ reg_776 = (1 << 0); reg_899 = 0; reg_1280 &= 0x01ff; break;#endif } dib7000p_write_word(state, 774, reg_774); dib7000p_write_word(state, 775, reg_775); dib7000p_write_word(state, 776, reg_776); dib7000p_write_word(state, 899, reg_899); dib7000p_write_word(state, 1280, reg_1280); return 0;}static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no){ u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909); switch (no) { case DIBX000_SLOW_ADC_ON: reg_909 |= (1 << 1) | (1 << 0); dib7000p_write_word(state, 909, reg_909); reg_909 &= ~(1 << 1); break; case DIBX000_SLOW_ADC_OFF: reg_909 |= (1 << 1) | (1 << 0); break; case DIBX000_ADC_ON: reg_908 &= 0x0fff; reg_909 &= 0x0003; break; case DIBX000_ADC_OFF: // leave the VBG voltage on reg_908 |= (1 << 14) | (1 << 13) | (1 << 12); reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); break; case DIBX000_VBG_ENABLE: reg_908 &= ~(1 << 15); break; case DIBX000_VBG_DISABLE: reg_908 |= (1 << 15); break; default: break; }// dprintk( "908: %x, 909: %x\n", reg_908, reg_909); dib7000p_write_word(state, 908, reg_908); dib7000p_write_word(state, 909, reg_909);}static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw){ u32 timf; // store the current bandwidth for later use state->current_bandwidth = bw; if (state->timf == 0) { dprintk( "using default timf"); timf = state->cfg.bw->timf; } else { dprintk( "using updated timf"); timf = state->timf; } timf = timf * (bw / 50) / 160; dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff)); return 0;}static int dib7000p_sad_calib(struct dib7000p_state *state){/* internal */// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096 /* do the calibration */ dib7000p_write_word(state, 73, (1 << 0)); dib7000p_write_word(state, 73, (0 << 0)); msleep(1); return 0;}int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value){ struct dib7000p_state *state = demod->demodulator_priv; if (value > 4095) value = 4095; state->wbd_ref = value; return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);}EXPORT_SYMBOL(dib7000p_set_wbd_ref);static void dib7000p_reset_pll(struct dib7000p_state *state){ struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; u16 clk_cfg0; /* force PLL bypass */ clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); dib7000p_write_word(state, 900, clk_cfg0); /* P_pll_cfg */ dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); dib7000p_write_word(state, 900, clk_cfg0); dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff)); dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff)); dib7000p_write_word(state, 72, bw->sad_cfg);}static int dib7000p_reset_gpio(struct dib7000p_state *st){ /* reset the GPIOs */ dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1029, st->gpio_dir); dib7000p_write_word(st, 1030, st->gpio_val); /* TODO 1031 is P_gpio_od */ dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div); return 0;}static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val){ st->gpio_dir = dib7000p_read_word(st, 1029); st->gpio_dir &= ~(1 << num); /* reset the direction bit */ st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ dib7000p_write_word(st, 1029, st->gpio_dir); st->gpio_val = dib7000p_read_word(st, 1030); st->gpio_val &= ~(1 << num); /* reset the direction bit */ st->gpio_val |= (val & 0x01) << num; /* set the new value */ dib7000p_write_word(st, 1030, st->gpio_val); return 0;}int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val){ struct dib7000p_state *state = demod->demodulator_priv; return dib7000p_cfg_gpio(state, num, dir, val);}EXPORT_SYMBOL(dib7000p_set_gpio);static u16 dib7000p_defaults[] ={ // auto search configuration 3, 2, 0x0004, 0x1000, 0x0814, /* Equal Lock */ 12, 6, 0x001b, 0x7740, 0x005b, 0x8d80, 0x01c9, 0xc380, 0x0000, 0x0080, 0x0000, 0x0090, 0x0001, 0xd4c0, 1, 26, 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 /* set ADC level to -16 */ 11, 79, (1 << 13) - 825 - 117, (1 << 13) - 837 - 117, (1 << 13) - 811 - 117, (1 << 13) - 766 - 117, (1 << 13) - 737 - 117, (1 << 13) - 693 - 117, (1 << 13) - 648 - 117, (1 << 13) - 619 - 117, (1 << 13) - 575 - 117, (1 << 13) - 531 - 117, (1 << 13) - 501 - 117, 1, 142, 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 /* disable power smoothing */ 8, 145, 0, 0, 0, 0, 0, 0, 0, 0, 1, 154, 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 1, 168, 0x0ccd, // P_pha3_thres, default 0x3000// 1, 169,// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 1, 183, 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 5, 187, 0x023d, // P_adp_regul_cnt=573, default: 410 0x00a4, // P_adp_noise_cnt= 0x00a4, // P_adp_regul_ext 0x7ff0, // P_adp_noise_ext 0x3ccc, // P_adp_fil
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -