diff -r ce1e93e4e1c8 linux/drivers/media/dvb/dvb-usb/dibusb-common.c --- a/linux/drivers/media/dvb/dvb-usb/dibusb-common.c Tue Nov 25 11:06:21 2008 -0200 +++ b/linux/drivers/media/dvb/dvb-usb/dibusb-common.c Wed Nov 26 08:54:02 2008 +0800 @@ -1,459 +1,473 @@ -/* Common methods for dibusb-based-receivers. - * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * 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. - * - * see Documentation/dvb/README.dvb-usb for more information - */ -#include "dibusb.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS); -MODULE_LICENSE("GPL"); - -#define deb_info(args...) dprintk(debug,0x01,args) - -/* common stuff used by the different dibusb modules */ -int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.fifo_ctrl != NULL) - if (st->ops.fifo_ctrl(adap->fe,onoff)) { - err("error while controlling the fifo of the demod."); - return -ENODEV; - } - } - return 0; -} -EXPORT_SYMBOL(dibusb_streaming_ctrl); - -int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.pid_ctrl != NULL) - st->ops.pid_ctrl(adap->fe,index,pid,onoff); - } - return 0; -} -EXPORT_SYMBOL(dibusb_pid_filter); - -int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - if (st->ops.pid_parse != NULL) - if (st->ops.pid_parse(adap->fe,onoff) < 0) - err("could not handle pid_parser"); - } - return 0; -} -EXPORT_SYMBOL(dibusb_pid_filter_ctrl); - -int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - u8 b[3]; - int ret; - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = DIBUSB_IOCTL_CMD_POWER_MODE; - b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP; - ret = dvb_usb_generic_write(d,b,3); - msleep(10); - return ret; -} -EXPORT_SYMBOL(dibusb_power_ctrl); - -int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - u8 b[3] = { 0 }; - int ret; - - if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0) - return ret; - - if (onoff) { - b[0] = DIBUSB_REQ_SET_STREAMING_MODE; - b[1] = 0x00; - if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0) - return ret; - } - - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; - return dvb_usb_generic_write(adap->dev,b,3); -} -EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); - -int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - if (onoff) { - u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP }; - return dvb_usb_generic_write(d,b,3); - } else - return 0; -} -EXPORT_SYMBOL(dibusb2_0_power_ctrl); - -static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ - /* write only ? */ - int wo = (rbuf == NULL || rlen == 0), - len = 2 + wlen + (wo ? 0 : 2); - - sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; - sndbuf[1] = (addr << 1) | (wo ? 0 : 1); - - memcpy(&sndbuf[2],wbuf,wlen); - - if (!wo) { - sndbuf[wlen+2] = (rlen >> 8) & 0xff; - sndbuf[wlen+3] = rlen & 0xff; - } - - return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0); -} - -/* - * I2C master xfer function - */ -static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len, - msg[i+1].buf,msg[i+1].len) < 0) - break; - i++; - } else - if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) - break; - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static u32 dibusb_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -struct i2c_algorithm dibusb_i2c_algo = { - .master_xfer = dibusb_i2c_xfer, - .functionality = dibusb_i2c_func, -#ifdef NEED_ALGO_CONTROL - .algo_control = dummy_algo_control, -#endif -}; -EXPORT_SYMBOL(dibusb_i2c_algo); - -int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) -{ - u8 wbuf[1] = { offs }; - return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); -} -EXPORT_SYMBOL(dibusb_read_eeprom_byte); - -/* 3000MC/P stuff */ -// Config Adjacent channels Perf -cal22 -static struct dibx000_agc_config dib3000p_mt2060_agc_config = { - .band_caps = BAND_VHF | BAND_UHF, - .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), - - .agc1_max = 48497, - .agc1_min = 23593, - .agc2_max = 46531, - .agc2_min = 24904, - - .agc1_pt1 = 0x65, - .agc1_pt2 = 0x69, - - .agc1_slope1 = 0x51, - .agc1_slope2 = 0x27, - - .agc2_pt1 = 0, - .agc2_pt2 = 0x33, - - .agc2_slope1 = 0x35, - .agc2_slope2 = 0x37, -}; - -static struct dib3000mc_config stk3000p_dib3000p_config = { - &dib3000p_mt2060_agc_config, - - .max_time = 0x196, - .ln_adc_level = 0x1cc7, - - .output_mpeg2_in_188_bytes = 1, - - .agc_command1 = 1, - .agc_command2 = 1, -}; - -static struct dibx000_agc_config dib3000p_panasonic_agc_config = { - .band_caps = BAND_VHF | BAND_UHF, - .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), - - .agc1_max = 56361, - .agc1_min = 22282, - .agc2_max = 47841, - .agc2_min = 36045, - - .agc1_pt1 = 0x3b, - .agc1_pt2 = 0x6b, - - .agc1_slope1 = 0x55, - .agc1_slope2 = 0x1d, - - .agc2_pt1 = 0, - .agc2_pt2 = 0x0a, - - .agc2_slope1 = 0x95, - .agc2_slope2 = 0x1e, -}; - -#if defined(CONFIG_DVB_DIB3000MC) || \ - (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE)) - -static struct dib3000mc_config mod3000p_dib3000p_config = { - &dib3000p_panasonic_agc_config, - - .max_time = 0x51, - .ln_adc_level = 0x1cc7, - - .output_mpeg2_in_188_bytes = 1, - - .agc_command1 = 1, - .agc_command2 = 1, -}; - -int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) -{ - if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || - (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { - if (adap->priv != NULL) { - struct dibusb_state *st = adap->priv; - st->ops.pid_parse = dib3000mc_pid_parse; - st->ops.pid_ctrl = dib3000mc_pid_control; - } - return 0; - } - return -ENODEV; -} -EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); - -static struct mt2060_config stk3000p_mt2060_config = { - 0x60 -}; - -int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dibusb_state *st = adap->priv; - u8 a,b; - u16 if1 = 1220; - struct i2c_adapter *tun_i2c; - - // First IF calibration for Liteon Sticks - if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && - adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { - - dibusb_read_eeprom_byte(adap->dev,0x7E,&a); - dibusb_read_eeprom_byte(adap->dev,0x7F,&b); - - if (a == 0x00) - if1 += b; - else if (a == 0x80) - if1 -= b; - else - warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); - - } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM && - adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) { - u8 desc; - dibusb_read_eeprom_byte(adap->dev, 7, &desc); - if (desc == 2) { - a = 127; - do { - dibusb_read_eeprom_byte(adap->dev, a, &desc); - a--; - } while (a > 7 && (desc == 0xff || desc == 0x00)); - if (desc & 0x80) - if1 -= (0xff - desc); - else - if1 += desc; - } - } - - tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); - if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { - /* not found - use panasonic pll parameters */ - if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) - return -ENOMEM; - } else { - st->mt2060_present = 1; - /* set the correct parameters for the dib3000p */ - dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config); - } - return 0; -} -EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); -#endif - -/* - * common remote control stuff - */ -struct dvb_usb_rc_key dibusb_rc_keys[] = { - /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ - { 0x00, 0x16, KEY_POWER }, - { 0x00, 0x10, KEY_MUTE }, - { 0x00, 0x03, KEY_1 }, - { 0x00, 0x01, KEY_2 }, - { 0x00, 0x06, KEY_3 }, - { 0x00, 0x09, KEY_4 }, - { 0x00, 0x1d, KEY_5 }, - { 0x00, 0x1f, KEY_6 }, - { 0x00, 0x0d, KEY_7 }, - { 0x00, 0x19, KEY_8 }, - { 0x00, 0x1b, KEY_9 }, - { 0x00, 0x15, KEY_0 }, - { 0x00, 0x05, KEY_CHANNELUP }, - { 0x00, 0x02, KEY_CHANNELDOWN }, - { 0x00, 0x1e, KEY_VOLUMEUP }, - { 0x00, 0x0a, KEY_VOLUMEDOWN }, - { 0x00, 0x11, KEY_RECORD }, - { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */ - { 0x00, 0x14, KEY_PLAY }, - { 0x00, 0x1a, KEY_STOP }, - { 0x00, 0x40, KEY_REWIND }, - { 0x00, 0x12, KEY_FASTFORWARD }, - { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */ - { 0x00, 0x4c, KEY_PAUSE }, - { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */ - { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ - { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */ - { 0x00, 0x1c, KEY_EPG }, /* EPG */ - { 0x00, 0x00, KEY_TAB }, /* Tab */ - { 0x00, 0x48, KEY_INFO }, /* Preview */ - { 0x00, 0x04, KEY_LIST }, /* RecordList */ - { 0x00, 0x0f, KEY_TEXT }, /* Teletext */ - /* Key codes for the KWorld/ADSTech/JetWay remote. */ - { 0x86, 0x12, KEY_POWER }, - { 0x86, 0x0f, KEY_SELECT }, /* source */ - { 0x86, 0x0c, KEY_UNKNOWN }, /* scan */ - { 0x86, 0x0b, KEY_EPG }, - { 0x86, 0x10, KEY_MUTE }, - { 0x86, 0x01, KEY_1 }, - { 0x86, 0x02, KEY_2 }, - { 0x86, 0x03, KEY_3 }, - { 0x86, 0x04, KEY_4 }, - { 0x86, 0x05, KEY_5 }, - { 0x86, 0x06, KEY_6 }, - { 0x86, 0x07, KEY_7 }, - { 0x86, 0x08, KEY_8 }, - { 0x86, 0x09, KEY_9 }, - { 0x86, 0x0a, KEY_0 }, - { 0x86, 0x18, KEY_ZOOM }, - { 0x86, 0x1c, KEY_UNKNOWN }, /* preview */ - { 0x86, 0x13, KEY_UNKNOWN }, /* snap */ - { 0x86, 0x00, KEY_UNDO }, - { 0x86, 0x1d, KEY_RECORD }, - { 0x86, 0x0d, KEY_STOP }, - { 0x86, 0x0e, KEY_PAUSE }, - { 0x86, 0x16, KEY_PLAY }, - { 0x86, 0x11, KEY_BACK }, - { 0x86, 0x19, KEY_FORWARD }, - { 0x86, 0x14, KEY_UNKNOWN }, /* pip */ - { 0x86, 0x15, KEY_ESC }, - { 0x86, 0x1a, KEY_UP }, - { 0x86, 0x1e, KEY_DOWN }, - { 0x86, 0x1f, KEY_LEFT }, - { 0x86, 0x1b, KEY_RIGHT }, - - /* Key codes for the DiBcom MOD3000 remote. */ - { 0x80, 0x00, KEY_MUTE }, - { 0x80, 0x01, KEY_TEXT }, - { 0x80, 0x02, KEY_HOME }, - { 0x80, 0x03, KEY_POWER }, - - { 0x80, 0x04, KEY_RED }, - { 0x80, 0x05, KEY_GREEN }, - { 0x80, 0x06, KEY_YELLOW }, - { 0x80, 0x07, KEY_BLUE }, - - { 0x80, 0x08, KEY_DVD }, - { 0x80, 0x09, KEY_AUDIO }, - { 0x80, 0x0a, KEY_MEDIA }, /* Pictures */ - { 0x80, 0x0b, KEY_VIDEO }, - - { 0x80, 0x0c, KEY_BACK }, - { 0x80, 0x0d, KEY_UP }, - { 0x80, 0x0e, KEY_RADIO }, - { 0x80, 0x0f, KEY_EPG }, - - { 0x80, 0x10, KEY_LEFT }, - { 0x80, 0x11, KEY_OK }, - { 0x80, 0x12, KEY_RIGHT }, - { 0x80, 0x13, KEY_UNKNOWN }, /* SAP */ - - { 0x80, 0x14, KEY_TV }, - { 0x80, 0x15, KEY_DOWN }, - { 0x80, 0x16, KEY_MENU }, /* DVD Menu */ - { 0x80, 0x17, KEY_LAST }, - - { 0x80, 0x18, KEY_RECORD }, - { 0x80, 0x19, KEY_STOP }, - { 0x80, 0x1a, KEY_PAUSE }, - { 0x80, 0x1b, KEY_PLAY }, - - { 0x80, 0x1c, KEY_PREVIOUS }, - { 0x80, 0x1d, KEY_REWIND }, - { 0x80, 0x1e, KEY_FASTFORWARD }, - { 0x80, 0x1f, KEY_NEXT}, - - { 0x80, 0x40, KEY_1 }, - { 0x80, 0x41, KEY_2 }, - { 0x80, 0x42, KEY_3 }, - { 0x80, 0x43, KEY_CHANNELUP }, - - { 0x80, 0x44, KEY_4 }, - { 0x80, 0x45, KEY_5 }, - { 0x80, 0x46, KEY_6 }, - { 0x80, 0x47, KEY_CHANNELDOWN }, - - { 0x80, 0x48, KEY_7 }, - { 0x80, 0x49, KEY_8 }, - { 0x80, 0x4a, KEY_9 }, - { 0x80, 0x4b, KEY_VOLUMEUP }, - - { 0x80, 0x4c, KEY_CLEAR }, - { 0x80, 0x4d, KEY_0 }, - { 0x80, 0x4e, KEY_ENTER }, - { 0x80, 0x4f, KEY_VOLUMEDOWN }, -}; -EXPORT_SYMBOL(dibusb_rc_keys); - -int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) -{ - u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE; - dvb_usb_generic_rw(d,&cmd,1,key,5,0); - dvb_usb_nec_rc_key_to_event(d,key,event,state); - if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); - return 0; -} -EXPORT_SYMBOL(dibusb_rc_query); +/* Common methods for dibusb-based-receivers. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * 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. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dibusb.h" + +#include "dib3000mc.h" //20080521, chihming + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS); +MODULE_LICENSE("GPL"); + +#define deb_info(args...) dprintk(debug,0x01,args) + +/* common stuff used by the different dibusb modules */ +int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.fifo_ctrl != NULL) + if (st->ops.fifo_ctrl(adap->fe,onoff)) { + err("error while controlling the fifo of the demod."); + return -ENODEV; + } + } + return 0; +} +EXPORT_SYMBOL(dibusb_streaming_ctrl); + +int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.pid_ctrl != NULL) + st->ops.pid_ctrl(adap->fe,index,pid,onoff); + } + return 0; +} +EXPORT_SYMBOL(dibusb_pid_filter); + +int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + if (st->ops.pid_parse != NULL) + if (st->ops.pid_parse(adap->fe,onoff) < 0) + err("could not handle pid_parser"); + } + return 0; +} +EXPORT_SYMBOL(dibusb_pid_filter_ctrl); + +int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b[3]; + int ret; + b[0] = DIBUSB_REQ_SET_IOCTL; + b[1] = DIBUSB_IOCTL_CMD_POWER_MODE; + b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP; + ret = dvb_usb_generic_write(d,b,3); + msleep(10); + return ret; +} +EXPORT_SYMBOL(dibusb_power_ctrl); +extern struct dib3000mc_state; +int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + u8 b[3] = { 0 }; + int ret; + // 20080521, chihming + struct dvb_frontend *demod = adap->fe; + struct dib3000mc_state *d3000mc_state = demod->demodulator_priv; + d3000mc_state->streaming_ctrl = onoff; + + printk("%s=> %s\n", __FUNCTION__, (onoff)?"on":"off"); //20080516, chihming + + if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0) + return ret; + + if (onoff) { + b[0] = DIBUSB_REQ_SET_STREAMING_MODE; + b[1] = 0x00; + if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0) + return ret; + } + + b[0] = DIBUSB_REQ_SET_IOCTL; + b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; + return dvb_usb_generic_write(adap->dev,b,3); +} +EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); + +int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + #if 1 //20080515, chihming, dont remove + if (onoff) { + u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP }; + int ret = dvb_usb_generic_write(d,b,3); + printk("dibusb2_0_power_ctrl: ret of dvb_usb_generic_write ==> %d\n", ret); + return ret; + //return dvb_usb_generic_write(d,b,3); + } else + return 0; + #endif + + return 0; +} +EXPORT_SYMBOL(dibusb2_0_power_ctrl); + +static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ + /* write only ? */ + int wo = (rbuf == NULL || rlen == 0), + len = 2 + wlen + (wo ? 0 : 2); + + sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; + sndbuf[1] = (addr << 1) | (wo ? 0 : 1); + + memcpy(&sndbuf[2],wbuf,wlen); + + if (!wo) { + sndbuf[wlen+2] = (rlen >> 8) & 0xff; + sndbuf[wlen+3] = rlen & 0xff; + } + //printk("dibusb_i2c_xfer: addr %x sb:%x %x %x %x %x %x slen %d \n",addr,sndbuf[0],sndbuf[1],sndbuf[2],sndbuf[3],sndbuf[4],sndbuf[5],len); + return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0); +} + +/* + * I2C master xfer function + */ +static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + //printk("dibusb_i2c_xfer: num %x \n",num); //JHA + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len, + msg[i+1].buf,msg[i+1].len) < 0) + break; + i++; + } else + if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) + break; + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 dibusb_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm dibusb_i2c_algo = { + .master_xfer = dibusb_i2c_xfer, + .functionality = dibusb_i2c_func, +}; +EXPORT_SYMBOL(dibusb_i2c_algo); + +int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) +{ + u8 wbuf[1] = { offs }; + return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1); +} +EXPORT_SYMBOL(dibusb_read_eeprom_byte); + +/* 3000MC/P stuff */ +// Config Adjacent channels Perf -cal22 +static struct dibx000_agc_config dib3000p_mt2060_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 48497, + .agc1_min = 23593, + .agc2_max = 46531, + .agc2_min = 24904, + + .agc1_pt1 = 0x65, + .agc1_pt2 = 0x69, + + .agc1_slope1 = 0x51, + .agc1_slope2 = 0x27, + + .agc2_pt1 = 0, + .agc2_pt2 = 0x33, + + .agc2_slope1 = 0x35, + .agc2_slope2 = 0x37, +}; + +static struct dib3000mc_config stk3000p_dib3000p_config = { + &dib3000p_mt2060_agc_config, + + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + + .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, +}; + +static struct dibx000_agc_config dib3000p_panasonic_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 56361, + .agc1_min = 22282, + .agc2_max = 47841, + .agc2_min = 36045, + + .agc1_pt1 = 0x3b, + .agc1_pt2 = 0x6b, + + .agc1_slope1 = 0x55, + .agc1_slope2 = 0x1d, + + .agc2_pt1 = 0, + .agc2_pt2 = 0x0a, + + .agc2_slope1 = 0x95, + .agc2_slope2 = 0x1e, +}; + +static struct dib3000mc_config mod3000p_dib3000p_config = { + &dib3000p_panasonic_agc_config, + + .max_time = 0x51, + .ln_adc_level = 0x1cc7, + + .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, +}; + +int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) +{ + if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || + (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + st->ops.pid_parse = dib3000mc_pid_parse; + st->ops.pid_ctrl = dib3000mc_pid_control; + } + return 0; + } + return -ENODEV; +} +EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); + +static struct mt2060_config stk3000p_mt2060_config = { + 0x60 +}; + +static struct mt2060_config stk3000p_adimtv102_config = { + (0xC2>>1) +}; + + +int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + u8 a,b; + u16 if1 = 1220; + struct i2c_adapter *tun_i2c; + + // First IF calibration for Liteon Sticks + if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && + adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { + + dibusb_read_eeprom_byte(adap->dev,0x7E,&a); + dibusb_read_eeprom_byte(adap->dev,0x7F,&b); + + if (a == 0x00) + if1 += b; + else if (a == 0x80) + if1 -= b; + else + warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); + + } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM && + adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) { + u8 desc; + dibusb_read_eeprom_byte(adap->dev, 7, &desc); + if (desc == 2) { + a = 127; + do { + dibusb_read_eeprom_byte(adap->dev, a, &desc); + a--; + } while (a > 7 && (desc == 0xff || desc == 0x00)); + if (desc & 0x80) + if1 -= (0xff - desc); + else + if1 += desc; + } + } + + tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); + //if (dvb_attach(adimtv102_attach, adap->fe, &adap->dev->i2c_adap, &stk3000p_adimtv102_config, if1) == NULL) { + /* not found - use panasonic pll parameters */ + // if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) + // return -ENOMEM; + //} else { + st->mt2060_present = 1; + /* set the correct parameters for the dib3000p */ + //dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config); JHA + //} + return 0; +} +EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); + +/* + * common remote control stuff + */ +struct dvb_usb_rc_key dibusb_rc_keys[] = { + /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ + { 0x00, 0x16, KEY_POWER }, + { 0x00, 0x10, KEY_MUTE }, + { 0x00, 0x03, KEY_1 }, + { 0x00, 0x01, KEY_2 }, + { 0x00, 0x06, KEY_3 }, + { 0x00, 0x09, KEY_4 }, + { 0x00, 0x1d, KEY_5 }, + { 0x00, 0x1f, KEY_6 }, + { 0x00, 0x0d, KEY_7 }, + { 0x00, 0x19, KEY_8 }, + { 0x00, 0x1b, KEY_9 }, + { 0x00, 0x15, KEY_0 }, + { 0x00, 0x05, KEY_CHANNELUP }, + { 0x00, 0x02, KEY_CHANNELDOWN }, + { 0x00, 0x1e, KEY_VOLUMEUP }, + { 0x00, 0x0a, KEY_VOLUMEDOWN }, + { 0x00, 0x11, KEY_RECORD }, + { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */ + { 0x00, 0x14, KEY_PLAY }, + { 0x00, 0x1a, KEY_STOP }, + { 0x00, 0x40, KEY_REWIND }, + { 0x00, 0x12, KEY_FASTFORWARD }, + { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */ + { 0x00, 0x4c, KEY_PAUSE }, + { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */ + { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ + /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ + { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */ + { 0x00, 0x1c, KEY_EPG }, /* EPG */ + { 0x00, 0x00, KEY_TAB }, /* Tab */ + { 0x00, 0x48, KEY_INFO }, /* Preview */ + { 0x00, 0x04, KEY_LIST }, /* RecordList */ + { 0x00, 0x0f, KEY_TEXT }, /* Teletext */ + /* Key codes for the KWorld/ADSTech/JetWay remote. */ + { 0x86, 0x12, KEY_POWER }, + { 0x86, 0x0f, KEY_SELECT }, /* source */ + { 0x86, 0x0c, KEY_UNKNOWN }, /* scan */ + { 0x86, 0x0b, KEY_EPG }, + { 0x86, 0x10, KEY_MUTE }, + { 0x86, 0x01, KEY_1 }, + { 0x86, 0x02, KEY_2 }, + { 0x86, 0x03, KEY_3 }, + { 0x86, 0x04, KEY_4 }, + { 0x86, 0x05, KEY_5 }, + { 0x86, 0x06, KEY_6 }, + { 0x86, 0x07, KEY_7 }, + { 0x86, 0x08, KEY_8 }, + { 0x86, 0x09, KEY_9 }, + { 0x86, 0x0a, KEY_0 }, + { 0x86, 0x18, KEY_ZOOM }, + { 0x86, 0x1c, KEY_UNKNOWN }, /* preview */ + { 0x86, 0x13, KEY_UNKNOWN }, /* snap */ + { 0x86, 0x00, KEY_UNDO }, + { 0x86, 0x1d, KEY_RECORD }, + { 0x86, 0x0d, KEY_STOP }, + { 0x86, 0x0e, KEY_PAUSE }, + { 0x86, 0x16, KEY_PLAY }, + { 0x86, 0x11, KEY_BACK }, + { 0x86, 0x19, KEY_FORWARD }, + { 0x86, 0x14, KEY_UNKNOWN }, /* pip */ + { 0x86, 0x15, KEY_ESC }, + { 0x86, 0x1a, KEY_UP }, + { 0x86, 0x1e, KEY_DOWN }, + { 0x86, 0x1f, KEY_LEFT }, + { 0x86, 0x1b, KEY_RIGHT }, + + /* Key codes for the DiBcom MOD3000 remote. */ + { 0x80, 0x00, KEY_MUTE }, + { 0x80, 0x01, KEY_TEXT }, + { 0x80, 0x02, KEY_HOME }, + { 0x80, 0x03, KEY_POWER }, + + { 0x80, 0x04, KEY_RED }, + { 0x80, 0x05, KEY_GREEN }, + { 0x80, 0x06, KEY_YELLOW }, + { 0x80, 0x07, KEY_BLUE }, + + { 0x80, 0x08, KEY_DVD }, + { 0x80, 0x09, KEY_AUDIO }, + { 0x80, 0x0a, KEY_MEDIA }, /* Pictures */ + { 0x80, 0x0b, KEY_VIDEO }, + + { 0x80, 0x0c, KEY_BACK }, + { 0x80, 0x0d, KEY_UP }, + { 0x80, 0x0e, KEY_RADIO }, + { 0x80, 0x0f, KEY_EPG }, + + { 0x80, 0x10, KEY_LEFT }, + { 0x80, 0x11, KEY_OK }, + { 0x80, 0x12, KEY_RIGHT }, + { 0x80, 0x13, KEY_UNKNOWN }, /* SAP */ + + { 0x80, 0x14, KEY_TV }, + { 0x80, 0x15, KEY_DOWN }, + { 0x80, 0x16, KEY_MENU }, /* DVD Menu */ + { 0x80, 0x17, KEY_LAST }, + + { 0x80, 0x18, KEY_RECORD }, + { 0x80, 0x19, KEY_STOP }, + { 0x80, 0x1a, KEY_PAUSE }, + { 0x80, 0x1b, KEY_PLAY }, + + { 0x80, 0x1c, KEY_PREVIOUS }, + { 0x80, 0x1d, KEY_REWIND }, + { 0x80, 0x1e, KEY_FASTFORWARD }, + { 0x80, 0x1f, KEY_NEXT}, + + { 0x80, 0x40, KEY_1 }, + { 0x80, 0x41, KEY_2 }, + { 0x80, 0x42, KEY_3 }, + { 0x80, 0x43, KEY_CHANNELUP }, + + { 0x80, 0x44, KEY_4 }, + { 0x80, 0x45, KEY_5 }, + { 0x80, 0x46, KEY_6 }, + { 0x80, 0x47, KEY_CHANNELDOWN }, + + { 0x80, 0x48, KEY_7 }, + { 0x80, 0x49, KEY_8 }, + { 0x80, 0x4a, KEY_9 }, + { 0x80, 0x4b, KEY_VOLUMEUP }, + + { 0x80, 0x4c, KEY_CLEAR }, + { 0x80, 0x4d, KEY_0 }, + { 0x80, 0x4e, KEY_ENTER }, + { 0x80, 0x4f, KEY_VOLUMEDOWN }, +}; +EXPORT_SYMBOL(dibusb_rc_keys); + +int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE; + dvb_usb_generic_rw(d,&cmd,1,key,5,0); + dvb_usb_nec_rc_key_to_event(d,key,event,state); + if (key[0] != 0) + deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + return 0; +} +EXPORT_SYMBOL(dibusb_rc_query); diff -r ce1e93e4e1c8 linux/drivers/media/dvb/dvb-usb/dibusb-mc.c --- a/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c Tue Nov 25 11:06:21 2008 -0200 +++ b/linux/drivers/media/dvb/dvb-usb/dibusb-mc.c Wed Nov 26 08:54:02 2008 +0800 @@ -22,26 +22,64 @@ static int dibusb_mc_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE, - NULL, adapter_nr); + printk("dibusb_mc_probe");//JHA + return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE,NULL,adapter_nr); +} + +// 20080513, chihming +static int asus_dmbth_identify_state (struct usb_device *udev, struct + dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, + int *cold) +{ + + static unsigned short int pid=0; + //printk("%s: iManufacturer => %d, iProduct => 0x%0x\n",__FUNCTION__, udev->descriptor.iManufacturer, udev->descriptor.iProduct);//20080513, chihming + *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; + #if 0 + t = last_tick + 3*HZ; + if (time_before(jiffies, t)) + *cold = false; + else + *cold = true; + if (last_tick == 0) + *cold = true; + last_tick = jiffies; + printk("time_before => %s\n", (*cold) ? "true":"false"); + #endif + // 20071103, chihming + #if 1 + //printk("%s: pid => 0x%x, idProduct => 0x%x\n", __FUNCTION__, pid, le16_to_cpu(udev->descriptor.idProduct)) + if (pid == 0 && (0x1749 == le16_to_cpu(udev->descriptor.idProduct))) + { + int ret = usb_trylock_device(udev); + if (ret == 1) { + ret = usb_reset_device(udev); + usb_unlock_device(udev); + //printk("usb_reset_device1"); + } else { + ret = usb_reset_device(udev); + //printk("usb_reset_device2"); + } + msleep(100); + //printk("%s\n", __FUNCTION__); + } + pid = le16_to_cpu(udev->descriptor.idProduct); + //printk("%s: Now pid => 0x%x\n", __FUNCTION__, pid); + #endif + // + + + return 0; } /* do not change the order of the ID table */ static struct usb_device_id dibusb_dib3000mc_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, -/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, -/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? ) -/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) }, -/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) }, -/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) }, -/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) }, -/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) }, -/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) }, -/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) }, -/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) }, -/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) }, -/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) }, +/* 0 */ {USB_DEVICE (USB_VID_ASUSTeK, USB_PID_U3100_8934_COLD) }, //JHA +/* 1 */ {USB_DEVICE (USB_VID_ASUSTeK, USB_PID_U3100_8934_WARM) }, //JHA +/* 2 */ {USB_DEVICE (USB_VID_ASUSTeK, USB_PID_U3100_8GL5_COLD) }, //JHA +/* 3 */ {USB_DEVICE (USB_VID_ASUSTeK, USB_PID_U3100_8GL5_WARM) }, //JHA + + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table); @@ -50,7 +88,7 @@ .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-dibusb-6.0.0.8.fw", + .firmware = "u3100dmbth.fw", .num_adapters = 1, .adapter = { @@ -67,7 +105,7 @@ .stream = { .type = USB_BULK, .count = 7, - .endpoint = 0x06, + .endpoint = 0x02, .u = { .bulk = { .buffersize = 4096, @@ -77,6 +115,7 @@ .size_of_priv = sizeof(struct dibusb_state), } }, + .identify_state = asus_dmbth_identify_state, // 20080513, chihming .power_ctrl = dibusb2_0_power_ctrl, .rc_interval = DEFAULT_RC_INTERVAL, @@ -90,35 +129,19 @@ .num_device_descs = 7, .devices = { - { "DiBcom USB2.0 DVB-T reference design (MOD3000P)", - { &dibusb_dib3000mc_table[0], NULL }, - { &dibusb_dib3000mc_table[1], NULL }, - }, - { "Artec T1 USB2.0 TVBOX (please check the warm ID)", - { &dibusb_dib3000mc_table[2], NULL }, - { &dibusb_dib3000mc_table[3], NULL }, - }, - { "LITE-ON USB2.0 DVB-T Tuner", - /* Also rebranded as Intuix S800, Toshiba */ - { &dibusb_dib3000mc_table[4], NULL }, - { &dibusb_dib3000mc_table[5], NULL }, - }, - { "MSI Digivox Mini SL", - { &dibusb_dib3000mc_table[6], NULL }, - { &dibusb_dib3000mc_table[7], NULL }, - }, - { "GRAND - USB2.0 DVB-T adapter", - { &dibusb_dib3000mc_table[8], NULL }, - { &dibusb_dib3000mc_table[9], NULL }, - }, - { "Artec T14 - USB2.0 DVB-T", - { &dibusb_dib3000mc_table[10], NULL }, - { &dibusb_dib3000mc_table[11], NULL }, - }, - { "Leadtek - USB2.0 Winfast DTV dongle", - { &dibusb_dib3000mc_table[12], NULL }, - { &dibusb_dib3000mc_table[13], NULL }, - }, + //{,JHA + { "ASUSTeK DMB-TH ", + { &dibusb_dib3000mc_table[0], NULL }, + { &dibusb_dib3000mc_table[1], NULL }, + }, + { "ASUSTeK DMB-TH", + { &dibusb_dib3000mc_table[2], NULL }, + { &dibusb_dib3000mc_table[3], NULL }, + }, + //},JHA + + + { NULL }, } }; diff -r ce1e93e4e1c8 linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c Tue Nov 25 11:06:21 2008 -0200 +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c Wed Nov 26 08:54:02 2008 +0800 @@ -126,8 +126,9 @@ if ((*pos + hx->len + 4) >= fw->size) return -EINVAL; - - hx->addr = b[1] | (b[2] << 8); + // added??? to fix something - ak based on diff.. + hx->addr = le16_to_cpu( *((u16 *) &b[1]) ); + //hx->addr = b[1] | (b[2] << 8); hx->type = b[3]; if (hx->type == 0x04) { diff -r ce1e93e4e1c8 linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h Tue Nov 25 11:06:21 2008 -0200 +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h Wed Nov 26 08:54:02 2008 +0800 @@ -19,6 +19,7 @@ #define USB_VID_ANSONIC 0x10b9 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd #define USB_VID_ASUS 0x0b05 +#define USB_VID_ASUSTeK 0x0b05 #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f @@ -228,6 +229,10 @@ #define USB_PID_ASUS_U3000 0x171f #define USB_PID_ASUS_U3000H 0x1736 #define USB_PID_ASUS_U3100 0x173f +#define USB_PID_U3100_8934_COLD 0x1748 //JHA +#define USB_PID_U3100_8934_WARM 0x1749 //JHA +#define USB_PID_U3100_8GL5_COLD 0x1721 //JHA +#define USB_PID_U3100_8GL5_WARM 0x1722 //JHA #define USB_PID_YUAN_EC372S 0x1edc #define USB_PID_YUAN_STK7700PH 0x1f08 #define USB_PID_DW2102 0x2102 diff -r ce1e93e4e1c8 linux/drivers/media/dvb/frontends/dib3000mc.c --- a/linux/drivers/media/dvb/frontends/dib3000mc.c Tue Nov 25 11:06:21 2008 -0200 +++ b/linux/drivers/media/dvb/frontends/dib3000mc.c Wed Nov 26 08:54:02 2008 +0800 @@ -1,934 +1,2341 @@ -/* - * Driver for DiBcom DiB3000MC/P-demodulator. - * - * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/) - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * - * This code is partially based on the previous dib3000mc.c . - * - * 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 -#include -#include "compat.h" - -#include "dvb_frontend.h" - -#include "dib3000mc.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 "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) - -struct dib3000mc_state { - struct dvb_frontend demod; - struct dib3000mc_config *cfg; - - u8 i2c_addr; - struct i2c_adapter *i2c_adap; - - struct dibx000_i2c_master i2c_master; - - u32 timf; - - fe_bandwidth_t current_bandwidth; - - u16 dev_id; - - u8 sfn_workaround_active :1; -}; - -static u16 dib3000mc_read_word(struct dib3000mc_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\n",reg); - - return (rb[0] << 8) | rb[1]; -} - -static int dib3000mc_write_word(struct dib3000mc_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 int dib3000mc_identify(struct dib3000mc_state *state) -{ - u16 value; - if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) { - dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value); - return -EREMOTEIO; - } - - value = dib3000mc_read_word(state, 1026); - if (value != 0x3001 && value != 0x3002) { - dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value); - return -EREMOTEIO; - } - state->dev_id = value; - - dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id); - - return 0; -} - -static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset) -{ - u32 timf; - - if (state->timf == 0) { - timf = 1384402; // default value for 8MHz - if (update_offset) - msleep(200); // first time we do an update - } else - timf = state->timf; - - timf *= (bw / 1000); - - if (update_offset) { - s16 tim_offs = dib3000mc_read_word(state, 416); - - if (tim_offs & 0x2000) - tim_offs -= 0x4000; - - if (nfft == TRANSMISSION_MODE_2K) - tim_offs *= 4; - - timf += tim_offs; - state->timf = timf / (bw / 1000); - } - - dprintk("timf: %d\n", timf); - - dib3000mc_write_word(state, 23, (u16) (timf >> 16)); - dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff); - - return 0; -} - -static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state) -{ - u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb; - if (state->cfg->pwm3_inversion) { - reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0); - reg_52 |= (1 << 2); - } else { - reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0); - reg_52 |= (1 << 8); - } - dib3000mc_write_word(state, 51, reg_51); - dib3000mc_write_word(state, 52, reg_52); - - if (state->cfg->use_pwm3) - dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0)); - else - dib3000mc_write_word(state, 245, 0); - - dib3000mc_write_word(state, 1040, 0x3); - return 0; -} - -static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode) -{ - int ret = 0; - u16 fifo_threshold = 1792; - u16 outreg = 0; - u16 outmode = 0; - u16 elecout = 1; - u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */ - - dprintk("-I- Setting output mode for demod %p to %d\n", - &state->demod, mode); - - switch (mode) { - case OUTMODE_HIGH_Z: // disable - elecout = 0; - break; - case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock - outmode = 0; - break; - case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock - outmode = 1; - break; - case OUTMODE_MPEG2_SERIAL: // STBs with serial input - outmode = 2; - break; - case OUTMODE_MPEG2_FIFO: // e.g. USB feeding - elecout = 3; - /*ADDR @ 206 : - P_smo_error_discard [1;6:6] = 0 - P_smo_rs_discard [1;5:5] = 0 - P_smo_pid_parse [1;4:4] = 0 - P_smo_fifo_flush [1;3:3] = 0 - P_smo_mode [2;2:1] = 11 - P_smo_ovf_prot [1;0:0] = 0 - */ - smo_reg |= 3 << 1; - fifo_threshold = 512; - outmode = 5; - break; - case OUTMODE_DIVERSITY: - outmode = 4; - elecout = 1; - break; - default: - dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod); - outmode = 0; - break; - } - - if ((state->cfg->output_mpeg2_in_188_bytes)) - smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1 - - outreg = dib3000mc_read_word(state, 244) & 0x07FF; - outreg |= (outmode << 11); - ret |= dib3000mc_write_word(state, 244, outreg); - ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/ - ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */ - ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */ - return ret; -} - -static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw) -{ - u16 bw_cfg[6] = { 0 }; - u16 imp_bw_cfg[3] = { 0 }; - u16 reg; - -/* settings here are for 27.7MHz */ - switch (bw) { - case 8000: - bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20; - imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7; - break; - - case 7000: - bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7; - imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0; - break; - - case 6000: - bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5; - imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089; - break; - - case 5000: - bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500; - imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072; - break; - - default: return -EINVAL; - } - - for (reg = 6; reg < 12; reg++) - dib3000mc_write_word(state, reg, bw_cfg[reg - 6]); - dib3000mc_write_word(state, 12, 0x0000); - dib3000mc_write_word(state, 13, 0x03e8); - dib3000mc_write_word(state, 14, 0x0000); - dib3000mc_write_word(state, 15, 0x03f2); - dib3000mc_write_word(state, 16, 0x0001); - dib3000mc_write_word(state, 17, 0xb0d0); - // P_sec_len - dib3000mc_write_word(state, 18, 0x0393); - dib3000mc_write_word(state, 19, 0x8700); - - for (reg = 55; reg < 58; reg++) - dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]); - - // Timing configuration - dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0); - - return 0; -} - -static u16 impulse_noise_val[29] = - -{ - 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3, - 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2, - 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd -}; - -static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft) -{ - u16 i; - for (i = 58; i < 87; i++) - dib3000mc_write_word(state, i, impulse_noise_val[i-58]); - - if (nfft == TRANSMISSION_MODE_8K) { - dib3000mc_write_word(state, 58, 0x3b); - dib3000mc_write_word(state, 84, 0x00); - dib3000mc_write_word(state, 85, 0x8200); - } - - dib3000mc_write_word(state, 34, 0x1294); - dib3000mc_write_word(state, 35, 0x1ff8); - if (mode == 1) - dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10)); -} - -static int dib3000mc_init(struct dvb_frontend *demod) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - struct dibx000_agc_config *agc = state->cfg->agc; - - // Restart Configuration - dib3000mc_write_word(state, 1027, 0x8000); - dib3000mc_write_word(state, 1027, 0x0000); - - // power up the demod + mobility configuration - dib3000mc_write_word(state, 140, 0x0000); - dib3000mc_write_word(state, 1031, 0); - - if (state->cfg->mobile_mode) { - dib3000mc_write_word(state, 139, 0x0000); - dib3000mc_write_word(state, 141, 0x0000); - dib3000mc_write_word(state, 175, 0x0002); - dib3000mc_write_word(state, 1032, 0x0000); - } else { - dib3000mc_write_word(state, 139, 0x0001); - dib3000mc_write_word(state, 141, 0x0000); - dib3000mc_write_word(state, 175, 0x0000); - dib3000mc_write_word(state, 1032, 0x012C); - } - dib3000mc_write_word(state, 1033, 0x0000); - - // P_clk_cfg - dib3000mc_write_word(state, 1037, 0x3130); - - // other configurations - - // P_ctrl_sfreq - dib3000mc_write_word(state, 33, (5 << 0)); - dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0)); - - // Phase noise control - // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange - dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0)); - - if (state->cfg->phase_noise_mode == 0) - dib3000mc_write_word(state, 111, 0x00); - else - dib3000mc_write_word(state, 111, 0x02); - - // P_agc_global - dib3000mc_write_word(state, 50, 0x8000); - - // agc setup misc - dib3000mc_setup_pwm_state(state); - - // P_agc_counter_lock - dib3000mc_write_word(state, 53, 0x87); - // P_agc_counter_unlock - dib3000mc_write_word(state, 54, 0x87); - - /* agc */ - dib3000mc_write_word(state, 36, state->cfg->max_time); - dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0)); - dib3000mc_write_word(state, 38, state->cfg->pwm3_value); - dib3000mc_write_word(state, 39, state->cfg->ln_adc_level); - - // set_agc_loop_Bw - dib3000mc_write_word(state, 40, 0x0179); - dib3000mc_write_word(state, 41, 0x03f0); - - dib3000mc_write_word(state, 42, agc->agc1_max); - dib3000mc_write_word(state, 43, agc->agc1_min); - dib3000mc_write_word(state, 44, agc->agc2_max); - dib3000mc_write_word(state, 45, agc->agc2_min); - dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2); - dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2); - dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2); - -// Begin: TimeOut registers - // P_pha3_thres - dib3000mc_write_word(state, 110, 3277); - // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80 - dib3000mc_write_word(state, 26, 0x6680); - // lock_mask0 - dib3000mc_write_word(state, 1, 4); - // lock_mask1 - dib3000mc_write_word(state, 2, 4); - // lock_mask2 - dib3000mc_write_word(state, 3, 0x1000); - // P_search_maxtrial=1 - dib3000mc_write_word(state, 5, 1); - - dib3000mc_set_bandwidth(state, 8000); - - // div_lock_mask - dib3000mc_write_word(state, 4, 0x814); - - dib3000mc_write_word(state, 21, (1 << 9) | 0x164); - dib3000mc_write_word(state, 22, 0x463d); - - // Spurious rm cfg - // P_cspu_regul, P_cspu_win_cut - dib3000mc_write_word(state, 120, 0x200f); - // P_adp_selec_monit - dib3000mc_write_word(state, 134, 0); - - // Fec cfg - dib3000mc_write_word(state, 195, 0x10); - - // diversity register: P_dvsy_sync_wait.. - dib3000mc_write_word(state, 180, 0x2FF0); - - // Impulse noise configuration - dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K); - - // output mode set-up - dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); - - /* close the i2c-gate */ - dib3000mc_write_word(state, 769, (1 << 7) ); - - return 0; -} - -static int dib3000mc_sleep(struct dvb_frontend *demod) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - - dib3000mc_write_word(state, 1031, 0xFFFF); - dib3000mc_write_word(state, 1032, 0xFFFF); - dib3000mc_write_word(state, 1033, 0xFFF0); - - return 0; -} - -static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) -{ - u16 cfg[4] = { 0 },reg; - switch (qam) { - case QPSK: - cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0; - break; - case QAM_16: - cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0; - break; - case QAM_64: - cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8; - break; - } - for (reg = 129; reg < 133; reg++) - dib3000mc_write_word(state, reg, cfg[reg - 129]); -} - -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) -{ - u16 value; - dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); - -// if (boost) -// dib3000mc_write_word(state, 100, (11 << 6) + 6); -// else - dib3000mc_write_word(state, 100, (16 << 6) + 9); - - dib3000mc_write_word(state, 1027, 0x0800); - dib3000mc_write_word(state, 1027, 0x0000); - - //Default cfg isi offset adp - dib3000mc_write_word(state, 26, 0x6680); - dib3000mc_write_word(state, 29, 0x1273); - dib3000mc_write_word(state, 33, 5); - dib3000mc_set_adp_cfg(state, QAM_16); - dib3000mc_write_word(state, 133, 15564); - - dib3000mc_write_word(state, 12 , 0x0); - dib3000mc_write_word(state, 13 , 0x3e8); - dib3000mc_write_word(state, 14 , 0x0); - dib3000mc_write_word(state, 15 , 0x3f2); - - dib3000mc_write_word(state, 93,0); - dib3000mc_write_word(state, 94,0); - dib3000mc_write_word(state, 95,0); - dib3000mc_write_word(state, 96,0); - dib3000mc_write_word(state, 97,0); - dib3000mc_write_word(state, 98,0); - - dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); - - value = 0; - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: value |= (0 << 7); break; - default: - case TRANSMISSION_MODE_8K: value |= (1 << 7); break; - } - switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_32: value |= (0 << 5); break; - case GUARD_INTERVAL_1_16: value |= (1 << 5); break; - case GUARD_INTERVAL_1_4: value |= (3 << 5); break; - default: - case GUARD_INTERVAL_1_8: value |= (2 << 5); break; - } - switch (ch->u.ofdm.constellation) { - case QPSK: value |= (0 << 3); break; - case QAM_16: value |= (1 << 3); break; - default: - case QAM_64: value |= (2 << 3); break; - } - switch (HIERARCHY_1) { - case HIERARCHY_2: value |= 2; break; - case HIERARCHY_4: value |= 4; break; - default: - case HIERARCHY_1: value |= 1; break; - } - dib3000mc_write_word(state, 0, value); - dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); - - value = 0; - if (ch->u.ofdm.hierarchy_information == 1) - value |= (1 << 4); - if (1 == 1) - value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { - case FEC_2_3: value |= (2 << 1); break; - case FEC_3_4: value |= (3 << 1); break; - case FEC_5_6: value |= (5 << 1); break; - case FEC_7_8: value |= (7 << 1); break; - default: - case FEC_1_2: value |= (1 << 1); break; - } - dib3000mc_write_word(state, 181, value); - - // diversity synchro delay add 50% SFN margin - switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: value = 256; break; - case TRANSMISSION_MODE_2K: - default: value = 64; break; - } - switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_16: value *= 2; break; - case GUARD_INTERVAL_1_8: value *= 4; break; - case GUARD_INTERVAL_1_4: value *= 8; break; - default: - case GUARD_INTERVAL_1_32: value *= 1; break; - } - value <<= 4; - value |= dib3000mc_read_word(state, 180) & 0x000f; - dib3000mc_write_word(state, 180, value); - - // restart demod - value = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, value | (1 << 9)); - dib3000mc_write_word(state, 0, value); - - msleep(30); - - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); -} - -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - u16 reg; -// u32 val; - struct dvb_frontend_parameters schan; - - schan = *chan; - - /* TODO what is that ? */ -#if 0 - if (boost) { - val = (dib3000mc_read_word(state, 6) << 16) | dib3000mc_read_word(state, 7); - val *= 85; - val >>= 7; - dib3000mc_write_word(state, 6, (val >> 16) & 0xffff); - dib3000mc_write_word(state, 7, (val ) & 0xffff); - } -#endif - - /* a channel for autosearch */ - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_2_3; - schan.u.ofdm.hierarchy_information = 0; - - dib3000mc_set_channel_cfg(state, &schan, 11); - - reg = dib3000mc_read_word(state, 0); - dib3000mc_write_word(state, 0, reg | (1 << 8)); - dib3000mc_read_word(state, 511); - dib3000mc_write_word(state, 0, reg); - - return 0; -} - -static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - u16 irq_pending = dib3000mc_read_word(state, 511); - - if (irq_pending & 0x1) // failed - return 1; - - if (irq_pending & 0x2) // succeeded - return 2; - - return 0; // still pending -} - -static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) -{ - struct dib3000mc_state *state = demod->demodulator_priv; - - // ** configure demod ** - dib3000mc_set_channel_cfg(state, ch, 0); - - // activates isi - if (state->sfn_workaround_active) { - dprintk("SFN workaround is active\n"); - dib3000mc_write_word(state, 29, 0x1273); - dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift - } else { - dib3000mc_write_word(state, 29, 0x1073); - dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift - } - - dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); - if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { - dib3000mc_write_word(state, 26, 38528); - dib3000mc_write_word(state, 33, 8); - } else { - dib3000mc_write_word(state, 26, 30336); - dib3000mc_write_word(state, 33, 6); - } - - if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); - - return 0; -} - -struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating) -{ - struct dib3000mc_state *st = demod->demodulator_priv; - return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating); -} - -EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master); - -static int dib3000mc_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - u16 tps = dib3000mc_read_word(state,458); - - fep->inversion = INVERSION_AUTO; - - fep->u.ofdm.bandwidth = state->current_bandwidth; - - switch ((tps >> 8) & 0x1) { - case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; - } - - switch (tps & 0x3) { - case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; - case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; - case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; - case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; - } - - switch ((tps >> 13) & 0x3) { - case 0: fep->u.ofdm.constellation = QPSK; break; - case 1: fep->u.ofdm.constellation = QAM_16; break; - case 2: - default: fep->u.ofdm.constellation = QAM_64; break; - } - - /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ - /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */ - - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; - switch ((tps >> 5) & 0x7) { - case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; - case 7: - default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; - - } - - switch ((tps >> 2) & 0x7) { - case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; - case 7: - default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; - } - - return 0; -} - -static int dib3000mc_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - int ret; - - dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); - - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); - - /* maybe the parameter has been changed */ - state->sfn_workaround_active = buggy_sfn_workaround; - - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fep); - msleep(100); - } - - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || - fep->u.ofdm.constellation == QAM_AUTO || - fep->u.ofdm.code_rate_HP == FEC_AUTO) { - int i = 1000, found; - - dib3000mc_autosearch_start(fe, fep); - do { - msleep(1); - found = dib3000mc_autosearch_is_irq(fe); - } while (found == 0 && i--); - - dprintk("autosearch returns: %d\n",found); - if (found == 0 || found == 1) - return 0; // no channel found - - dib3000mc_get_frontend(fe, fep); - } - - ret = dib3000mc_tune(fe, fep); - - /* make this a config parameter */ - dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return ret; -} - -static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - u16 lock = dib3000mc_read_word(state, 509); - - *stat = 0; - - if (lock & 0x8000) - *stat |= FE_HAS_SIGNAL; - if (lock & 0x3000) - *stat |= FE_HAS_CARRIER; - if (lock & 0x0100) - *stat |= FE_HAS_VITERBI; - if (lock & 0x0010) - *stat |= FE_HAS_SYNC; - if (lock & 0x0008) - *stat |= FE_HAS_LOCK; - - return 0; -} - -static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501); - return 0; -} - -static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - *unc = dib3000mc_read_word(state, 508); - return 0; -} - -static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - u16 val = dib3000mc_read_word(state, 392); - *strength = 65535 - val; - return 0; -} - -static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) -{ - *snr = 0x0000; - return 0; -} - -static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static void dib3000mc_release(struct dvb_frontend *fe) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - dibx000_exit_i2c_master(&state->i2c_master); - kfree(state); -} - -int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0); - return 0; -} -EXPORT_SYMBOL(dib3000mc_pid_control); - -int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4); - tmp |= (onoff << 4); - return dib3000mc_write_word(state, 206, tmp); -} -EXPORT_SYMBOL(dib3000mc_pid_parse); - -void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg) -{ - struct dib3000mc_state *state = fe->demodulator_priv; - state->cfg = cfg; -} -EXPORT_SYMBOL(dib3000mc_set_config); - -int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]) -{ - struct dib3000mc_state st = { .i2c_adap = i2c }; - int k; - u8 new_addr; - - static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26}; - - for (k = no_of_demods-1; k >= 0; k--) { - st.cfg = &cfg[k]; - - /* designated i2c address */ - new_addr = DIB3000MC_I2C_ADDRESS[k]; - st.i2c_addr = new_addr; - if (dib3000mc_identify(&st) != 0) { - st.i2c_addr = default_addr; - if (dib3000mc_identify(&st) != 0) { - dprintk("-E- DiB3000P/MC #%d: not identified\n", k); - return -ENODEV; - } - } - - dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK); - - // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0) - dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1); - st.i2c_addr = new_addr; - } - - for (k = 0; k < no_of_demods; k++) { - st.cfg = &cfg[k]; - st.i2c_addr = DIB3000MC_I2C_ADDRESS[k]; - - dib3000mc_write_word(&st, 1024, st.i2c_addr << 3); - - /* turn off data output */ - dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z); - } - return 0; -} -EXPORT_SYMBOL(dib3000mc_i2c_enumeration); - -static struct dvb_frontend_ops dib3000mc_ops; - -struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg) -{ - struct dvb_frontend *demod; - struct dib3000mc_state *st; - st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL); - if (st == NULL) - return NULL; - - st->cfg = cfg; - st->i2c_adap = i2c_adap; - st->i2c_addr = i2c_addr; - - demod = &st->demod; - demod->demodulator_priv = st; - memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); - - if (dib3000mc_identify(st) != 0) - goto error; - - dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr); - - dib3000mc_write_word(st, 1037, 0x3130); - - return demod; - -error: - kfree(st); - return NULL; -} -EXPORT_SYMBOL(dib3000mc_attach); - -static struct dvb_frontend_ops dib3000mc_ops = { - .info = { - .name = "DiBcom 3000MC/P", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - 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_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = dib3000mc_release, - - .init = dib3000mc_init, - .sleep = dib3000mc_sleep, - - .set_frontend = dib3000mc_set_frontend, - .get_tune_settings = dib3000mc_fe_get_tune_settings, - .get_frontend = dib3000mc_get_frontend, - - .read_status = dib3000mc_read_status, - .read_ber = dib3000mc_read_ber, - .read_signal_strength = dib3000mc_read_signal_strength, - .read_snr = dib3000mc_read_snr, - .read_ucblocks = dib3000mc_read_unc_blocks, -}; - -MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator"); -MODULE_LICENSE("GPL"); +/* + * Driver for DiBcom DiB3000MC/P-demodulator. + * + * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * This code is partially based on the previous dib3000mc.c . + * + * 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 +#include +//#include +//#include +//#include +//#include +#include + +#include "dvb_frontend.h" + +#include "dib3000mc.h" +#include "initfrontend.h" + + + +static int debug,lg8934lock=0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0) + +#define Sleep msleep + +#if 0 // 20080521, chihming, move tp head file +struct dib3000mc_state { + struct dvb_frontend demod; + struct dib3000mc_config *cfg; + + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + + struct dibx000_i2c_master i2c_master; + + u32 timf; + + fe_bandwidth_t current_bandwidth; + + u16 dev_id; + + int streaming_ctrl; // 20080521, chihming + + struct task_struct *kthread; +}; +#endif + + + +/* define the register address and data of Tuner that need to be initialized when power on */ +m_BYTE AddrDataMemADMTV102_UHF[100]= +{ +//Addr Data + 0x10,0x6A, // LNA current, 0x4C will degrade 1 dB performance but get better power consumption. + 0x11,0xD8, // Mixer current + 0x12,0xC0, // Mixer gain + 0x15,0x3D, // TOP and ADJ to optimize SNR and ACI + 0x17,0x97, // TOP and ADJ to optimize SNR and ACI //*9A->97,Changed TOP and ADJ to optimize SNR and ACI + 0x18,0x03, // Changed power detector saturation voltage point and warning voltage point //* new insert + 0x1F,0x17, // VCOSEL,PLLF RFPGA amp current + 0x20,0xFF, // RFPGA amp current + 0x21,0xA4, // RFPGA amp current + 0x22,0xA4, // RFPGA amp current + 0x23,0xDF, // Mixer Bias control + 0x26,0xFA, // PLL BUFFER CURRENT + 0x27,0x00, // CONVCOL/H for VCO current control + 0x28,0xFF, // CONVCOBUFL/H for VCO buffer amplifier current control + 0x29,0xFF, // CONDIV1/2 for first and second divider current control + 0x2A,0xFF, // CONDIV3/4 for third and last divider current control + 0x2B,0xE7, // CONDIV5 for third and last divider current control + 0X2C,0xFF, // CONBUF0/1 for L-Band Buffer amp and first Buffer amp current control + 0x2E,0xFB, // CONBUF4 for forth Buffer amp current control + 0x30,0x80, // LFSW(Internal Loop Filter) to improve phase noise //* F8->80 + 0x32,0xc2, // LOOP filter boundary + 0x33,0x80, // DC offset control + 0x34,0xEC, // DC offset control + 0x39,0x96, // AGCHM AGC compensation value when LNA changes + 0x3A,0xA0, // AGCHM AGC compensation value when LNA changes + 0x3B,0x05, // AGCHM AGC compensation value when LNA changes + 0x3C,0xD0, // AGCHM AGC compensation value when LNA changes + 0x44,0xDF, // BBPGA needs to stay on for current silicon revision + 0x48,0x23, // current for output buffer amp //*23->21 + 0x49,0x08, // gain mode for output buffer amp + 0x4A,0xA0, // trip point for BBVGA + 0x4B,0x9D, // trip point for RFPGA + 0x4C,0x9D, // ADJRSSI warning point + 0x4D,0xC3, // PLL current for stability PLL lock + 0xff,0xff +}; + +m_BYTE AddrDataMemADMTV102_VHF[100]= +{ +//Addr Data + 0x10,0x08, // LNA current + 0x11,0xc2, // Mixer current + 0x12,0xC0, // Mixer gain + 0x17,0x98, // TOP and ADJ to optimize SNR and ACI //* 9A->98 + 0x1F,0x17, // VCOSEL,PLLF RFPGA amp current + 0x20,0x9b, // RFPGA amp current + 0x21,0xA4, // RFPGA amp current + 0x22,0xA4, // RFPGA amp current + 0x23,0x9F, // Mixer Bias control + 0x26,0xF9, // PLL BUFFER CURRENT + 0x27,0x11, // CONVCOL/H for VCO current control + 0x28,0x92, // CONVCOBUFL/H for VCO buffer amplifier current control + 0x29,0xBC, // CONDIV1/2 for first and second divider current control + 0x2B,0xE7, // CONDIV5 for third and last divider current control + 0x2D,0x9C, + 0x2E,0xCE, // CONBUF4 for forth Buffer amp current control + 0x2F,0x1F, + 0x30,0x80, // LFSW(Internal Loop Filter) to improve phase noise + 0x32,0xc2, // LOOP filter boundary + 0x33,0x80, // DC offset control + 0x34,0xEC, // DC offset control + 0x48,0x29, // current for output buffer amp + 0x49,0x08, // gain mode for output buffer amp + 0x4A,0xA0, // trip point for BBVGA + 0x4B,0x9D, // trip point for RFPGA + 0x4C,0x9D, // ADJRSSI warning point + 0x4D,0xC3, // PLL current for stability PLL lock + 0xff,0xff +}; + +m_BYTE PLLRegSetTable [10][3]= +{ // 0x24,0x31,0x38 + {0x0F,0x04,0x50}, //13MHz //0x24: 0xnB-> 0xnF + {0x1F,0x04,0x50}, //16.384MHz + {0x2F,0x04,0x50}, //19.2MHz + {0x3F,0x04,0x50}, //20.48MHz + {0x4F,0x15,0x51}, //24.576MHz + {0x5F,0x15,0x51}, //26MHz + {0x5A,0x04,0x51}, //30.4MHz //* special set for 30.4MHz case + {0x6F,0x15,0x51}, //36MHz + {0x7F,0x15,0x51}, //38.4MHz + {0x3F,0x04,0x50}, //20MHz +}; + +struct dib3000mc_state *m_U3300DmbthState=NULL; +m_BYTE g_icp,g_convco,g_curTempState,g_CTUNE_CLKOFS; +int g_VHFSet=UHFSupport; +int g_TunerPLLType=REFCLK16384; +ChannelInfo FindChannel[50]; +MPEG_PROGINFO myMpegInfo[MaxProgNum]; +int FindProgNum; // indicate how many program is found in one certain channel + + +void myAdiInit(struct dib3000mc_state *state) +{ + m_U3300DmbthState = state; +} + +//***************************************************************************** +// Function: Configure Tuner chip registers +// Input: target -- Device I2C address +// AddrData -- Register address and Config data array +// Output: None +//***************************************************************************** +void ConfigTuner(m_BYTE target, m_BYTE *AddrData) +{ + int i=0; + m_BYTE addr, data; + + while (AddrData[i]!=0xFF) + { + addr = AddrData[i++]; + data = AddrData[i++]; + swrite(target, addr, data); + } +} + +//***************************************************************************** +// Function: Set Tuner LPF configuration +// Input: target -- Tuner I2C device Address +// refClkType -- Tuner PLL Type +// lpfBW -- Band width , in MHz unit +// Return: None +//***************************************************************************** +void SetLPF(m_BYTE target,m_WORD refClkType,m_BYTE lpfBW) +{ + m_BYTE tuneval; + USB_I2C_READ ReadResult; + + swrite(target,0x15, (m_BYTE)( 0x38| ((lpfBW-3)& 0x07) )); + swrite(target, 0x25 , (_EXTUNEOFF << 2) | (_TUNEEN<<1) ); + Sleep(10); //change from 1 to 10 + + tuneval=0x10; //default value + ReadResult=sread(target,0x0F); + if(ReadResult.ACK_status==1) tuneval = ReadResult.read_data; + + swrite(target, 0x25 , (_EXTUNEON << 2) | (_TUNEEN << 1) ); //change Tuning mode : auto-tune => manual tune(hold mode). + + if (refClkType==REFCLK30400) + swrite(target, 0x25 , (m_BYTE)(((tuneval+g_CTUNE_CLKOFS)<<3) | (_EXTUNEON << 2) | (_TUNEEN << 1)) ); //Write CTUNE val. in order to store tuned value. + else swrite(target, 0x25 , (m_BYTE)((tuneval<<3) | (_EXTUNEON << 2) | (_TUNEEN << 1)) ); //Write CTUNE val. in order to store tuned value. + + return; +} + +//****************************************************************************** +// Function: Tuner PLL Register Setting +// Input: target -- Tuner I2C device Address +// RegDat -- Reg set value table +// Return: success flag +//****************************************************************************** +int TunerPLLRegSet(m_BYTE target, m_BYTE* RegDat,int TunerPLLType) +{ + int i=0; + m_BYTE addr, data; + m_BYTE splitid; + USB_I2C_READ ReadData; + + if(REFCLK30400==TunerPLLType) + { + addr=0x24; + ReadData=sread (target, 0x00); + if(ReadData.ACK_status==1) splitid = ReadData.read_data; + else return(-1); + + if (0x0E==splitid) data=REFCLK30400_CLKSEL_REG_SPLITID0E; // 0x5A + else if(0x0F==splitid) data=REFCLK30400_CLKSEL_REG_SPLITID0F; // 0x6A, for mass product + else data=RegDat[i]; + + swrite (target, addr, data); + i++; + } + else { + addr=0x24; + data=RegDat[i++]; + swrite (target, addr, data); + } + + addr=0x31; + data=RegDat[i++]; + swrite (target, addr, data); + + addr=0x38; + data=RegDat[i++]; + swrite (target, addr, data); + + return 1; +} +//***************************************************************************** +// Function: Distinguish Tuner Chip type by read SplidID +// Input: target -- Device I2C address +// +// Return: Tuner Type, MTV102 or ADMTV102 +//***************************************************************************** +int GetTunerType(m_BYTE target) +{ + m_BYTE splitid,RetTunerType; + USB_I2C_READ ReadData; + ReadData=sread (target, 0x00); + if(ReadData.ACK_status==1) splitid = ReadData.read_data; + else return(-1); + + g_CTUNE_CLKOFS=CTUNE_CLKOFS_SPLIT0E; + switch(splitid) + { + case 0x0E: { + g_CTUNE_CLKOFS=CTUNE_CLKOFS_SPLIT0E; + RetTunerType=Tuner_ADMTV102; + break; + } + case 0x0F: { // for mass product version + g_CTUNE_CLKOFS=CTUNE_CLKOFS_SPLIT0F; + RetTunerType=Tuner_ADMTV102; + break; + } + case 0x08: + case 0x0A: + { RetTunerType=Tuner_MTV102; + break; + } + default: RetTunerType=Tuner_NewMTV102; + break; + } + + return(RetTunerType); +} + +//***************************************************************************** +// Function: Main Function for Tuner Initialization +// only support ADMTV102 type, do not support MTV102 any more +// Input: None +// Return: None +//***************************************************************************** +void TunerInit(m_BYTE target, int TunerPLLType) +{ + GetTunerType(target); + g_icp=0; + g_convco=0; + g_curTempState=HIGH_TEMP; + if(TunerPLLType<0 || TunerPLLType>9 ) TunerPLLType=1; + if(g_VHFSet== VHFSupport) ConfigTuner (target, &AddrDataMemADMTV102_VHF[0]); + else ConfigTuner (target, &AddrDataMemADMTV102_UHF[0]); + + TunerPLLRegSet(target,&PLLRegSetTable[TunerPLLType][0],TunerPLLType); + SetLPF(target,TunerPLLType,8); + + return; +} + +//***************************************************************************** +// Function: frequency setting for ADMTV102 +// Input: +// target : I2C address of tuner +// frequency : Tuner center frequency in MHz +// lpfBW : Channel Bandwidth in MHz (default: 8- 8MHZ) +// refClkType: Tuner PLL reference clock type +// frequency setting formula +// LOfrequency=(Clockfrequency/PLLR*(PLLN+PLLF/2^20))/PLLS; +// Return: None +//***************************************************************************** +void SetTunerFreq(m_BYTE target, m_WORD frequency, m_WORD lpfBW, int refClkType) +{ + m_WORD MTV10x_REFCLK; + m_WORD PLLFREQ,Freq; + m_WORD DIVSEL=0,VCOSEL=0; + m_BYTE PC4=0,PC8_16=0,DATA47,_temper; + m_WORD Seg_num; + m_BYTE PLLR; + m_WORD lofreq; + m_DWORD PLLN, PLLF,tmp; + m_WORD MultiFactor,sub_exp,div_1,div_2; + USB_I2C_READ ReadData; + + // judge if the VFHset has conflict with frequency value or not + if( frequency >400 && VHFSupport==g_VHFSet) // VHF is 174MHz ~ 245MHz + { + g_VHFSet=UHFSupport; + TunerInit(lowTunerI2CAdr, refClkType ); + } + else if(frequency <400 && UHFSupport==g_VHFSet) + { + g_VHFSet=VHFSupport; + TunerInit(lowTunerI2CAdr, refClkType ); + } + + PLLR=1; + lofreq = frequency*1000; + DIVSEL = LO2PLL_Freq(lofreq); + Seg_num = (0x01 << DIVSEL); + + if(Seg_num >=1 && Seg_num <=16) + { PLLFREQ = lofreq* (16/Seg_num); + Freq=frequency* (16/Seg_num); + } + else + { PLLFREQ = lofreq*2; + Freq=frequency*2; + } + + switch(refClkType) + { + case REFCLK13000: { + MTV10x_REFCLK = 130; // 13*MultiFactor + MultiFactor=10; + sub_exp=1; + div_1=5; + div_2=13; // 130=13*5*(2^1) + break; } + case REFCLK16384: { + MTV10x_REFCLK = 16384; + MultiFactor=1000; + sub_exp=14; + div_1=1; + div_2=1; // 16384== 2^14 + break; } + case REFCLK19200: { + MTV10x_REFCLK = 192; + MultiFactor=10; + sub_exp=6; + div_1=1; + div_2=3; // 192 = 2^6 *3 + break;} + case REFCLK20480: { + MTV10x_REFCLK = 2048; + MultiFactor=100; + sub_exp=11; + div_1=1; + div_2=1; // 2048 = 2^11 + break;} + case REFCLK24576: { + MTV10x_REFCLK = 24576; + MultiFactor=1000; + sub_exp=13; + div_1=1; + div_2=3; // 24576 = 2^13*3 + break; } + case REFCLK26000: { + MTV10x_REFCLK = 260; + MultiFactor=10; + sub_exp=2; + div_1=5; + div_2=13; // 260=13*5*(2^2) + break;} + case REFCLK30400: { + MTV10x_REFCLK = 304; + MultiFactor=10; + PLLR = 2 ; + SetLPF(target,REFCLK30400,(unsigned char)lpfBW); + swrite(target,0x19, PLLR); //Ref. Clock Divider PLL0 register , bit[7:4] is reserved, bit[3:0] is PLLR + sub_exp=4; + div_1=1; + div_2=19; // 304 = 16*19 + break; + } + case REFCLK36000: { + MTV10x_REFCLK = 360; + MultiFactor=10; + sub_exp=3; + div_1=5; + div_2=9; // 360=2^3*9*5 + break;} + case REFCLK38400:{ + MTV10x_REFCLK = 384; + MultiFactor=10; + sub_exp=7; + div_1=1; + div_2=3; // 384 = 2^7 *3 + break;} + case REFCLK20000:{ + MTV10x_REFCLK = 200; + MultiFactor=10; + sub_exp=3; + div_1=5; + div_2=5; // 200=8*5*5 + break;} + default: { + MTV10x_REFCLK = 16384; + MultiFactor=1000; + sub_exp=14; + div_1=1; + div_2=1; // 16384== 2^14 + break;} + } + + PLLN = (Freq*MultiFactor* PLLR/MTV10x_REFCLK ); //new formula, liu dong, 2007/12/11 + tmp = ((PLLR*Freq*MultiFactor/div_1) << (20-sub_exp) )/div_2; + PLLF = tmp - (PLLN<<20); + + DATA47 = 0x10; //default Value + ReadData= sread(target,0x2f); + if(ReadData.ACK_status==1) DATA47 = (m_BYTE)(ReadData.read_data & 0x1f); + + if (PLLN<=66) + { + //4-prescaler + PC4 = 1; + PC8_16 = 0; + DATA47 = (m_BYTE)(DATA47 | (PC4<<6) | (PC8_16<<5)); + } + else + { + //8-prescaler + PC4 = 0; + PC8_16 = 0; + DATA47 = (m_BYTE) (DATA47 | (PC4<<6) | (PC8_16<<5)); + } + + // do a reset operation + swrite(target, 0x27, 0x00 ); //added : v1.6.3 at PM 20:39 2007-07-26 + //PLL Reset Enable + swrite(target, 0x2f, DATA47 ); //Reset Seq. 0 => 1 : //updated : v1.6.3 at PM 20:39 2007-07-26 + swrite(target, 0x2f, (m_BYTE) (DATA47 | 0x80)); + + if ((PLLFREQ*2)<2592000) // 648*1000*2*2 according to data sheet + VCOSEL = 0; + else VCOSEL = 1; + + // read 0x09 register bit [5:0] + _temper=0x0C; + ReadData= sread(target, 0x09) ; //To get Temperature sensor value + if(ReadData.ACK_status==1) _temper= (m_BYTE)(ReadData.read_data &0x3f ); // get low 6 bits + + dpPhaseTuning(lofreq,_temper); //these value may changes: g_icp=0, g_convco=0, g_curTempState=HIGH_TEMP; + + if (lofreq>400000) //if iRF=UHF + { + swrite(target,0x1a, (m_BYTE)((g_icp<<2)| ((PLLN&0x300)>>8))); // change 1C to 7C. 2007/07/09 + } + else + { + swrite(target,0x1a, (m_BYTE)( 0xFC | ( ( PLLN&0x300 ) >> 8 )) ); + } + + //PLL Setting + swrite(target,0x1b, (m_BYTE)(PLLN & 0xFF)); + swrite(target,0x1c, (m_BYTE)( (DIVSEL<<4) | (VCOSEL<<7) | ((PLLF&0xF0000)>>16) ) ); + swrite(target,0x1d, (m_BYTE)( (PLLF&0x0FF00)>>8 ) ); + swrite(target,0x1e, (m_BYTE)( PLLF&0xFF )); + swrite(target,0x15, (m_BYTE)( 0x38| ((lpfBW-3)& 0x07) )); + + //PLL Reset + swrite(target,0x2f, DATA47); //Reset Seq. 0 => 1 => 0 : //updated : v1.5 at PM 20:39 2007-06-8 + swrite(target,0x2f, (m_BYTE)( DATA47 | 0x80 )); + swrite(target,0x2f, DATA47); + + swrite(target, 0x27, g_convco ); + if (lofreq>400000) swrite(target, 0x29, 0xBF ); + return; +} +//***************************************************************************** +// Function: calculate DIVSEL according to lofreq +// Input: lofreq -- Frequency point value in kHz unit +// Return: m_DIVSEL -- DIVSEL in register 0x1C +//***************************************************************************** +int LO2PLL_Freq(m_DWORD lofreq) +{ + m_WORD fdefLoBoundFreq=940000; + + int Seg_num, m_DIVSEL=0; + + Seg_num=(int)(lofreq/(fdefLoBoundFreq/16)); + + while(Seg_num>0x01) + { + Seg_num=(Seg_num>>1); + m_DIVSEL++; + } + return(m_DIVSEL) ; +} + +//****************************************************************************** +// Function: Change CONVCO value according to Temperature Sensor(0x27[0:4]) +// Input: lofreq -- frequency in kHz unit +// temper -- Tuner 0x09 register content +// Return: None +//****************************************************************************** +void dpPhaseTuning(m_DWORD lofreq, m_BYTE temper) +{ + if (fDegVcoApply) + { + if(g_VHFSet== VHFSupport) { + if (temper<=vlowDegBoundary) //low boundary + { + g_convco=rglowDegCONVCO_VHF; + g_curTempState=LOW_TEMP; + } + else + if (temper>=vhighDegBoundary) //high boundary + { + g_convco=rgHighDegCONVCO; + g_curTempState=HIGH_TEMP; + } + } + else { + if (temper<=vlowDegBoundary) //low boundary + { + g_convco=rglowDegCONDIV; + g_icp=0x3F; + g_curTempState=LOW_TEMP; + } + else + if (temper>=vhighDegBoundary) //high boundary + { + g_convco=rgHighDegCONDIV; + if (( lofreq > 610000 ) && ( lofreq < 648000 )) //610MHz ~ 648MHz + g_icp=0x1F; + else g_icp=0x3F; + g_curTempState=HIGH_TEMP; + } + else + { if (g_curTempState) + { + g_convco=rglowDegCONDIV; + g_icp=0x3F; + } + else + { g_convco=rgHighDegCONDIV; + if (( lofreq > 610000 ) && ( lofreq < 648000 )) //610MHz ~ 648MHz + g_icp=0x1F; + else g_icp=0x3F; + } + } + } + } + return; +} +//****************************************************************************** +// Function: Do tuner temperature compensate, it can be called by processor +// for every 5~10 seconds. This may improve the tuner performance. +// +// Input: lofreq -- frequency in kHz unit +// Return: None +//****************************************************************************** +void TunerTemperatureComp(long lofreq) +{ + m_BYTE Ori_Reg_0x1A,Reg_0x1A,_temper; + USB_I2C_READ ReadData; + + Ori_Reg_0x1A=0xFC; + _temper=0x0C; + ReadData= sread(lowTunerI2CAdr, 0x09) ; //To get Temperature sensor value + if(ReadData.ACK_status==1) _temper= (m_BYTE)(ReadData.read_data &0x3f ); // get low 6 bits + + dpPhaseTuning(lofreq, _temper); + + ReadData= sread(lowTunerI2CAdr, 0x1A) ; //To get Temperature sensor value + if(ReadData.ACK_status==1) Ori_Reg_0x1A=ReadData.read_data; + + // reserve bit 7, bit1 and bit 0 + Reg_0x1A= (m_BYTE)((g_icp <<2) | (Ori_Reg_0x1A & 0x83)); + // write g_icp into 0x1A register bit[6:2] + swrite(lowTunerI2CAdr, 0x1A, Reg_0x1A); + swrite(lowTunerI2CAdr, 0x27, g_convco); + + return; +} + +//****************************************************************************** +// Function: Check if Tuner I2C access is OK or not. read-write 0x1B register +// Input: target -- Tuner I2C device Address +// Return: 0x03 -- all is ok +// bit1: read operation check result, 0 means error, 1 means ok. +// bit0: write operation check result, 0 means error, 1 means ok. +//****************************************************************************** +int CheckTunerI2C(m_BYTE target) +{ + m_BYTE Ori_dat,Wri_dat,Read_dat; + int ret_val=0; + USB_I2C_READ ReadData; + + Ori_dat=0x00; + Read_dat=0xff; + ReadData=sread (target, 0x1b); // save original data + if(ReadData.ACK_status==1) + { Ori_dat=ReadData.read_data; + ret_val=0x02; // read is ok + } + + Wri_dat=(m_BYTE)((~Ori_dat) & 0xff); // write XOR value + swrite(target, 0x1b , Wri_dat); + + ReadData=sread (target, 0x1b); // read back + if(ReadData.ACK_status==1) Read_dat=ReadData.read_data; + + if(Read_dat==Wri_dat) + ret_val=(ret_val | 0x01); // write is ok + + swrite(target, 0x1b , Ori_dat); + + return(ret_val); +} + +// **************************************************************************** +// Function: calculate signal power using Tuner related registers +// Input: None +// Return: signal power in dBm unit +// Note: The precise is about 10dB +// **************************************************************************** +#if 0 +int TunerRSSICalc(int freq) +{ + USB_I2C_READ myi2cRead; + int PowerDBValue=0; // in dBm unit + unsigned char RF_AGC_LowByte,RF_AGC_HighByte,LNA_Gain,GVBB; + int RF_AGC; + int CaseNumber; + int Coef[5]; + //double CompTab[2]={ 4.97,-5.30}; + int CompTab[2]={ 49700,-53000}; + int FreqTab[2]={474,858}; + int BBAGC,Freq_Comp; + unsigned char Val_0x3D,Val_0x3e,Val_0x3f; + long Demod_BBAGC; + + //Freq_Comp= -( (CompTab[1]-CompTab[0]) / (FreqTab[1]-FreqTab[0])*(freq-FreqTab[0])+ CompTab[0]); + Freq_Comp= -( ((CompTab[1]-CompTab[0]) / (FreqTab[1]-FreqTab[0]))*(freq-FreqTab[0])+ CompTab[0]); + + GVBB=0; + RF_AGC_LowByte=0; + RF_AGC_HighByte=0; + myi2cRead=sread (lowTunerI2CAdr, 0x05); + if (myi2cRead.ACK_status) + RF_AGC_LowByte = myi2cRead.read_data; + + myi2cRead=sread (lowTunerI2CAdr, 0x06); + if (myi2cRead.ACK_status) + RF_AGC_HighByte = myi2cRead.read_data; + + RF_AGC= (RF_AGC_HighByte & 0x01); + RF_AGC= (RF_AGC<<8) + RF_AGC_LowByte; + DbgLogTrace(("RF_AGC = %d RF_AGC_HighByte=%x RF_AGC_LowByte=%x\n",RF_AGC,RF_AGC_HighByte,RF_AGC_LowByte)); + myi2cRead=sread (lowTunerI2CAdr, 0x0d); + if (myi2cRead.ACK_status) + LNA_Gain = myi2cRead.read_data; + + LNA_Gain = ( (LNA_Gain & 0x60 )>> 5 ); + + myi2cRead=sread (lowTunerI2CAdr, 0x04); + if (myi2cRead.ACK_status) + GVBB = myi2cRead.read_data; + GVBB=(GVBB&0xf0)>>4; + + Val_0x3D=0; + Val_0x3e=0; + Val_0x3f=0; + + myi2cRead=sread (lowDemodI2CAdr, 0x3d); + if (myi2cRead.ACK_status) Val_0x3D = myi2cRead.read_data; + + myi2cRead=sread (lowDemodI2CAdr, 0x3e); + if (myi2cRead.ACK_status) Val_0x3e = myi2cRead.read_data; + + myi2cRead=sread (lowDemodI2CAdr, 0x3f); + if (myi2cRead.ACK_status) Val_0x3f = myi2cRead.read_data & 0x1f; + if (Val_0x3f & 0x10) Val_0x3f= (Val_0x3f & 0x0f);// two's complement to offset binary + else Val_0x3f= (Val_0x3f | 0x1f); // + + Demod_BBAGC= (Val_0x3f<<16) + (Val_0x3e<<8) + Val_0x3D; + //BBAGC= (double)(Demod_BBAGC)/2097151; // percent + BBAGC=((Demod_BBAGC)*100)/2097151; // percent + DbgLogTrace(("BBAGC = %d Demod_BBAGC=%ld hex=%x%x %x \n",BBAGC,Demod_BBAGC,Val_0x3f,Val_0x3e,Val_0x3D)); + CaseNumber=0; // default algorithm + if(LNA_Gain==0 && GVBB==4) CaseNumber=1; //[0,-31dBm], case 1 + if(LNA_Gain==3 && GVBB==4 && RF_AGC<383) CaseNumber=2; //[-34dBm,-59dBm], case 2 + if(LNA_Gain==3 && GVBB>4 && RF_AGC>=383) CaseNumber=3; //[-61Bm,-93dBm], case 3 + if( (LNA_Gain==0 && GVBB>4) || (LNA_Gain==3 && GVBB<4) ) CaseNumber=4; //[-2,-52dBm], case 4 + if(LNA_Gain==3 && GVBB>4 && RF_AGC<383) CaseNumber=5; //[-53,-78dBm], case 5 + if(GetTunerType(lowTunerI2CAdr)==Tuner_MTV102) CaseNumber=0; //use default formula + + DbgLogTrace(("CaseNumber = %d LNA_Gain=%x GVBB=%x\n",CaseNumber,LNA_Gain,GVBB)); + switch(CaseNumber) + { case 1: { + // Coef=[-0.1282 -7.5229 -0.1148 10 11.1148]; // used in 1.0.1 version + // Coef=[-0.25 -10 -2.87 -114 -3.1]; // used in 1.0.2 version + // Coef[0]=-0.25; Coef[1]=-10; Coef[2]=-2.87; Coef[3]=-114 ; Coef[4]=-3.1; + Coef[0]=-25; Coef[1]=-1000; Coef[2]=-287; Coef[3]=-114 ; Coef[4]=-310; + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+Coef[3]*(BBAGC-44)+Coef[4]+(Freq_Comp/100); + + break; + } + case 2: { + // Coef=[-0.1282 -7.5229 2.1443 10 8.8557]; // used in 1.0.1 version + //Coef[0]=-0.1282; Coef[1]=-7.5229; Coef[2]=2.1443; Coef[3]=10 ; Coef[4]=8.8557; + Coef[0]=-1282; Coef[1]=-75229; Coef[2]=21443; Coef[3]=1000 ; Coef[4]=88557; + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+Coef[3]*(BBAGC-44)+Coef[4]+Freq_Comp; + PowerDBValue = PowerDBValue/100; + break; + } + case 3: { // Coef[0]=-0.0548; Coef[1]=-8.0007; Coef[2]=-3; //old parameters used in 0.1.7 + // Coef=[-0.1537 -7.5229 -3.7059 10 11.1148]; // used in 1.0.1 version + // Coef=[-0.12 -9.52 -3.47 -114 1.2]; // used in 1.0.2 version + //Coef[0]=-0.12; Coef[1]=-9.52; Coef[2]=-3.47; Coef[3]=-114 ; Coef[4]=1.2; + Coef[0]=-1200; Coef[1]=-95200; Coef[2]=-34700; Coef[3]=-11400 ; Coef[4]=12000; + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+Coef[3]*(BBAGC-44)+Coef[4]+Freq_Comp; + PowerDBValue = PowerDBValue/100; + break; + } + case 4: { // Coef=[-0.1336 -7 -14.3975 10 11.1148]; // used in 1.0.1 version + // Coef=[-0.12 -10 -3.3 -114 0.7]; // used in 1.0.2 version + // Coef[0]=-0.12; Coef[1]=-10; Coef[2]=-3.3; Coef[3]=-114 ; Coef[4]=0.7; + Coef[0]=-12; Coef[1]=-1000; Coef[2]=-330; Coef[3]=-114 ; Coef[4]=70; + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+Coef[3]*(BBAGC-44)+Coef[4]+(Freq_Comp/100); + + break; } + case 5: { // Coef=[-0.1269 -7.3537 8.6511 10 11.1148]; // used in 1.0.1 version + // Coef=[-0.12 -9.52 -2.8 -114 1.2]; // used in 1.0.2 version + //Coef[0]=-0.12; Coef[1]=-9.52; Coef[2]=-2.8; Coef[3]=-114 ; Coef[4]=1.2; + Coef[0]=-12; Coef[1]=-952; Coef[2]=-280; Coef[3]=-114 ; Coef[4]=120; + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+Coef[3]*(BBAGC-44)+Coef[4]+(Freq_Comp/100); + + break; + } + default: { // default formular + //Coef[0]=-0.125; Coef[1]=-8.3; Coef[2]=8; + Coef[0]=-125; Coef[1]=-8300; Coef[2]=8000; + PowerDBValue=(RF_AGC*Coef[0])+(LNA_Gain*Coef[1]) +Coef[2]; + PowerDBValue=PowerDBValue-3000*(GVBB-5)-100*(BBAGC-50); + PowerDBValue = PowerDBValue/10; + break; + } + } + DbgLogTrace(("Read PowerDBValue %d\n", PowerDBValue)); + return(PowerDBValue); +} +#else +int TunerRSSICalc(int freq) +{ + USB_I2C_READ myi2cRead; + int PowerDBValue=0; // in dBm unit + unsigned char RF_AGC_LowByte,RF_AGC_HighByte,LNA_Gain,GVBB; + int RF_AGC; + int CaseNumber; + int Coef[5]; + int CompTab[2]={ 497,-530}; + int FreqTab[2]={474,858}; + int Freq_Comp,BBAGC_Part; + unsigned char Val_0x3D,Val_0x3e,Val_0x3f; + + + Freq_Comp= -( (CompTab[1]-CompTab[0]) *(freq-FreqTab[0])/ (FreqTab[1]-FreqTab[0]) + CompTab[0] ); //0.01dB + + GVBB=0; + myi2cRead=sread (lowTunerI2CAdr, 0x05); + if (myi2cRead.ACK_status) + RF_AGC_LowByte = myi2cRead.read_data; + + myi2cRead=sread (lowTunerI2CAdr, 0x06); + if (myi2cRead.ACK_status) + RF_AGC_HighByte = myi2cRead.read_data; + + RF_AGC= (RF_AGC_HighByte & 0x01); + RF_AGC= (RF_AGC<<8) + RF_AGC_LowByte; + + myi2cRead=sread (lowTunerI2CAdr, 0x0d); + if (myi2cRead.ACK_status) + LNA_Gain = myi2cRead.read_data; + + LNA_Gain = ( (LNA_Gain & 0x60 )>> 5 ); + + myi2cRead=sread (lowTunerI2CAdr, 0x04); + if (myi2cRead.ACK_status) + GVBB = myi2cRead.read_data; + GVBB=(GVBB&0xf0)>>4; + + Val_0x3D=0; + Val_0x3e=0; + Val_0x3f=0; + + myi2cRead=sread (lowDemodI2CAdr, 0x3d); + if (myi2cRead.ACK_status) Val_0x3D = myi2cRead.read_data; + + myi2cRead=sread (lowDemodI2CAdr, 0x3e); + if (myi2cRead.ACK_status) Val_0x3e = myi2cRead.read_data; + + myi2cRead=sread (lowDemodI2CAdr, 0x3f); + if (myi2cRead.ACK_status) Val_0x3f = myi2cRead.read_data & 0x1f; + if (Val_0x3f & 0x10) Val_0x3f= (Val_0x3f & 0x0f);// two's complement to offset binary + else Val_0x3f= (Val_0x3f|0x1f); // + + BBAGC_Part= Val_0x3f; + BBAGC_Part = ( BBAGC_Part <<8) + Val_0x3e; + + CaseNumber=0; // default algorithm + if(LNA_Gain==0 && GVBB==4) CaseNumber=1; //[0,-31dBm], case 1 + if(LNA_Gain==3 && GVBB==4 && RF_AGC<383) CaseNumber=2; //[-34dBm,-59dBm], case 2 + if(LNA_Gain==3 && GVBB>4 && RF_AGC>=383) CaseNumber=3; //[-61Bm,-93dBm], case 3 + if( (LNA_Gain==0 && GVBB>4) || (LNA_Gain==3 && GVBB<4) ) CaseNumber=4; //[-2,-52dBm], case 4 + if(LNA_Gain==3 && GVBB>4 && RF_AGC<383) CaseNumber=5; //[-53,-78dBm], case 5 + if(GetTunerType(lowTunerI2CAdr)==Tuner_MTV102) CaseNumber=0; //use default formula + + // if BBAGC > 0.97, case number is forced to 0, liu dong, 2008/04/22 + if(Val_0x3f >= 0x10) CaseNumber=0; + + switch(CaseNumber) + { case 1: { + Coef[0]=-25; Coef[1]=-1000; Coef[2]=-287; Coef[3]=-11400 ; Coef[4]=-310; + BBAGC_Part=((Coef[3]*BBAGC_Part)/8192) + 5016; // 5016 = Coef[3]*0.44 + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+BBAGC_Part+Coef[4]+Freq_Comp; + break; + } + case 2: { + Coef[0]=-13; Coef[1]=-752; Coef[2]=214; Coef[3]=1000 ; Coef[4]=886; + BBAGC_Part=((Coef[3]*BBAGC_Part)/8192)- 440; // 440 = Coef[3]*0.44 + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+BBAGC_Part+Coef[4]+Freq_Comp; + break; + } + case 3: { + Coef[0]=-12; Coef[1]=-952; Coef[2]=-347; Coef[3]=-11400 ; Coef[4]=120; + BBAGC_Part=((Coef[3]*BBAGC_Part)/8192) + 5016; // 502 = Coef[3]*0.44 + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+BBAGC_Part+Coef[4]+Freq_Comp; + break; + } + case 4: { + Coef[0]=-12; Coef[1]=-1000; Coef[2]=-330; Coef[3]=-11400 ; Coef[4]=70; + BBAGC_Part=((Coef[3]*BBAGC_Part)/8192) + 5016; // 5016 = Coef[3]*0.44 + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+BBAGC_Part+Coef[4]+Freq_Comp; + break; + } + case 5: { + Coef[0]=-12; Coef[1]=-952; Coef[2]=-280; Coef[3]=-11400 ; Coef[4]=120; + BBAGC_Part=((Coef[3]*BBAGC_Part)/8192) + 5016; // 502 = Coef[3]*0.44 + PowerDBValue=Coef[0]*RF_AGC+Coef[1]*LNA_Gain+Coef[2]*(GVBB-5)+BBAGC_Part+Coef[4]+Freq_Comp; + break; + } + default: { + Coef[0]=-12; Coef[1]=-830; Coef[2]=800; + PowerDBValue=RF_AGC*Coef[0]+LNA_Gain*Coef[1] +Coef[2]; + BBAGC_Part= -1000*BBAGC_Part/8192; + PowerDBValue=PowerDBValue-300*(GVBB-5)+BBAGC_Part + Freq_Comp; // for 8934 case + break; + } + } + + return(PowerDBValue); +} +#endif +//***************************************************************************** +// Functions: Initialization of LGS8934/LGS8GL5 at start-up +//***************************************************************************** + + m_BYTE AddrDataMemLGS8GL5 [40]= //8GL5 case , Internal ADC +{ +/* define the register address and data of LGS8gl5 that need to be initialized when power on */ + 0x05,0x04, + 0x07,0x1C, // BB_SEL=1 because the MTV10X tuner output is I/Q signal; IF_SEL=1, set the negative center frequency for IF + // 0x1C: internal ADC + 0x09,0x00, // Set the initial IF frequency of the automatic frequency control as 0Hz. + 0x0A,0x00, // + 0x0B,0x00, // + 0x0C,0x00, // + 0x2d,0x60, // set AGC_REF[15:8]; + 0x2e,0x61, // set AGC_REF[20:16] and AGC_GAIN[2:0]; + 0xC5,0x06, // FEC auto reset + 0xC1,0x00, + 0x02,0x00, // Perform the soft reset. + 0x02,0x01, // Disable soft reset. + 0xff,0xff +}; + + + m_BYTE AddrDataMemLGS8934 [40]= //8934 case , external ADC +{ +/* define the register address and data of LGS8934 that need to be initialized when power on */ + 0x05,0x04, + 0x07,0x9F, // BB_SEL=1 because the MTV10X tuner output is I/Q signal; IF_SEL=1, set the negative center frequency for IF + // 0x9F: External ADC + 0x09,0x00, // Set the initial IF frequency of the automatic frequency control as 0Hz. + 0x0A,0x00, // + 0x0B,0x00, // + 0x0C,0x00, // + 0x2d,0x00, // set AGC_REF[15:8]; + 0x2e,0x62, // set AGC_REF[20:16] and AGC_GAIN[2:0]; + 0xC5,0x06, // FEC auto reset + 0xC1,0x00, + 0x02,0x00, // Perform the soft reset. + 0x02,0x01, // Disable soft reset. + 0xff,0xff +}; + +//***************************************************************************** +// Function: Main Function for Demodulator Initialization +// Input: DemodOutType -- Demodulator output type, parallel or serials +// Return: None +//***************************************************************************** +void DemodInit(int DemodOutType) +{ + int DemodType; + + if(DemodOutType==DemodSerialOutType) DemodOutputSerialSet(); + else if (DemodOutType==DemodParallelOutType) DemodOutputParallelSet(); + + DemodType=GetDemodType(); + if(DemodType==Demod_8GL5) ConfigDemod(AddrDataMemLGS8GL5); + else if(DemodType==Demod_8934) ConfigDemod(AddrDataMemLGS8934); + + GIModeSet(GI_420); + DisableGIAutoDetect(); + DemodAutoDetectSet(); + DemodSoftReset(); + + return; +} +//***************************************************************************** +// Function: Configure Demod chip +// Input: AddrData -- Register address and Config data array +// Return: None +//***************************************************************************** +void ConfigDemod(m_BYTE *AddrData) +{ + int i=0; + m_BYTE addr, data,target; + + while (AddrData[i]!=0xFF) + { + addr = AddrData[i++]; + data = AddrData[i++]; + if (addr>DemodSec1MaxAdr) target = highDemodI2CAdr; // change the I2C device address + else target = lowDemodI2CAdr; + swrite(target, addr, data); + } + return; +} + +// ****************************************************************** +// function: Check if Demodulator I2C access is ok or not +// check 0x03 and 0xc2 register, read-write-read again. +// return: 2 bits +// Bit0: indicate the write operation successful or not. 0: fail, 1: ok +// Bit1: indicate the read operation successful or not. 0: fail, 1: ok +// +// ****************************************************************** +int CheckDemodI2C() +{ + USB_I2C_READ myi2cRead; + m_BYTE OriData,WriteData,ReadData; + int Ret_val=0; + int Low_read=0,High_read=0,Low_write=0,High_write=0; + + myi2cRead=sread (lowDemodI2CAdr, 0x03); + if( myi2cRead.ACK_status ==1) { + OriData = myi2cRead.read_data; + Low_read=1; + } + else { + Low_read=0; + return(Ret_val); + } + + WriteData= (m_BYTE)(( ~(OriData &0x01) ) & 0x01); + swrite (lowDemodI2CAdr, 0x03,WriteData); + myi2cRead=sread (lowDemodI2CAdr, 0x03); + if( myi2cRead.ACK_status ==1) { + ReadData = myi2cRead.read_data; + Low_read=1; + } + else { + Low_read=0; + return(Ret_val); + } + + if(ReadData==WriteData){ Low_write=1; + Low_read=1;} + else Low_write=0; + + // resume the 0x03 value. + swrite (lowDemodI2CAdr, 0x03,OriData); + + // check 0x36 section + myi2cRead=sread (highDemodI2CAdr, 0xc2); + if( myi2cRead.ACK_status ==1) { + OriData = myi2cRead.read_data; + High_read=1; + } + else { High_read=0; + return(Ret_val); + } + + WriteData= (m_BYTE)(( ~(OriData &0x07) ) & 0x07); + swrite (highDemodI2CAdr, 0xC2,WriteData); + myi2cRead=sread (highDemodI2CAdr, 0xC2); + if( myi2cRead.ACK_status ==1) { + ReadData = myi2cRead.read_data; + High_read=1; + } + else { High_read=0; + return(Ret_val); + } + + if(ReadData==WriteData){ + High_write=1; + High_read=1; + } + else High_write=0; + + + // resume the 0xc2 value. + swrite (highDemodI2CAdr, 0xC2,OriData); + + if (Low_read && High_read) Ret_val= (Ret_val | 0x02); //bit1=1 + else Ret_val= (Ret_val & 0x01); //bit1=0 + + if (Low_write && High_write) Ret_val= (Ret_val | 0x01); //bit0=1 + else Ret_val= (Ret_val & 0x02); //bit0=0 + + return(Ret_val); // 0x03 means all ok. +} +//***************************************************************************** +// Function: Set Demodulator works in Serials output mode +// Input: none +// Return: None +//***************************************************************************** +void DemodOutputSerialSet() +{ + m_BYTE MiscReadData; + USB_I2C_READ myi2cRead; + + MiscReadData=0x0f; //default value; + myi2cRead=sread(highDemodI2CAdr,0xC2); // read the 0xC2 register value + if(myi2cRead.ACK_status==1) MiscReadData=myi2cRead.read_data; + MiscReadData=(m_BYTE)(MiscReadData|0x05); + swrite(highDemodI2CAdr,0xC2,MiscReadData); //set SERIAL=1, MPEGCLK=1; + return ; +} +//***************************************************************************** +// Function: Set Demodulator works in Serials output mode +// Input: none +// Return: None +//***************************************************************************** +void DemodOutputParallelSet() +{ + m_BYTE MiscReadData; + USB_I2C_READ myi2cRead; + MiscReadData=0x0a; //default value; + myi2cRead=sread(highDemodI2CAdr,0xC2); // read the 0xC2 register value + if(myi2cRead.ACK_status==1) MiscReadData=myi2cRead.read_data; + MiscReadData=(m_BYTE)((MiscReadData & 0xfa) | 0x02); + swrite(highDemodI2CAdr,0xC2,MiscReadData); //set SERIAL=0, MPEGCLK=0; + return ; +} + +//***************************************************************************** +// Function: Get Demodulator Chip Type +// Input: None +// Return: DemodType -- Demodulator Type , 8GL5 or 8934 +//***************************************************************************** +int GetDemodType() +{ + m_BYTE Dat; + USB_I2C_READ myi2cRead; + int DemodType; + Dat=0xff; + myi2cRead=sread (lowDemodI2CAdr, 0x00); + if( myi2cRead.ACK_status ==1) Dat = myi2cRead.read_data; + printk("Demod ID=%x\n",Dat); + if(Demod_8GL5ID ==Dat) DemodType=Demod_8GL5; + else if(Demod_8934ID ==Dat) DemodType=Demod_8934; + else DemodType=Demod_8G44; + + return(DemodType); +} +//***************************************************************************** +// Function: Set Tuner I2C bus type as "From Demod type" +// Input: None +// Return: None +//***************************************************************************** +void SetTunerI2CInternal() +{ + m_BYTE I2CSignalData; + I2CSignalData=(0x80 | ((lowTunerI2CAdr)>>1)); + swrite(lowDemodI2CAdr, 0x01,I2CSignalData); + return; +} +//***************************************************************************** +// Function: Set Tuner I2C bus type as "Bypass Demod type" +// Input: None +// Return: None +//***************************************************************************** +void SetTunerI2CExternal() +{ + // write 0x01 with 0x00, set the Tuner I2C access path bypass Demod. + swrite(lowDemodI2CAdr, 0x01,0x00); + return; +} + +//***************************************************************************** +// Function: Disable GI Auto-detect mode +// Input: none +// Return: None +//***************************************************************************** +void DisableGIAutoDetect() +{ + swrite(lowDemodI2CAdr, 0x03,0x00); + return; +} +//***************************************************************************** +// Function: Get current Demod working mode parameters according to +// "Auto-detect" mode setting status (0x7E register setting) +// The working mode parameters include Time interleaver, Code rate, Constellation etc. +// Input: none +// Return: the TIM, QAM and Code rate parameters . return -1 means I2C read error. +// FEC_Par: Bit[7] = Control Frame; +// Bit[6:5] = Time Interleaver; +// Bit[4:2] = constellation; +// Bit[1:0] = code rate; +//***************************************************************************** +int GetFECPara() +{ + m_BYTE FEC_para; + USB_I2C_READ myi2cRead; + + if(CheckDetectMode()==1) // auto-detected mode , read 0xA2 register. + { + // read 0xA2 register + myi2cRead=sread (lowDemodI2CAdr, 0xA2); + if( myi2cRead.ACK_status ==1) + { FEC_para = myi2cRead.read_data; + return(FEC_para); + } + } + else if(CheckDetectMode()==0) //manual mode , read 0x7D register. + { + // read 0x7D register + myi2cRead=sread (lowDemodI2CAdr, 0x7D); + if( myi2cRead.ACK_status ==1) + { FEC_para = myi2cRead.read_data; + return(FEC_para); + } + } + + return(-1); +} + +//***************************************************************************** +// Function: Set the demodulator works in Auto-detect mode +// Input: none +// Return: None +//***************************************************************************** +void DemodAutoDetectSet() +{ + m_BYTE I2CSignalData; + USB_I2C_READ myi2cRead; + + I2CSignalData=0x06; //default value; + // read demodulator 0xC5 register, bitand with 0xE0, and write back. + myi2cRead=sread (highDemodI2CAdr, 0xC5); + if( myi2cRead.ACK_status ==1) + I2CSignalData = myi2cRead.read_data; + I2CSignalData=(m_BYTE)(I2CSignalData & 0x0e0); + swrite(highDemodI2CAdr, 0xC5,I2CSignalData); + + // write 0x7e with 0x01 + I2CSignalData=0x01; + swrite(lowDemodI2CAdr, 0x7e,I2CSignalData); + + // write 0xC1 with 0x03 + I2CSignalData=0x03; + swrite(highDemodI2CAdr, 0xC1,I2CSignalData); + + // read demodulator 0x7C register, Do bitand with 0x88, bitOr with 0x07, and write back. + I2CSignalData=0x03; //default value; + myi2cRead=sread (lowDemodI2CAdr, 0x7C); + if( myi2cRead.ACK_status ==1) + I2CSignalData = myi2cRead.read_data; + + I2CSignalData=(m_BYTE)( (I2CSignalData&0x88) | 0x07); + swrite(lowDemodI2CAdr, 0x7C,I2CSignalData); + + // read demodulator 0xC3 register, bitand with 0xE0, and write back. + I2CSignalData=0x01; //default value; + myi2cRead=sread (highDemodI2CAdr, 0xC3); + if( myi2cRead.ACK_status ==1) + I2CSignalData = myi2cRead.read_data; + I2CSignalData=(m_BYTE)( (I2CSignalData&0xEF) | 0x10); + swrite(highDemodI2CAdr, 0xC3,I2CSignalData); + + // add 0x37 register setting according to Joshua's suggestion + swrite(lowDemodI2CAdr, 0x37,0x01); // not suitable for GI=545 case + + DemodSoftReset(); + + return; +} + +//************************************************************************** +// Function: Set the demodulator works in manual set mode +// Input : +// FEC_Par: Bit[7] = Control Frame; +// Bit[6:5] = Time Interleaver; +// Bit[4:2] = constellation; +// Bit[1:0] = code rate; +// GI_mode: Bit[1:0] = Guard interval, 420 (0x00), 595 (0x01) or 945 (0x02); +// Return: None +//************************************************************************** +void DemodManualDetectSet(m_BYTE FEC_Par,int GI_mode) +{ + m_BYTE I2CSignalData; + USB_I2C_READ myi2cRead; + + if(GI_mode>=0) + { // write 0x04 with GI_mode + I2CSignalData=(m_BYTE)GI_mode; + swrite(lowDemodI2CAdr, 0x04,I2CSignalData); + + // write 0x03 with 0x00 + I2CSignalData=0x00; + swrite(lowDemodI2CAdr, 0x03,I2CSignalData); + } + + // write 0x7d with FEC_Par + I2CSignalData=FEC_Par; + swrite(lowDemodI2CAdr, 0x7d,I2CSignalData); + + // write 0xC0 with FEC_Par + I2CSignalData=FEC_Par; + swrite(highDemodI2CAdr, 0xC0,I2CSignalData); + + // write 0x7e with 0x00 + I2CSignalData=0x00; + swrite(lowDemodI2CAdr, 0x7e,I2CSignalData); + + // write 0xC1 with 0x00 + I2CSignalData=0x00; + swrite(highDemodI2CAdr, 0xC1,I2CSignalData); + + + // read demodulator 0xC5 register, bitand with 0xE0, and write back. + myi2cRead=sread (highDemodI2CAdr, 0xC5); + if( myi2cRead.ACK_status ==1) + I2CSignalData = myi2cRead.read_data; + I2CSignalData=(m_BYTE)( (I2CSignalData&0x0e0) | 0x06 ); + swrite(highDemodI2CAdr, 0xC5,I2CSignalData); + + // read and set 0x7c according to han liang's advice. + myi2cRead=sread (lowDemodI2CAdr, 0x7c); + if( myi2cRead.ACK_status ==1) + I2CSignalData = myi2cRead.read_data; + I2CSignalData=(m_BYTE)( (I2CSignalData&0x088) | 0x07); + swrite(lowDemodI2CAdr, 0x7c,I2CSignalData); + + DemodSoftReset(); + + return; +} + +//************************************************************************** +// function: check if the auto Detection procedure is finished. +// return: 0: fail; 1: success +//************************************************************************** +int AutoDetectDoneCheck() +{ + m_BYTE I2CSignalData; + USB_I2C_READ myi2cRead; + int Demod_AutoDone; + + //check if 0xA4 F_AUTO and Done_Auto bits is 01b or not + Demod_AutoDone=0; + myi2cRead=sread (lowDemodI2CAdr, 0xA4); + I2CSignalData=myi2cRead.read_data; + if (myi2cRead.ACK_status && (I2CSignalData&0x03) ==0x01) + Demod_AutoDone=1; + else Demod_AutoDone=0; + + return(Demod_AutoDone); +} +//***************************************************************************** +// Function: Set the demodulator works in Auto-detect mode +// Input: None +// Return: None +//***************************************************************************** +void DemodSoftReset() +{ + m_BYTE I2CSignalData; + + I2CSignalData=0x00; + swrite (lowDemodI2CAdr, 0x02, I2CSignalData); + msleep(10); + I2CSignalData=0x01; + swrite (lowDemodI2CAdr, 0x02, I2CSignalData); + return; +} + +//***************************************************************************** +// Function: Set Guard Interval Mode +// Input: GI_mode -- GI mode, GI_420(1/9), GI_595 or GI_945(1/4) +// Return: None +//***************************************************************************** +void GIModeSet(m_BYTE GI_mode) +{ + // write 0x04 with GI_mode + if(GI_mode==GI_420 || GI_mode==GI_945 || GI_mode==GI_595) + { + swrite (lowDemodI2CAdr, 0x04, GI_mode); + } + return; +} +//******************************************************************************** +// Function: check the detected mode by read 0x7E register +// Input: None +// Return: 0x00 is manual mode, 0x01 is the auto-detected mode, -1 means I2C read Error. +//******************************************************************************** +int CheckDetectMode() +{ + m_BYTE I2CSignalData; + USB_I2C_READ myi2cRead; + + // read 0x7E + myi2cRead=sread(lowDemodI2CAdr, 0x7E); + if( myi2cRead.ACK_status ==1) + { + I2CSignalData = myi2cRead.read_data; + return(I2CSignalData); + } + else return(-1); +} + +//************************************************************************** +// Function: return GI detection current value +// Input: None +// Return: Guard Interval +// +//************************************************************************** +int GetGISet() +{ + USB_I2C_READ myi2cRead; + int GI_detect_val,Auto_set; + + GI_detect_val=-1; + Auto_set=-1; + + myi2cRead=sread(lowDemodI2CAdr, 0x03); // 0x03 + if( myi2cRead.ACK_status ==1) + { + Auto_set = myi2cRead.read_data; + } + else return(GI_detect_val); + + if(Auto_set==0) { + myi2cRead=sread(lowDemodI2CAdr, 0x04); // 0x04 , manual set value + if( myi2cRead.ACK_status ==1) + { + GI_detect_val = myi2cRead.read_data; + } + else return(GI_detect_val); + } + else if(Auto_set==1){ + myi2cRead=sread(lowDemodI2CAdr, 0x44); // 0x044 + if( myi2cRead.ACK_status ==1) + { + GI_detect_val = myi2cRead.read_data; + } + else return(GI_detect_val); + } + + return(GI_detect_val); +} +//***************************************************************************** +// Function: Check the Demod lock status by checking Demod 0x4B register. +// Input: None +// Return: Lock_flag -- lock status, 1 means lock, 0 no lock. +//***************************************************************************** +int SignalLockCheck() +{ + USB_I2C_READ myi2cRead; + int TunerI2C_status, DemodI2C_status1, DemodI2C_status2; //record the I2C access status + int Tuner_pll_lock, Demod_CALOCK, Demod_AutoDone,lock_status; //record the bit status + int check_mode; + int Tuner0x06Lock,TunerADout; + + printk("%s\n", __FUNCTION__); // 20080515, chihming + + TunerI2C_status=DemodI2C_status1=DemodI2C_status2=0; + Tuner_pll_lock=Demod_CALOCK=Demod_AutoDone=0; + + check_mode=1; + + // check if the Tuner PLL is locked or not + myi2cRead=sread (lowTunerI2CAdr, 0x06); + TunerI2C_status=myi2cRead.ACK_status; + if (TunerI2C_status && (myi2cRead.read_data&0x02) ==0x02) + Tuner0x06Lock=1; + else Tuner0x06Lock=0; + + myi2cRead=sread (lowTunerI2CAdr, 0x04); + TunerI2C_status=myi2cRead.ACK_status; + TunerADout=0xff; + if (TunerI2C_status) TunerADout=(myi2cRead.read_data&0x0f); + + if ( ( ( TunerADout > TunerADOutMin ) && ( TunerADout < TunerADOutMax ) ) && Tuner0x06Lock ) //pll lock cross check + Tuner_pll_lock=1; + else Tuner_pll_lock=0; + + + // check if Demod is locked or not + myi2cRead=sread (lowDemodI2CAdr, 0x4b); + DemodI2C_status1=myi2cRead.ACK_status; // Access 0x4b register + if (DemodI2C_status1 && (myi2cRead.read_data&0xc0) ==0xc0) // means the signal is not locked + Demod_CALOCK=1; + else Demod_CALOCK=0; + + if(Demod_CALOCK==1) Tuner_pll_lock=1; + if(CheckDetectMode()==1) // FEC auto-detected is enable + { + Demod_AutoDone=AutoDetectDoneCheck(); + check_mode=2; + } + + //merge the three lock status together, [Auto_done,CA_Lock,PLL_Lock] + lock_status= Tuner_pll_lock+Demod_CALOCK*2+Demod_AutoDone*4; + //printk("check_mode=%x lock_status =%x\n",check_mode,lock_status); + if (lock_status==0x07 && check_mode==2) return (1); + else if((lock_status & 0x03)==0x03 && check_mode==1) return (1); + else return (0); +} + + +int TunerPllLockCheck() +{ + USB_I2C_READ myi2cRead; + int TunerI2C_status, DemodI2C_status1, DemodI2C_status2; //record the I2C access status + int Tuner_pll_lock, Demod_CALOCK, Demod_AutoDone,lock_status; //record the bit status + int check_mode; + int Tuner0x06Lock,TunerADout; + + TunerI2C_status=DemodI2C_status1=DemodI2C_status2=0; + Tuner_pll_lock=Demod_CALOCK=Demod_AutoDone=0; + + check_mode=1; + + // check if the Tuner PLL is locked or not + myi2cRead=sread (lowTunerI2CAdr, 0x06); + TunerI2C_status=myi2cRead.ACK_status; + if (TunerI2C_status && (myi2cRead.read_data&0x02) ==0x02) + Tuner0x06Lock=1; + else Tuner0x06Lock=0; + + myi2cRead=sread (lowTunerI2CAdr, 0x04); + TunerI2C_status=myi2cRead.ACK_status; + TunerADout=0xff; + if (TunerI2C_status) TunerADout=(myi2cRead.read_data&0x0f); + + if ( ( ( TunerADout > TunerADOutMin ) && ( TunerADout < TunerADOutMax ) ) && Tuner0x06Lock ) //pll lock cross check + Tuner_pll_lock=1; + else Tuner_pll_lock=0; + return Tuner_pll_lock; +} + +// **************************************************************************** +// Function: check if the demodulator auto-detect mode work normally +// Input: None +// Return: success or not flag +// **************************************************************************** +int DetectDemodMode() +{ + USB_I2C_READ myi2cRead; + int lock_flag=0; + int ret_status; + int GI_Val; + unsigned char tmp_demod_mode; + + lock_flag=SignalLockCheck(); + if (lock_flag) + { + tmp_demod_mode = 0xff; // modified by liu dong, enable [240, QPSK, 0.4] case ! + myi2cRead=sread (lowDemodI2CAdr, 0xA2); //auto-deteced result + if(myi2cRead.ACK_status ==1) tmp_demod_mode = myi2cRead.read_data; + + if(tmp_demod_mode != 0xff ){ + if(GetDemodType()==Demod_8934) // for LGS8934 case + { + // for LGS8934 case , it can not distinguish 00 and 240 + if((tmp_demod_mode & 0x60)!=0x60) + { + tmp_demod_mode=(m_BYTE) ( (tmp_demod_mode & 0x1f) | 0x40 ); + + DemodManualDetectSet(tmp_demod_mode,-1); + } + else DemodManualDetectSet(tmp_demod_mode,-1); + } + else if(GetDemodType()==Demod_8GL5) // LGS8GL5 case + DemodManualDetectSet(tmp_demod_mode,-1); //for 8GL5 do not set manually. + + } + + DemodSoftReset(); + ret_status=DetectOkOnLock; + } + else { + GI_Val=GetGISet(); + if(GI_Val==GI_420) GIModeSet(GI_945); + else if(GI_Val==GI_945) GIModeSet(GI_595); + else if(GI_Val==GI_595) GIModeSet(GI_420); + Sleep(400); + DemodSoftReset(); + ret_status=OnProcessNoLock; + } + return(ret_status); +} + +//***************************************************************************************** +// Function: Init the Front-end board. +// Default working mode is Demod: parallel output +// DMB-TH signal bandwidth is 8MHz +// Input: +// Freq: channel frequency value, in MHz unit +// PLLType: Tuner Crystal type +// InitMode: Init mode, 0 means need to set Tuner I2C working mode and check I2C bus +// Output: success or fail flag +//***************************************************************************************** +int FrontEndBoardInit(int Freq, int PLLType, int InitMode) +{ + if(InitMode==0) { // need to set Tuner I2C bus type and check I2C bus + // here Get Tuner and Demod I2C address if needed. + if(0x03!=CheckDemodI2C()) return(false); // check if Demod I2C is error ! + + // first determine the Tuner I2C type + // set Tuner I2C bus type according to the Demodulator type + if(GetDemodType()==Demod_8GL5) SetTunerI2CInternal(); //8GL5 type + else SetTunerI2CExternal(); + + if(0x03!=CheckTunerI2C(lowTunerI2CAdr)) return(false); // check if Tuner I2C is error ! + } + + TunerInit(lowTunerI2CAdr,PLLType); // init Tuner + SetTunerFreq(lowTunerI2CAdr,Freq, 8, PLLType);// set default frequency point + + // init Demodulator + DemodInit(DemodParallelOutType); + + return true; +} + +//************************************************************************** +// function: Set the Demodulator works in single Carrier mode +// return value: false means operation is fail, true means operation is success +//************************************************************************** +int DemodSingleCarrSet() +{ + USB_I2C_READ myi2cRead; + unsigned char ReadRet; + + myi2cRead=sread(lowDemodI2CAdr, 0x7C); + if(myi2cRead.ACK_status==1) ReadRet=myi2cRead.read_data; + else return(false); + + if((ReadRet & 0x80) !=0x80 ) // in Multiple Carrier mode + { ReadRet=(m_BYTE) (ReadRet | 0x80); + swrite(lowDemodI2CAdr, 0x7C,ReadRet); + } + + return(true); +} + +//************************************************************************** +// function: Set the Demodulator works in multiple Carrier mode +// return value: false means operation is fail, true means operation is success +//************************************************************************** +int DemodMultiCarrSet() +{ + USB_I2C_READ myi2cRead; + unsigned char ReadRet; + + myi2cRead=sread(lowDemodI2CAdr, 0x7C); + if(myi2cRead.ACK_status==1) ReadRet=myi2cRead.read_data; + else return(false); + + if((ReadRet & 0x80) ==0x80 ) // in single Carrier mode + { ReadRet=(m_BYTE) (ReadRet & 0x7f); + swrite(lowDemodI2CAdr, 0x7C,ReadRet); + } + return(true); +} +//***************************************************************************************** +// Function: wait for Demod and Tuner are locked while detecting carrier mode. +// Input: +// SupportSingleCarrier: indicate support multiple carrier, single carrier or both of them. +// Output: lock or no lock status +//***************************************************************************************** +int WaitForDetect(int SupportSingleCarrier) +{ + int ret_status; + + ret_status=false; + + if( SupportSingleCarrier== MultipleCarrierOnly ) + { + if(DemodMultiCarrSet()==false) return(false); // set Demod works in Multiple Carrier mode + ret_status=DetectFEBoard(); + } + else if(SupportSingleCarrier== SingleCarrierOnly) + { + if(DemodSingleCarrSet()==false) return(false); // set Demod works in Multiple Carrier mode + ret_status=DetectFEBoard(); + } + else if(SupportSingleCarrier== BothMultipleSingle) + { + if(DemodMultiCarrSet()==false) return(false);// set Demod works in Multiple Carrier mode + ret_status=DetectFEBoard(); + if(ret_status!=VIEW_FIND) + { + if(DemodSingleCarrSet()==false) return(false);// set Demod works in Multiple Carrier mode + ret_status=DetectFEBoard(); + } + } + return(ret_status); +} + +//***************************************************************************************** +// Function: Detect front-end board in one certain carrier mode. +// Input: None +// Output: Detect result status, VIEW_FIND or VIEW_TIME_OUT +//***************************************************************************************** +int DetectFEBoard() +{ + int HaveEnabledView=0; + int ret_status, LockTimes; + int DetectTimes=0; + + LockTimes=0; + HaveEnabledView=0; + + while(HaveEnabledView==0) + { + DetectTimes++; + ret_status=DetectDemodMode(); // all other times + if(ret_status== DetectOkOnLock ){ + LockTimes++; + if( LockTimes>MaxLockTimes ){ + HaveEnabledView=1; + break; } + } + Sleep(200); + if(HaveEnabledView==0 && DetectTimes>=MaxNoLockTimes) break; // always no lock ! wait for some times + } + if (HaveEnabledView) + { + ProcessOnGI595SC(); // special processing for GI595 and signal carrier + return VIEW_FIND; + } + else return VIEW_TIME_OUT; +} +//************************************************************************** +// function: return carrier mode +// input: None +// output: Carrier mode. +//************************************************************************** +int GetCarrMode() +{ + USB_I2C_READ myi2cRead; + int CarrMode=0; + + myi2cRead=sread(lowDemodI2CAdr, 0x7C); // 0x03 + if( myi2cRead.ACK_status ==1) + { + if( (myi2cRead.read_data & 0x80) == 0x80) + CarrMode=SingleCarrier; //single carrier mode + else if( (myi2cRead.read_data & 0x80) == 0x00) + CarrMode=MultiCarrier; + } + return(CarrMode); +} +//************************************************************************** +// function: Special Process for Single Carrier and GI595 case +// input: None +// output: process success or not +// This function shall be called when the signal is lock +//************************************************************************** +int ProcessOnGI595SC() +{ + int CarrMode; + int GI_mode; + + CarrMode=GetCarrMode(); + GI_mode=GetGISet(); + //DbgLogTrace(("ProcessOnGI595SC CarrierMode=%x GI_mode=%x\n",CarrMode,GI_mode)); + if(SingleCarrier==CarrMode && GI_595==GI_mode) + { + swrite(lowTunerI2CAdr, 0x25, 0x42); + Sleep(100); + swrite(lowTunerI2CAdr, 0x25, 0x7D); + return(1); + } + else return(0); +} + +//***************************************************************************************** +// Function: calculate DBB signal quality +// Input: None +// Output: quality value, 100 means the best +//***************************************************************************************** +int DBBSignalQuality() +{ + USB_I2C_READ myi2cRead; + int Quality=0; + + myi2cRead=sread (0x32, 0x4B); + if((myi2cRead.read_data & 0xC0) != 0xC0) + Quality= -100; + else + { + myi2cRead=sread(lowDemodI2CAdr, 0x95); + if(myi2cRead.ACK_status==1) Quality=myi2cRead.read_data; + Quality = 100 - 100*Quality/255; + } + return Quality; +} +//************************************************************************** +// function: Channel Scan scheme2 +// input : Frequency point list that need to scan. +// the list last item shall be 0 marked as end flag +// return value are stored in FindChannel +// +// write by Liu dong, 2007/11/19 +//************************************************************************** +#if 0 +int ChannelScan(int *ScanChannelTable) +{ + int Freq; + int k,m; + double RSSI_val,RSSI_val_total,RSSI_val_ave; + int HaveEnabledView=0; + int ret_status, LockTimes; + int DetectTimes=0; + int FindAllProg; + + k=0; + while(1){ + Freq=ScanChannelTable[k++]; + if(Freq<=0) break; + + SetTunerFreq(0xc2,Freq,8,REFCLK16384); //set frequency point to tuner + + RSSI_val_total=0; + for(m=0;m NoSignalThreshold ) + { + LockTimes=0; + + HaveEnabledView=0; + while(HaveEnabledView==0){ + DetectTimes++; + ret_status=DetectDemodMode(); + if(ret_status== DetectOkOnLock ) // #define DetectOkOnLock 1 + { + LockTimes++; + if( LockTimes>MaxLockTimes ){ HaveEnabledView=1; break; } + } + Sleep(200); + if(HaveEnabledView==0 && DetectTimes>=MaxNoLockTimes) break; // always no lock ! wait for some times + } + + if (HaveEnabledView) + { + FindAllProg=0; + FindProgNum=0; + while( FindAllProg==0) FindAllProg=GetProgramInfo(); + + FindChannel[k]. ProgNum= FindProgNum; + if(FindProgNum>0) { + for(m=0;m< FindProgNum;m++) { + FindChannel[k]. ProgID[m]= myMpegInfo[m]. m_program_id; + FindChannel[k]. VideoID[m]= myMpegInfo[m]. m_video_pid; + FindChannel[k]. VideoType[m]= myMpegInfo[m]. m_video_type; + FindChannel[k]. AudioID[m]= myMpegInfo[m]. m_audio_pid; + FindChannel[k]. AudioType[m]= myMpegInfo[m]. m_audio_type; + } + } + + } //end of searching Program + } // end of Detect signal and program searching + } // end of scan all channels in List + + return 1; +} +#endif + +//************************************************************************** +// function: I2C bus Read operation +// input : target -- Device address +// addr -- register address +// output: Read result, include read data and ACK status +// Note: User shall implement this function according to real application platform +//************************************************************************** +static USB_I2C_READ sread(m_BYTE target , m_BYTE addr) +{ + USB_I2C_READ readback; + u8 wb[2] = { addr,addr }; + u8 rb[2]; + + m_U3300DmbthState->i2c_addr = target>>1; + + struct i2c_msg msg[2] = { + { .addr = m_U3300DmbthState->i2c_addr , .flags = 0, .buf = wb, .len = 2 }, + { .addr = m_U3300DmbthState->i2c_addr , .flags = I2C_M_RD, .buf = rb, .len = 2 }, + }; + + if (i2c_transfer(m_U3300DmbthState->i2c_adap, msg, 2) != 2) + { + printk("i2c read error on %d\n",addr); + readback.ACK_status = 0; + readback.read_data = 0; + return readback; + } + //else + //printk("Read target =%x Reg %x value %x\n",target, addr, rb[0]); + + readback.ACK_status = 1; + readback.read_data = rb[0]; + return readback; +} + +//************************************************************************** +// function: I2C bus write operation +// input : target -- Device address +// addr -- register address +// data -- write data +// output: Read result, include read data and ACK status +// Note: User shall implement this function according to real application platform +//************************************************************************** +static void swrite(m_BYTE target, m_BYTE addr,m_BYTE data) +{ + u8 b[2] = { addr, data }; + m_U3300DmbthState->i2c_addr = target >>1 ; + //printk("Write target =%x Reg %x value %x\n",target, addr, data); + struct i2c_msg msg = { + .addr = m_U3300DmbthState->i2c_addr , .flags = 0, .buf = b, .len = 2 + }; + i2c_transfer(m_U3300DmbthState->i2c_adap, &msg, 1); +} +/* +static int dib3000mc_read_byte(struct dib3000mc_state *state, u8 dev_addr, u8 reg, u8 *value) +{ + u8 wb[2] = { reg,reg }; + u8 rb[2]; + + state->i2c_addr = dev_addr>>1; + + struct i2c_msg msg[2] = { + { .addr = state->i2c_addr , .flags = 0, .buf = wb, .len = 2 }, + { .addr = state->i2c_addr , .flags = I2C_M_RD, .buf = rb, .len = 2 }, + }; + + if (i2c_transfer(state->i2c_adap, msg, 2) != 2) + { + printk("i2c read error on %d\n",reg); + return 1; + } + //else + // printk("Read Legend Reg %x value %x\n",reg, rb[0]); + + *value = rb[0]; + return 0; +} +*/ +/*static int dib3000mc_write_byte(struct dib3000mc_state *state, u8 dev_addr, u8 reg, u8 val) +{ + u8 b[2] = { reg, val }; + u8 dev_addr; + + state->i2c_addr = dev_addr >>1 ; + + struct i2c_msg msg = { + .addr = state->i2c_addr , .flags = 0, .buf = b, .len = 2 + }; + return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; +}*/ + +//************************************************************************** +// function: Get TV program information +// input : None +// Return: have got program information or not +//************************************************************************** +int GetProgramInfo() +{ + return 1; +} + +static int dib3000mc_identify(struct dib3000mc_state *state) +{ + u16 value; + u8 version=0xff; + m_U3300DmbthState = state; + + state->dev_id = GetDemodType(); + printk("U3100-DMBTH Device ID: %d\n",state->dev_id); + return 0; +} + +static i