?? dib7000m.c
字號:
/* * Linux-DVB Driver for DiBcom's DiB7000M and * first generation DiB7000P-demodulator-family. * * 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 "dib7000m.h"static int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0)struct dib7000m_state { struct dvb_frontend demod; struct dib7000m_config cfg; u8 i2c_addr; struct i2c_adapter *i2c_adap; struct dibx000_i2c_master i2c_master;/* offset is 1 in case of the 7000MC */ u8 reg_offs; u16 wbd_ref; u8 current_band; fe_bandwidth_t current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; u32 timf_default; u32 internal_clk; u8 div_force_off : 1; u8 div_state : 1; u16 div_sync_wait; u16 revision; u8 agc_state;};enum dib7000m_power_mode { DIB7000M_POWER_ALL = 0, DIB7000M_POWER_NO, DIB7000M_POWER_INTERF_ANALOG_AGC, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD, DIB7000M_POWER_INTERFACE_ONLY,};static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg){ u8 wb[2] = { (reg >> 8) | 0x80, 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 dib7000m_write_word(struct dib7000m_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 dib7000m_write_tab(struct dib7000m_state *state, u16 *buf){ u16 l = 0, r, *n; n = buf; l = *n++; while (l) { r = *n++; if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC r++; do { dib7000m_write_word(state, r, *n++); r++; } while (--l); l = *n++; }}static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode){ int ret = 0; u16 outreg, fifo_threshold, smo_mode, sram = 0x0005; /* by default SRAM output is disabled */ outreg = 0; fifo_threshold = 1792; smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 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); /* 0x0482 */ break; case OUTMODE_DIVERSITY: if (state->cfg.hostbus_diversity) outreg = (1 << 10) | (4 << 6); /* 0x0500 */ else sram |= 0x0c00; break; case OUTMODE_MPEG2_FIFO: // e.g. USB feeding smo_mode |= (3 << 1); fifo_threshold = 512; outreg = (1 << 10) | (5 << 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 |= dib7000m_write_word(state, 294 + state->reg_offs, smo_mode); ret |= dib7000m_write_word(state, 295 + state->reg_offs, fifo_threshold); /* synchronous fread */ ret |= dib7000m_write_word(state, 1795, outreg); ret |= dib7000m_write_word(state, 1805, sram); if (state->revision == 0x4003) { u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd; if (mode == OUTMODE_DIVERSITY) clk_cfg1 |= (1 << 1); // P_O_CLK_en dib7000m_write_word(state, 909, clk_cfg1); } return ret;}static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode){ /* by default everything is going to be powered off */ u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff; u8 offset = 0; /* now, depending on the requested mode, we power on */ switch (mode) { /* power up everything in the demod */ case DIB7000M_POWER_ALL: reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000; break; /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); break; case DIB7000M_POWER_INTERF_ANALOG_AGC: reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); reg_906 &= ~((1 << 0)); break; case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000; break; case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD: reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000; break; case DIB7000M_POWER_NO: break; } /* always power down unused parts */ if (!state->cfg.mobile_mode) reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); /* P_sdio_select_clk = 0 on MC and after*/ if (state->revision != 0x4000) reg_906 <<= 1; if (state->revision == 0x4003) offset = 1; dib7000m_write_word(state, 903 + offset, reg_903); dib7000m_write_word(state, 904 + offset, reg_904); dib7000m_write_word(state, 905 + offset, reg_905); dib7000m_write_word(state, 906 + offset, reg_906);}static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no){ int ret = 0; u16 reg_913 = dib7000m_read_word(state, 913), reg_914 = dib7000m_read_word(state, 914); switch (no) { case DIBX000_SLOW_ADC_ON: reg_914 |= (1 << 1) | (1 << 0); ret |= dib7000m_write_word(state, 914, reg_914); reg_914 &= ~(1 << 1); break; case DIBX000_SLOW_ADC_OFF: reg_914 |= (1 << 1) | (1 << 0); break; case DIBX000_ADC_ON: if (state->revision == 0x4000) { // workaround for PA/MA // power-up ADC dib7000m_write_word(state, 913, 0); dib7000m_write_word(state, 914, reg_914 & 0x3); // power-down bandgag dib7000m_write_word(state, 913, (1 << 15)); dib7000m_write_word(state, 914, reg_914 & 0x3); } reg_913 &= 0x0fff; reg_914 &= 0x0003; break; case DIBX000_ADC_OFF: // leave the VBG voltage on reg_913 |= (1 << 14) | (1 << 13) | (1 << 12); reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); break; case DIBX000_VBG_ENABLE: reg_913 &= ~(1 << 15); break; case DIBX000_VBG_DISABLE: reg_913 |= (1 << 15); break; default: break; }// dprintk( "913: %x, 914: %x", reg_913, reg_914); ret |= dib7000m_write_word(state, 913, reg_913); ret |= dib7000m_write_word(state, 914, reg_914); return ret;}static int dib7000m_set_bandwidth(struct dib7000m_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->timf_default; } else { dprintk( "using updated timf"); timf = state->timf; } timf = timf * (bw / 50) / 160; dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff)); return 0;}static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff){ struct dib7000m_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) { dib7000m_write_word(state, 263 + state->reg_offs, 6); dib7000m_write_word(state, 264 + state->reg_offs, 6); dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); } else { dib7000m_write_word(state, 263 + state->reg_offs, 1); dib7000m_write_word(state, 264 + state->reg_offs, 0); dib7000m_write_word(state, 266 + state->reg_offs, 0); } return 0;}static int dib7000m_sad_calib(struct dib7000m_state *state){#if 0 double ref,x;/* external */ dib7000m_write_word(state, 928, (1 << 14) | (3 << 12) | (524 << 0)); dib7000m_write_word(state, 929, (1 << 1) | (0 << 0)); dib7000m_write_word(state, 930, 4096); msleep(1); ref = dib7000m_read_word(state, 934); x = 0.625/3.3 * (4096.0/ref); dprintk( "ref: %g = %g (%x)", ref, x, (int) (x * 8192.0) / 2); dib7000m_write_word(state, 930, (int) (x * 8192.0) / 2); dib7000m_write_word(state, 928, (0 << 14) | (1 << 12) | (524 << 0)); msleep(1); ref = dib7000m_read_word(state, 932); dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3); msleep(1); ref = dib7000m_read_word(state, 932); dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3); msleep(1); ref = dib7000m_read_word(state, 932); dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3); msleep(1); ref = dib7000m_read_word(state, 932); dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3); msleep(1); ref = dib7000m_read_word(state, 932); dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3);#else/* internal */// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 /* do the calibration */ dib7000m_write_word(state, 929, (1 << 0)); dib7000m_write_word(state, 929, (0 << 0)); msleep(1);#endif return 0;}static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw){ dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff)); dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff)); dib7000m_write_word(state, 928, bw->sad_cfg);}static void dib7000m_reset_pll(struct dib7000m_state *state){ const struct dibx000_bandwidth_config *bw = state->cfg.bw; u16 reg_907,reg_910; /* default */ reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset; // for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value) // this is only working only for 30 MHz crystals if (!state->cfg.quartz_direct) { reg_910 |= (1 << 5); // forcing the predivider to 1 // if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2) if(state->cfg.input_clk_is_div_2) reg_907 |= (16 << 9); else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary reg_907 |= (8 << 9); } else { reg_907 |= (bw->pll_ratio & 0x3f) << 9; reg_910 |= (bw->pll_prediv << 5); } dib7000m_write_word(state, 910, reg_910); // pll cfg dib7000m_write_word(state, 907, reg_907); // clk cfg0 dib7000m_write_word(state, 908, 0x0006); // clk_cfg1 dib7000m_reset_pll_common(state, bw);}static void dib7000mc_reset_pll(struct dib7000m_state *state){ const struct dibx000_bandwidth_config *bw = state->cfg.bw; u16 clk_cfg1; // clk_cfg0 dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0)); // clk_cfg1 //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) | clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) | (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) | (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0); dib7000m_write_word(state, 908, clk_cfg1); clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3); dib7000m_write_word(state, 908, clk_cfg1); // smpl_cfg dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7)); dib7000m_reset_pll_common(state, bw);}static int dib7000m_reset_gpio(struct dib7000m_state *st){ /* reset the GPIOs */ dib7000m_write_word(st, 773, st->cfg.gpio_dir); dib7000m_write_word(st, 774, st->cfg.gpio_val); /* TODO 782 is P_gpio_od */ dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos); dib7000m_write_word(st, 780, st->cfg.pwm_freq_div); return 0;}static u16 dib7000m_defaults_common[] ={ // auto search configuration 3, 2, 0x0004, 0x1000, 0x0814, 12, 6, 0x001b, 0x7740, 0x005b, 0x8d80, 0x01c9, 0xc380, 0x0000, 0x0080, 0x0000, 0x0090, 0x0001, 0xd4c0, 1, 26, 0x6680, // P_corm_thres Lock algorithms configuration 1, 170, 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on 8, 173,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -