📄 bcm3510.c
字号:
/* Pulse Byte */ c.ctl_dat[15].ctrl.size = BITS_3; c.ctl_dat[15].ctrl.clk_off = 1; c.ctl_dat[15].ctrl.cs1 = 1; c.ctl_dat[15].data = 0x40; return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0);}static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq){ u8 bc,a; u16 n; s32 YIntercept,Tfvco1; freq /= 1000; deb_info("%dkHz:",freq); /* set Band Switch */ if (freq <= 168000) bc = 0x1c; else if (freq <= 378000) bc = 0x2c; else bc = 0x30; if (freq >= 470000) { freq -= 470001; YIntercept = 18805; } else if (freq >= 90000) { freq -= 90001; YIntercept = 15005; } else if (freq >= 76000){ freq -= 76001; YIntercept = 14865; } else { freq -= 54001; YIntercept = 14645; } Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10; n = Tfvco1 >> 6; a = Tfvco1 & 0x3f; deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a); if (n >= 16 && n <= 2047) return bcm3510_tuner_cmd(st,bc,n,a); return -EINVAL;}static int bcm3510_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p){ struct bcm3510_state* st = fe->demodulator_priv; struct bcm3510_hab_cmd_ext_acquire cmd; struct bcm3510_hab_cmd_bert_control bert; int ret; memset(&cmd,0,sizeof(cmd)); switch (p->u.vsb.modulation) { case QAM_256: cmd.ACQUIRE0.MODE = 0x1; cmd.ACQUIRE1.SYM_RATE = 0x1; cmd.ACQUIRE1.IF_FREQ = 0x1; break; case QAM_64: cmd.ACQUIRE0.MODE = 0x2; cmd.ACQUIRE1.SYM_RATE = 0x2; cmd.ACQUIRE1.IF_FREQ = 0x1; break;/* case QAM_256: cmd.ACQUIRE0.MODE = 0x3; break; case QAM_128: cmd.ACQUIRE0.MODE = 0x4; break; case QAM_64: cmd.ACQUIRE0.MODE = 0x5; break; case QAM_32: cmd.ACQUIRE0.MODE = 0x6; break; case QAM_16: cmd.ACQUIRE0.MODE = 0x7; break;*/ case VSB_8: cmd.ACQUIRE0.MODE = 0x8; cmd.ACQUIRE1.SYM_RATE = 0x0; cmd.ACQUIRE1.IF_FREQ = 0x0; break; case VSB_16: cmd.ACQUIRE0.MODE = 0x9; cmd.ACQUIRE1.SYM_RATE = 0x0; cmd.ACQUIRE1.IF_FREQ = 0x0; default: return -EINVAL; }; cmd.ACQUIRE0.OFFSET = 0; cmd.ACQUIRE0.NTSCSWEEP = 1; cmd.ACQUIRE0.FA = 1; cmd.ACQUIRE0.BW = 0;/* if (enableOffset) { cmd.IF_OFFSET0 = xx; cmd.IF_OFFSET1 = xx; cmd.SYM_OFFSET0 = xx; cmd.SYM_OFFSET1 = xx; if (enableNtscSweep) { cmd.NTSC_OFFSET0; cmd.NTSC_OFFSET1; } } */ bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0);/* doing it with different MSGIDs, data book and source differs */ bert.BE = 0; bert.unused = 0; bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0); bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0); bcm3510_bert_reset(st); if ((ret = bcm3510_set_freq(st,p->frequency)) < 0) return ret; memset(&st->status1,0,sizeof(st->status1)); memset(&st->status2,0,sizeof(st->status2)); st->status_check_interval = 500;/* Give the AP some time */ msleep(200); return 0;}static int bcm3510_sleep(struct dvb_frontend* fe){ return 0;}static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s){ s->min_delay_ms = 1000; s->step_size = 0; s->max_drift = 0; return 0;}static void bcm3510_release(struct dvb_frontend* fe){ struct bcm3510_state* state = fe->demodulator_priv; kfree(state);}/* firmware download: * firmware file is build up like this: * 16bit addr, 16bit length, 8byte of length */#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw"static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, u8 *b, u16 len){ int ret = 0,i; bcm3510_register_value vH, vL,vD; vH.MADRH_a9 = addr >> 8; vL.MADRL_aa = addr; if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret; if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret; for (i = 0; i < len; i++) { vD.MDATA_ab = b[i]; if ((ret = bcm3510_writeB(st,0xab,vD)) < 0) return ret; } return 0;}static int bcm3510_download_firmware(struct dvb_frontend* fe){ struct bcm3510_state* st = fe->demodulator_priv; const struct firmware *fw; u16 addr,len; u8 *b; int ret,i; deb_info("requesting firmware\n"); if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) { err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); return ret; } deb_info("got firmware: %d\n",fw->size); b = fw->data; for (i = 0; i < fw->size;) { addr = le16_to_cpu( *( (u16 *)&b[i] ) ); len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size); if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { err("firmware download failed: %d\n",ret); return ret; } i += 4 + len; } release_firmware(fw); deb_info("firmware download successfully completed\n"); return 0;}static int bcm3510_check_firmware_version(struct bcm3510_state *st){ struct bcm3510_hab_cmd_get_version_info ver; bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver)); deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n", ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version); if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION && ver.config_version == BCM3510_DEF_CONFIG_VERSION && ver.demod_version == BCM3510_DEF_DEMOD_VERSION) return 0; deb_info("version check failed\n"); return -ENODEV;}/* (un)resetting the AP */static int bcm3510_reset(struct bcm3510_state *st){ int ret; unsigned long t; bcm3510_register_value v; bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1; if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) return ret; t = jiffies + 3*HZ; while (time_before(jiffies, t)) { msleep(10); if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) return ret; if (v.APSTAT1_a2.RESET) return 0; } deb_info("reset timed out\n"); return -ETIMEDOUT;}static int bcm3510_clear_reset(struct bcm3510_state *st){ bcm3510_register_value v; int ret; unsigned long t; v.raw = 0; if ((ret = bcm3510_writeB(st,0xa0,v)) < 0) return ret; t = jiffies + 3*HZ; while (time_before(jiffies, t)) { msleep(10); if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) return ret; /* verify that reset is cleared */ if (!v.APSTAT1_a2.RESET) return 0; } deb_info("reset clear timed out\n"); return -ETIMEDOUT;}static int bcm3510_init_cold(struct bcm3510_state *st){ int ret; bcm3510_register_value v; /* read Acquisation Processor status register and check it is not in RUN mode */ if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) return ret; if (v.APSTAT1_a2.RUN) { deb_info("AP is already running - firmware already loaded.\n"); return 0; } deb_info("reset?\n"); if ((ret = bcm3510_reset(st)) < 0) return ret; deb_info("tristate?\n"); /* tri-state */ v.TSTCTL_2e.CTL = 0; if ((ret = bcm3510_writeB(st,0x2e,v)) < 0) return ret; deb_info("firmware?\n"); if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 || (ret = bcm3510_clear_reset(st)) < 0) return ret; /* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */ return 0;}static int bcm3510_init(struct dvb_frontend* fe){ struct bcm3510_state* st = fe->demodulator_priv; bcm3510_register_value j; struct bcm3510_hab_cmd_set_agc c; int ret; if ((ret = bcm3510_readB(st,0xca,&j)) < 0) return ret; deb_info("JDEC: %02x\n",j.raw); switch (j.JDEC_ca.JDEC) { case JDEC_WAIT_AT_RAM: deb_info("attempting to download firmware\n"); if ((ret = bcm3510_init_cold(st)) < 0) return ret; case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */ deb_info("firmware is loaded\n"); bcm3510_check_firmware_version(st); break; default: return -ENODEV; } memset(&c,0,1); c.SEL = 1; bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0); return 0;}static struct dvb_frontend_ops bcm3510_ops;struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config, struct i2c_adapter *i2c){ struct bcm3510_state* state = NULL; int ret; bcm3510_register_value v; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct bcm3510_state), GFP_KERNEL); if (state == NULL) goto error; memset(state,0,sizeof(struct bcm3510_state)); /* setup the state */ state->config = config; state->i2c = i2c; memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops)); /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; sema_init(&state->hab_sem, 1); if ((ret = bcm3510_readB(state,0xe0,&v)) < 0) goto error; deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER); if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */ (v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0)) /* warm */ goto error; info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER); bcm3510_reset(state); return &state->frontend;error: kfree(state); return NULL;}EXPORT_SYMBOL(bcm3510_attach);static struct dvb_frontend_ops bcm3510_ops = { .info = { .name = "Broadcom BCM3510 VSB/QAM frontend", .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 803000000, /* stepsize is just a guess */ .frequency_stepsize = 0, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_8VSB | FE_CAN_16VSB | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 }, .release = bcm3510_release, .init = bcm3510_init, .sleep = bcm3510_sleep, .set_frontend = bcm3510_set_frontend, .get_tune_settings = bcm3510_get_tune_settings, .read_status = bcm3510_read_status, .read_ber = bcm3510_read_ber, .read_signal_strength = bcm3510_read_signal_strength, .read_snr = bcm3510_read_snr, .read_ucblocks = bcm3510_read_unc,};MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -