diff --git a/packages/linux/patches/linux-3.6.7-210-dvbsky.patch b/packages/linux/patches/linux-3.6.7-210-dvbsky.patch new file mode 100644 index 0000000000..9a910cadcb --- /dev/null +++ b/packages/linux/patches/linux-3.6.7-210-dvbsky.patch @@ -0,0 +1,5788 @@ +diff -urN a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c +--- a/drivers/media/dvb/dvb-usb/dw2102.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/dvb/dvb-usb/dw2102.c 2012-11-18 23:22:52.641154591 +0800 +@@ -19,6 +19,7 @@ + #include "stb6000.h" + #include "eds1547.h" + #include "cx24116.h" ++#include "m88ds3103.h" + #include "tda1002x.h" + #include "mt312.h" + #include "zl10039.h" +@@ -830,6 +831,39 @@ + return 0; + } + ++static int dvbsky_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) ++{ ++ int i; ++ u8 obuf[] = { 0x1e, 0x00 }; ++ u8 ibuf[] = { 0 }; ++ struct i2c_msg msg[] = { ++ { ++ .addr = 0x51, ++ .flags = 0, ++ .buf = obuf, ++ .len = 2, ++ }, { ++ .addr = 0x51, ++ .flags = I2C_M_RD, ++ .buf = ibuf, ++ .len = 1, ++ ++ } ++ }; ++ ++ for (i = 0; i < 6; i++) { ++ obuf[1] = i; ++ if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) ++ break; ++ else ++ mac[i] = ibuf[0]; ++ ++ debug_dump(mac, 6, printk); ++ } ++ ++ return 0; ++} ++ + static int su3000_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, +@@ -878,6 +912,43 @@ + return 0; + } + ++static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) ++{ ++ ++ struct dvb_usb_adapter *udev_adap = ++ (struct dvb_usb_adapter *)(fe->dvb->priv); ++ ++ u8 obuf[3] = { 0xe, 0x80, 0 }; ++ u8 ibuf[] = { 0 }; ++ ++ info("US6830: %s!\n", __func__); ++ ++ if (voltage == SEC_VOLTAGE_OFF) ++ obuf[2] = 0; ++ else ++ obuf[2] = 1; ++ ++ if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0) ++ err("command 0x0e transfer failed."); ++ ++ return 0; ++} ++ ++static int bstusb_restart(struct dvb_frontend *fe) ++{ ++ ++ struct dvb_usb_adapter *udev_adap = ++ (struct dvb_usb_adapter *)(fe->dvb->priv); ++ ++ u8 obuf[3] = { 0x36, 3, 0 }; ++ u8 ibuf[] = { 0 }; ++ ++ if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0) ++ err("command 0x36 transfer failed."); ++ ++ return 0; ++} ++ + static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) + { + static u8 led_off[] = { 0 }; +@@ -983,6 +1054,24 @@ + .ci_mode = 1, + }; + ++static struct m88ds3103_config US6830_ds3103_config = { ++ .demod_address = 0x68, ++ .ci_mode = 1, ++ .pin_ctrl = 0x83, ++ .ts_mode = 0, ++ .start_ctrl = bstusb_restart, ++ .set_voltage = bstusb_set_voltage, ++}; ++ ++static struct m88ds3103_config US6832_ds3103_config = { ++ .demod_address = 0x68, ++ .ci_mode = 1, ++ .pin_ctrl = 0x80, ++ .ts_mode = 0, ++ .start_ctrl = bstusb_restart, ++ .set_voltage = bstusb_set_voltage, ++}; ++ + static int dw2104_frontend_attach(struct dvb_usb_adapter *d) + { + struct dvb_tuner_ops *tuner_ops = NULL; +@@ -1210,6 +1299,87 @@ + return 0; + } + ++static int US6830_frontend_attach(struct dvb_usb_adapter *d) ++{ ++ u8 obuf[3] = { 0xe, 0x04, 1 }; ++ u8 ibuf[] = { 0 }; ++ ++ info("US6830: %s!\n", __func__); ++ ++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) ++ err("command 0x0e transfer failed."); ++ ++ obuf[0] = 0xe; ++ obuf[1] = 0x83; ++ obuf[2] = 0; ++ ++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) ++ err("command 0x0e transfer failed."); ++ ++ msleep(20); ++ ++ obuf[0] = 0xe; ++ obuf[1] = 0x83; ++ obuf[2] = 1; ++ ++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) ++ err("command 0x0e transfer failed."); ++ ++ obuf[0] = 0x51; ++ ++ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) ++ err("command 0x51 transfer failed."); ++ ++ d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6830_ds3103_config, ++ &d->dev->i2c_adap); ++ if (d->fe_adap[0].fe == NULL) ++ return -EIO; ++ ++ info("Attached M88DS3103!\n"); ++ ++ return 0; ++} ++ ++static int US6832_frontend_attach(struct dvb_usb_adapter *d) ++{ ++ u8 obuf[3] = { 0xe, 0x04, 1 }; ++ u8 ibuf[] = { 0 }; ++ ++ info("US6832: %s!\n", __func__); ++ ++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) ++ err("command 0x0e transfer failed."); ++ ++ obuf[0] = 0xe; ++ obuf[1] = 0x83; ++ obuf[2] = 0; ++ ++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) ++ err("command 0x0e transfer failed."); ++ ++ msleep(20); ++ obuf[0] = 0xe; ++ obuf[1] = 0x83; ++ obuf[2] = 1; ++ ++ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) ++ err("command 0x0e transfer failed."); ++ ++ obuf[0] = 0x51; ++ ++ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) ++ err("command 0x51 transfer failed."); ++ ++ d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6832_ds3103_config, ++ &d->dev->i2c_adap); ++ if (d->fe_adap[0].fe == NULL) ++ return -EIO; ++ ++ info("Attached M88DS3103!\n"); ++ ++ return 0; ++} ++ + static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) + { + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, +@@ -1447,6 +1617,9 @@ + TEVII_S480_1, + TEVII_S480_2, + X3M_SPC1400HD, ++ BST_US6830HD, ++ BST_US6831HD, ++ BST_US6832HD, + }; + + static struct usb_device_id dw2102_table[] = { +@@ -1465,6 +1638,9 @@ + [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, + [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, + [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, ++ [BST_US6830HD] = {USB_DEVICE(0x0572, 0x6830)}, ++ [BST_US6831HD] = {USB_DEVICE(0x0572, 0x6831)}, ++ [BST_US6832HD] = {USB_DEVICE(0x0572, 0x6832)}, + { } + }; + +@@ -1870,6 +2046,106 @@ + } + }; + ++static struct dvb_usb_device_properties US6830_properties = { ++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, ++ .usb_ctrl = DEVICE_SPECIFIC, ++ .size_of_priv = sizeof(struct su3000_state), ++ .power_ctrl = su3000_power_ctrl, ++ .num_adapters = 1, ++ .identify_state = su3000_identify_state, ++ .i2c_algo = &su3000_i2c_algo, ++ ++ .rc.legacy = { ++ .rc_map_table = rc_map_su3000_table, ++ .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), ++ .rc_interval = 150, ++ .rc_query = dw2102_rc_query, ++ }, ++ ++ .read_mac_address = dvbsky_read_mac_address, ++ ++ .generic_bulk_ctrl_endpoint = 0x01, ++ ++ .adapter = { ++ { ++ .num_frontends = 1, ++ .fe = {{ ++ .streaming_ctrl = su3000_streaming_ctrl, ++ .frontend_attach = US6830_frontend_attach, ++ .stream = { ++ .type = USB_BULK, ++ .count = 8, ++ .endpoint = 0x82, ++ .u = { ++ .bulk = { ++ .buffersize = 4096, ++ } ++ } ++ } ++ }}, ++ } ++ }, ++ .num_device_descs = 2, ++ .devices = { ++ { "Bestunar US6830 HD", ++ { &dw2102_table[BST_US6830HD], NULL }, ++ { NULL }, ++ }, ++ { "Bestunar US6831 HD", ++ { &dw2102_table[BST_US6831HD], NULL }, ++ { NULL }, ++ }, ++ } ++}; ++ ++static struct dvb_usb_device_properties US6832_properties = { ++ .caps = DVB_USB_IS_AN_I2C_ADAPTER, ++ .usb_ctrl = DEVICE_SPECIFIC, ++ .size_of_priv = sizeof(struct su3000_state), ++ .power_ctrl = su3000_power_ctrl, ++ .num_adapters = 1, ++ .identify_state = su3000_identify_state, ++ .i2c_algo = &su3000_i2c_algo, ++ ++ .rc.legacy = { ++ .rc_map_table = rc_map_su3000_table, ++ .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), ++ .rc_interval = 150, ++ .rc_query = dw2102_rc_query, ++ }, ++ ++ .read_mac_address = dvbsky_read_mac_address, ++ ++ .generic_bulk_ctrl_endpoint = 0x01, ++ ++ .adapter = { ++ { ++ .num_frontends = 1, ++ .fe = {{ ++ .streaming_ctrl = su3000_streaming_ctrl, ++ .frontend_attach = US6832_frontend_attach, ++ .stream = { ++ .type = USB_BULK, ++ .count = 8, ++ .endpoint = 0x82, ++ .u = { ++ .bulk = { ++ .buffersize = 4096, ++ } ++ } ++ } ++ }}, ++ } ++ }, ++ .num_device_descs = 1, ++ .devices = { ++ { "Bestunar US6832 HD", ++ { &dw2102_table[BST_US6832HD], NULL }, ++ { NULL }, ++ }, ++ } ++}; ++ + static int dw2102_probe(struct usb_interface *intf, + const struct usb_device_id *id) + { +@@ -1926,6 +2202,10 @@ + 0 == dvb_usb_device_init(intf, p7500, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &su3000_properties, ++ THIS_MODULE, NULL, adapter_nr) || ++ 0 == dvb_usb_device_init(intf, &US6830_properties, ++ THIS_MODULE, NULL, adapter_nr) || ++ 0 == dvb_usb_device_init(intf, &US6832_properties, + THIS_MODULE, NULL, adapter_nr)) + return 0; + +diff -urN a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig +--- a/drivers/media/dvb/dvb-usb/Kconfig 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/dvb/dvb-usb/Kconfig 2012-11-18 23:23:02.517154858 +0800 +@@ -279,6 +279,7 @@ + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE ++ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE + select DVB_SI21XX if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_MT312 if !DVB_FE_CUSTOMISE +diff -urN a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig +--- a/drivers/media/dvb/frontends/Kconfig 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/dvb/frontends/Kconfig 2012-11-18 23:23:15.397155199 +0800 +@@ -215,6 +215,20 @@ + help + A DVB-S/S2 tuner module. Say Y when you want to support this frontend. + ++config DVB_M88DS3103 ++ tristate "Montage DS3103 based" ++ depends on DVB_CORE && I2C ++ default m if DVB_FE_CUSTOMISE ++ help ++ A DVB-S/S2 tuner module. Say Y when you want to support this frontend. ++ ++config DVB_M88DC2800 ++ tristate "Montage DC2800 DVB-C" ++ depends on DVB_CORE && I2C ++ default m if DVB_FE_CUSTOMISE ++ help ++ A DVB-C tuner module. Say Y when you want to support this frontend. ++ + config DVB_SI21XX + tristate "Silicon Labs SI21XX based" + depends on DVB_CORE && I2C +diff -urN a/drivers/media/dvb/frontends/m88dc2800.c b/drivers/media/dvb/frontends/m88dc2800.c +--- a/drivers/media/dvb/frontends/m88dc2800.c 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/media/dvb/frontends/m88dc2800.c 2012-11-18 23:23:20.205155329 +0800 +@@ -0,0 +1,2235 @@ ++/* ++ M88DC2800/M88TC2800 - DVB-C demodulator and tuner from Montage ++ ++ Copyright (C) 2012 Max nibble ++ Copyright (C) 2011 Montage Technology ++ ++ 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; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dvb_frontend.h" ++#include "m88dc2800.h" ++ ++struct m88dc2800_state { ++ struct i2c_adapter* i2c; ++ const struct m88dc2800_config *config; ++ struct dvb_frontend frontend; ++ u32 freq; ++ u32 ber; ++ u32 sym; ++ u16 qam; ++ u8 inverted; ++ u32 xtal; ++ /*tuner state*/ ++ u8 tuner_init_OK; /* Tuner initialize status */ ++ u8 tuner_dev_addr; /* Tuner device address */ ++ u32 tuner_freq; /* RF frequency to be set, unit: KHz */ ++ u16 tuner_qam; /* Reserved */ ++ u16 tuner_mode; ++ u8 tuner_bandwidth; /* Bandwidth of the channel, unit: MHz, 6/7/8 */ ++ u8 tuner_loopthrough; /* Tuner loop through switch, 0/1 */ ++ u32 tuner_crystal; /* Tuner crystal frequency, unit: KHz */ ++ u32 tuner_dac; /* Tuner DAC frequency, unit: KHz */ ++ u16 tuner_mtt; /* Tuner chip version, D1: 0x0d, E0: 0x0e, E1: 0x8e */ ++ u16 tuner_custom_cfg; ++ u32 tuner_version; /* Tuner driver version number */ ++ u32 tuner_time; ++}; ++ ++static int debug; ++module_param(debug, int, 0644); ++MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); ++ ++#define dprintk(args...) \ ++ do { \ ++ if (debug) \ ++ printk(KERN_INFO "m88dc2800: " args); \ ++ } while (0) ++ ++ ++static int m88dc2800_i2c_write(struct m88dc2800_state *state, u8 addr, u8 *p_data, u8 len) ++{ ++ struct i2c_msg msg = { .flags = 0 }; ++ ++ msg.addr = addr; ++ msg.buf = p_data; ++ msg.len = len; ++ ++ return i2c_transfer(state->i2c, &msg, 1); ++} ++ ++static int m88dc2800_i2c_read(struct m88dc2800_state *state, u8 addr, u8 *p_data, u8 len) ++{ ++ struct i2c_msg msg = { .flags = I2C_M_RD }; ++ ++ msg.addr = addr; ++ msg.buf = p_data; ++ msg.len = len; ++ ++ return i2c_transfer(state->i2c, &msg, 1); ++} ++ ++/*demod register operations.*/ ++static int WriteReg(struct m88dc2800_state *state, u8 reg, u8 data) ++{ ++ u8 buf[] = { reg, data }; ++ u8 addr = state->config->demod_address; ++ int err; ++ ++ if (debug > 1) ++ printk("m88dc2800: %s: write reg 0x%02x, value 0x%02x\n", ++ __func__, reg, data); ++ ++ err = m88dc2800_i2c_write(state, addr, buf, 2); ++ ++ if (err != 1) { ++ printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," ++ " value == 0x%02x)\n", __func__, err, reg, data); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int ReadReg(struct m88dc2800_state *state, u8 reg) ++{ ++ int ret; ++ u8 b0[] = { reg }; ++ u8 b1[] = { 0 }; ++ u8 addr = state->config->demod_address; ++ ++ ret = m88dc2800_i2c_write(state, addr, b0, 1); ++ ++ if (ret != 1) { ++ printk(KERN_ERR "%s: reg=0x%x (error=%d)\n", ++ __func__, reg, ret); ++ return -EIO; ++ } ++ ++ ret = m88dc2800_i2c_read(state, addr, b1, 1); ++ ++ if (debug > 1) ++ printk(KERN_INFO "m88dc2800: read reg 0x%02x, value 0x%02x\n", ++ reg, b1[0]); ++ return b1[0]; ++} ++ ++static int _mt_fe_tn_set_reg(struct m88dc2800_state *state, u8 reg, u8 data) ++{ ++ int ret; ++ u8 buf[2]; ++ u8 addr = state->tuner_dev_addr; ++ ++ buf[1] = ReadReg(state, 0x86); ++ buf[1] |= 0x80; ++ ret = WriteReg(state, 0x86, buf[1]); ++ ++ buf[0] = reg; ++ buf[1] = data; ++ ++ ret = m88dc2800_i2c_write(state, addr, buf, 2); ++ if(ret != 1) ++ return -EIO; ++ return 0; ++} ++ ++static int _mt_fe_tn_get_reg(struct m88dc2800_state *state, u8 reg, u8 *p_data) ++{ ++ int ret; ++ u8 buf[2]; ++ u8 addr = state->tuner_dev_addr; ++ ++ buf[1] = ReadReg(state, 0x86); ++ buf[1] |= 0x80; ++ ret = WriteReg(state, 0x86, buf[1]); ++ ++ buf[0] = reg; ++ ret = m88dc2800_i2c_write(state, addr, buf, 1); ++ ++ msleep(1); ++ ++ buf[1] = ReadReg(state, 0x86); ++ buf[1] |= 0x80; ++ ret = WriteReg(state, 0x86, buf[1]); ++ ++ return m88dc2800_i2c_read(state, addr, p_data, 1); ++} ++ ++/* Tuner operation functions.*/ ++static int _mt_fe_tn_set_RF_front_tc2800(struct m88dc2800_state *state) ++{ ++ u32 freq_KHz = state->tuner_freq; ++ ++ if (state->tuner_mtt == 0xD1) { /* D1 */ ++ if (freq_KHz <= 123000) { ++ if (freq_KHz <= 56000) { ++ _mt_fe_tn_set_reg(state, 0x58, 0x9b); ++ _mt_fe_tn_set_reg(state, 0x59, 0x00); ++ _mt_fe_tn_set_reg(state, 0x5d, 0x00); ++ _mt_fe_tn_set_reg(state, 0x5e, 0x00); ++ }else if (freq_KHz <= 64000) { ++ _mt_fe_tn_set_reg(state, 0x58, 0x9b); ++ _mt_fe_tn_set_reg(state, 0x59, 0x10); ++ _mt_fe_tn_set_reg(state, 0x5d, 0x01); ++ _mt_fe_tn_set_reg(state, 0x5e, 0x08); ++ }else if (freq_KHz <= 72000) { ++ _mt_fe_tn_set_reg(state, 0x58, 0x9b); ++ _mt_fe_tn_set_reg(state, 0x59, 0x20); ++ _mt_fe_tn_set_reg(state, 0x5d, 0x02); ++ _mt_fe_tn_set_reg(state, 0x5e, 0x10); ++ }else if (freq_KHz <= 80000) { ++ _mt_fe_tn_set_reg(state, 0x58, 0x9b); ++ _mt_fe_tn_set_reg(state, 0x59, 0x30); ++ _mt_fe_tn_set_reg(state, 0x5d, 0x03); ++ _mt_fe_tn_set_reg(state, 0x5e, 0x18); ++ }else if (freq_KHz <= 88000) { ++ _mt_fe_tn_set_reg(state, 0x58, 0x9b); ++ _mt_fe_tn_set_reg(state, 0x59, 0x40); ++ _mt_fe_tn_set_reg(state, 0x5d, 0x04); ++ _mt_fe_tn_set_reg(state, 0x5e, 0x20); ++ }else if (freq_KHz <= 96000) { ++ _mt_fe_tn_set_reg(state, 0x58, 0x9b); ++ _mt_fe_tn_set_reg(state, 0x59, 0x50); ++ _mt_fe_tn_set_reg(state, 0x5d, 0x05); ++ _mt_fe_tn_set_reg(state, 0x5e, 0x28); ++ }else if (freq_KHz <= 104000) { ++ _mt_fe_tn_set_reg(state, 0x58, 0x9b); ++ _mt_fe_tn_set_reg(state, 0x59, 0x60); ++ _mt_fe_tn_set_reg(state, 0x5d, 0x06); ++ _mt_fe_tn_set_reg(state, 0x5e, 0x30); ++ }else { ++ _mt_fe_tn_set_reg(state, 0x58, 0x9b); ++ _mt_fe_tn_set_reg(state, 0x59, 0x70); ++ _mt_fe_tn_set_reg(state, 0x5d, 0x07); ++ _mt_fe_tn_set_reg(state, 0x5e, 0x38); ++ } ++ _mt_fe_tn_set_reg(state, 0x5a, 0x75); ++ _mt_fe_tn_set_reg(state, 0x73, 0x0c); ++ } else { /* if (freq_KHz > 112000) */ ++ _mt_fe_tn_set_reg(state, 0x58, 0x7b); ++ if (freq_KHz <= 304000) { ++ if (freq_KHz <= 136000) { ++ _mt_fe_tn_set_reg(state, 0x5e, 0x40); ++ }else if (freq_KHz <= 160000) { ++ _mt_fe_tn_set_reg(state, 0x5e, 0x48); ++ }else if (freq_KHz <= 184000) { ++ _mt_fe_tn_set_reg(state, 0x5e, 0x50); ++ }else if (freq_KHz <= 208000) { ++ _mt_fe_tn_set_reg(state, 0x5e, 0x58); ++ }else if (freq_KHz <= 232000) { ++ _mt_fe_tn_set_reg(state, 0x5e, 0x60); ++ }else if (freq_KHz <= 256000) { ++ _mt_fe_tn_set_reg(state, 0x5e, 0x68); ++ }else if (freq_KHz <= 280000) { ++ _mt_fe_tn_set_reg(state, 0x5e, 0x70); ++ }else { /*if (freq_KHz <= 304000)*/ ++ _mt_fe_tn_set_reg(state, 0x5e, 0x78); ++ } ++ if (freq_KHz <= 171000) { ++ _mt_fe_tn_set_reg(state, 0x73, 0x08); ++ }else if (freq_KHz <= 211000) { ++ _mt_fe_tn_set_reg(state, 0x73, 0x0a); ++ }else { ++ _mt_fe_tn_set_reg(state, 0x73, 0x0e); ++ } ++ }else { /* if (freq_KHz > 304000) */ ++ _mt_fe_tn_set_reg(state, 0x5e, 0x88); ++ if (freq_KHz <= 400000) { ++ _mt_fe_tn_set_reg(state, 0x73, 0x0c); ++ }else if (freq_KHz <= 450000) { ++ _mt_fe_tn_set_reg(state, 0x73, 0x09); ++ }else if (freq_KHz <= 550000) { ++ _mt_fe_tn_set_reg(state, 0x73, 0x0e); ++ }else if (freq_KHz <= 650000) { ++ _mt_fe_tn_set_reg(state, 0x73, 0x0d); ++ }else { /*if (freq_KHz > 650000) */ ++ _mt_fe_tn_set_reg(state, 0x73, 0x0e); ++ } ++ } ++ } ++ ++ if (freq_KHz > 800000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x24); ++ else if (freq_KHz > 700000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x34); ++ else if (freq_KHz > 500000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x44); ++ else if (freq_KHz > 300000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x43); ++ else if (freq_KHz > 220000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x54); ++ else if (freq_KHz > 110000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x14); ++ else ++ _mt_fe_tn_set_reg(state, 0x87, 0x54); ++ ++ if (freq_KHz > 600000) ++ _mt_fe_tn_set_reg(state, 0x6a, 0x53); ++ else if (freq_KHz > 500000) ++ _mt_fe_tn_set_reg(state, 0x6a, 0x57); ++ else ++ _mt_fe_tn_set_reg(state, 0x6a, 0x59); ++ ++ if (freq_KHz < 200000) { ++ _mt_fe_tn_set_reg(state, 0x20, 0x5d); ++ }else if (freq_KHz < 500000) { ++ _mt_fe_tn_set_reg(state, 0x20, 0x7d); ++ }else { ++ _mt_fe_tn_set_reg(state, 0x20, 0xfd); ++ }/* end of 0xD1 */ ++ }else if (state->tuner_mtt == 0xE1) { /* E1 */ ++ if (freq_KHz <= 112000) { /* 123MHz */ ++ if (freq_KHz <= 56000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x01); ++ }else if (freq_KHz <= 64000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x09); ++ }else if (freq_KHz <= 72000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x11); ++ }else if (freq_KHz <= 80000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x19); ++ }else if (freq_KHz <= 88000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x21); ++ }else if (freq_KHz <= 96000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x29); ++ }else if (freq_KHz <= 104000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x31); ++ }else {/* if (freq_KHz <= 112000) */ ++ _mt_fe_tn_set_reg(state, 0x5c, 0x39); ++ } ++ _mt_fe_tn_set_reg(state, 0x5b, 0x30); ++ }else { /* if (freq_KHz > 112000) */ ++ if (freq_KHz <= 304000) { ++ if (freq_KHz <= 136000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x41); ++ }else if (freq_KHz <= 160000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x49); ++ }else if (freq_KHz <= 184000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x51); ++ }else if (freq_KHz <= 208000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x59); ++ }else if (freq_KHz <= 232000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x61); ++ }else if (freq_KHz <= 256000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x69); ++ }else if (freq_KHz <= 280000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x71); ++ }else { /*if (freq_KHz <= 304000)*/ ++ _mt_fe_tn_set_reg(state, 0x5c, 0x79); ++ } ++ ++ if (freq_KHz <= 150000) { ++ _mt_fe_tn_set_reg(state, 0x5b, 0x28); ++ }else if (freq_KHz <= 256000) { ++ _mt_fe_tn_set_reg(state, 0x5b, 0x29); ++ }else { ++ _mt_fe_tn_set_reg(state, 0x5b, 0x2a); ++ } ++ }else { /* if (freq_KHz > 304000) */ ++ if (freq_KHz <= 400000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x89); ++ }else if (freq_KHz <= 450000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x91); ++ }else if (freq_KHz <= 650000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0x98); ++ }else if (freq_KHz <= 850000) { ++ _mt_fe_tn_set_reg(state, 0x5c, 0xa0); ++ }else { ++ _mt_fe_tn_set_reg(state, 0x5c, 0xa8); ++ } ++ _mt_fe_tn_set_reg(state, 0x5b, 0x08); ++ } ++ } ++ } /* end of 0xE1 */ ++ return 0; ++} ++ ++static int _mt_fe_tn_cali_PLL_tc2800(struct m88dc2800_state *state, u32 freq_KHz, u32 cali_freq_thres_div2, u32 cali_freq_thres_div3r, u32 cali_freq_thres_div3) ++{ ++ s32 N, F, MUL; ++ u8 buf, tmp, tmp2; ++ s32 M; ++ const s32 crystal_KHz = state->tuner_crystal; ++ ++ if (state->tuner_mtt == 0xD1) { ++ M = state->tuner_crystal / 4000; ++ if (freq_KHz > cali_freq_thres_div2) { ++ MUL = 4; ++ tmp = 2; ++ }else if (freq_KHz > 300000) { ++ MUL = 8; ++ tmp = 3; ++ }else if (freq_KHz > (cali_freq_thres_div2 / 2)) { ++ MUL = 8; ++ tmp = 4; ++ }else if (freq_KHz > (cali_freq_thres_div2 / 4)) { ++ MUL = 16; ++ tmp = 5; ++ }else if (freq_KHz > (cali_freq_thres_div2 / 8)) { ++ MUL = 32; ++ tmp = 6; ++ }else if (freq_KHz > (cali_freq_thres_div2 / 16)){ ++ MUL = 64; ++ tmp = 7; ++ }else { /* invalid */ ++ MUL = 0; ++ tmp = 0; ++ return 1; ++ } ++ }else if (state->tuner_mtt == 0xE1) { ++ M = state->tuner_crystal / 1000; ++ ++ _mt_fe_tn_set_reg(state, 0x30, 0xff); ++ _mt_fe_tn_set_reg(state, 0x32, 0xe0); ++ _mt_fe_tn_set_reg(state, 0x33, 0x86); ++ _mt_fe_tn_set_reg(state, 0x37, 0x70); ++ _mt_fe_tn_set_reg(state, 0x38, 0x20); ++ _mt_fe_tn_set_reg(state, 0x39, 0x18); ++ _mt_fe_tn_set_reg(state, 0x89, 0x83); ++ ++ if (freq_KHz > cali_freq_thres_div2) { ++ M = M / 4; ++ MUL = 4; ++ tmp = 2; ++ tmp2 = M + 16; /*48*/ ++ }else if (freq_KHz > cali_freq_thres_div3r) { ++ M = M / 3; ++ MUL = 6; ++ tmp = 2; ++ tmp2 = M + 32; /*32*/ ++ }else if (freq_KHz > cali_freq_thres_div3) { ++ M = M / 3; ++ MUL = 6; ++ tmp = 2; ++ tmp2 = M; /*16*/ ++ }else if (freq_KHz > 304000) { ++ M = M / 4; ++ MUL = 8; ++ tmp = 3; ++ tmp2 = M + 16; /*48*/ ++ }else if (freq_KHz > (cali_freq_thres_div2 / 2)) { ++ M = M / 4; ++ MUL = 8; ++ tmp = 4; ++ tmp2 = M + 16; /*48*/ ++ }else if (freq_KHz > (cali_freq_thres_div3r / 2)) { ++ M = M / 3; ++ MUL = 12; ++ tmp = 4; ++ tmp2 = M + 32; /*32*/ ++ }else if (freq_KHz > (cali_freq_thres_div3 / 2)) { ++ M = M / 3; ++ MUL = 12; ++ tmp = 4; ++ tmp2 = M; /*16*/ ++ }else if (freq_KHz > (cali_freq_thres_div2 / 4)) { ++ M = M / 4; ++ MUL = 16; ++ tmp = 5; ++ tmp2 = M + 16; /*48*/ ++ }else if (freq_KHz > (cali_freq_thres_div3r / 4)) { ++ M = M / 3; ++ MUL = 24; ++ tmp = 5; ++ tmp2 = M + 32; /*32*/ ++ }else if (freq_KHz > (cali_freq_thres_div3 / 4)) { ++ M = M / 3; ++ MUL = 24; ++ tmp = 5; ++ tmp2 = M; /*16*/ ++ }else if (freq_KHz > (cali_freq_thres_div2 / 8)) { ++ M = M / 4; ++ MUL = 32; ++ tmp = 6; ++ tmp2 = M + 16; /*48*/ ++ }else if (freq_KHz > (cali_freq_thres_div3r / 8)) { ++ M = M / 3; ++ MUL = 48; ++ tmp = 6; ++ tmp2 = M + 32; /*32*/ ++ }else if (freq_KHz > (cali_freq_thres_div3 / 8)) { ++ M = M / 3; ++ MUL = 48; ++ tmp = 6; ++ tmp2 = M; /*16*/ ++ }else if (freq_KHz > (cali_freq_thres_div2 / 16)) { ++ M = M / 4; ++ MUL = 64; ++ tmp = 7; ++ tmp2 = M + 16; /*48*/ ++ }else if (freq_KHz > (cali_freq_thres_div3r / 16)) { ++ M = M / 3; ++ MUL = 96; ++ tmp = 7; ++ tmp2 = M + 32; /*32*/ ++ }else if (freq_KHz > (cali_freq_thres_div3 / 16)) { ++ M = M / 3; ++ MUL = 96; ++ tmp = 7; ++ tmp2 = M; /*16*/ ++ }else { /* invalid */ ++ M = M / 4; ++ MUL = 0; ++ tmp = 0; ++ tmp2 = 48; ++ return 1; ++ } ++ ++ if (freq_KHz == 291000) { ++ M = state->tuner_crystal / 1000 / 3; ++ MUL = 12; ++ tmp = 4; ++ tmp2 = M + 32; /*32*/ ++ } ++ /* ++ if (freq_KHz == 578000) { ++ M = state->tuner_crystal / 1000 / 4; ++ MUL = 4; ++ tmp = 2; ++ tmp2 = M + 16; //48 ++ } ++ */ ++ if (freq_KHz == 690000) { ++ M = state->tuner_crystal / 1000 / 3; ++ MUL = 4; ++ tmp = 2; ++ tmp2 = M + 16; /*48*/ ++ } ++ _mt_fe_tn_get_reg(state, 0x33, &buf); ++ buf &= 0xc0; ++ buf += tmp2; ++ _mt_fe_tn_set_reg(state, 0x33, buf); ++ }else { ++ return 1; ++ } ++ ++ _mt_fe_tn_get_reg(state, 0x39, &buf); ++ buf &= 0xf8; ++ buf += tmp; ++ _mt_fe_tn_set_reg(state, 0x39, buf); ++ ++ N = (freq_KHz * MUL * M / crystal_KHz) / 2 * 2 - 256; ++ ++ buf = (N >> 8) & 0xcf; ++ if (state->tuner_mtt == 0xE1) { ++ buf |= 0x30; ++ } ++ _mt_fe_tn_set_reg(state, 0x34, buf); ++ ++ buf = N & 0xff; ++ _mt_fe_tn_set_reg(state, 0x35, buf); ++ ++ F = ((freq_KHz * MUL * M / (crystal_KHz / 1000) / 2) - (freq_KHz * MUL * M / crystal_KHz / 2 * 1000)) * 64 / 1000; ++ ++ buf = F & 0xff; ++ _mt_fe_tn_set_reg(state, 0x36, buf); ++ ++ if (F == 0) { ++ if (state->tuner_mtt == 0xD1) { ++ _mt_fe_tn_set_reg(state, 0x3d, 0xca); ++ }else if (state->tuner_mtt == 0xE1) { ++ _mt_fe_tn_set_reg(state, 0x3d, 0xfe); ++ } else { ++ return 1; ++ } ++ _mt_fe_tn_set_reg(state, 0x3e, 0x9c); ++ _mt_fe_tn_set_reg(state, 0x3f, 0x34); ++ } ++ ++ if (F > 0) { ++ if (state->tuner_mtt == 0xD1) { ++ if ((F == 32) || (F == 16) || (F == 48)) { ++ _mt_fe_tn_set_reg(state, 0x3e, 0xa4); ++ _mt_fe_tn_set_reg(state, 0x3d, 0x4a); ++ _mt_fe_tn_set_reg(state, 0x3f, 0x36); ++ }else { ++ _mt_fe_tn_set_reg(state, 0x3e, 0xa4); ++ _mt_fe_tn_set_reg(state, 0x3d, 0x4a); ++ _mt_fe_tn_set_reg(state, 0x3f, 0x36); ++ } ++ }else if (state->tuner_mtt == 0xE1) { ++ _mt_fe_tn_set_reg(state, 0x3e, 0xa4); ++ _mt_fe_tn_set_reg(state, 0x3d, 0x7e); ++ _mt_fe_tn_set_reg(state, 0x3f, 0x36); ++ _mt_fe_tn_set_reg(state, 0x89, 0x84); ++ _mt_fe_tn_get_reg(state, 0x39, &buf); ++ buf = buf & 0x1f; ++ _mt_fe_tn_set_reg(state, 0x39, buf); ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = buf | 0x02; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ }else { ++ return 1; ++ } ++ } ++ ++ _mt_fe_tn_set_reg(state, 0x41, 0x00); ++ if (state->tuner_mtt == 0xD1) { ++ msleep(5); ++ }else if (state->tuner_mtt == 0xE1) { ++ msleep(2); ++ }else { ++ return 1; ++ } ++ _mt_fe_tn_set_reg(state, 0x41, 0x02); ++ _mt_fe_tn_set_reg(state, 0x30, 0x7f); ++ _mt_fe_tn_set_reg(state, 0x30, 0xff); ++ _mt_fe_tn_set_reg(state, 0x31, 0x80); ++ _mt_fe_tn_set_reg(state, 0x31, 0x00); ++ ++ return 0; ++} ++ ++static int _mt_fe_tn_set_PLL_freq_tc2800(struct m88dc2800_state *state) ++{ ++ u8 buf, buf1; ++ u32 freq_thres_div2_KHz, freq_thres_div3r_KHz, freq_thres_div3_KHz; ++ ++ const u32 freq_KHz = state->tuner_freq; ++ ++ if (state->tuner_mtt == 0xD1) { ++ _mt_fe_tn_set_reg(state, 0x32, 0xe1); ++ _mt_fe_tn_set_reg(state, 0x33, 0xa6); ++ _mt_fe_tn_set_reg(state, 0x37, 0x7f); ++ _mt_fe_tn_set_reg(state, 0x38, 0x20); ++ _mt_fe_tn_set_reg(state, 0x39, 0x18); ++ _mt_fe_tn_set_reg(state, 0x40, 0x40); ++ ++ freq_thres_div2_KHz = 520000; ++ _mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, freq_thres_div2_KHz, 0, 0); ++ ++ msleep(5); ++ _mt_fe_tn_get_reg(state, 0x3a, &buf); ++ buf1 = buf; ++ buf = buf & 0x03; ++ buf1 = buf1 & 0x01; ++ if ((buf1 == 0) || (buf == 3)) { ++ freq_thres_div2_KHz = 420000; ++ _mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, freq_thres_div2_KHz, 0, 0); ++ msleep(5); ++ ++ _mt_fe_tn_get_reg(state, 0x3a, &buf); ++ buf = buf & 0x07; ++ if (buf == 5) { ++ freq_thres_div2_KHz = 520000; ++ _mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, freq_thres_div2_KHz, 0, 0); ++ msleep(5); ++ } ++ } ++ ++ _mt_fe_tn_get_reg(state, 0x38, &buf); ++ _mt_fe_tn_set_reg(state, 0x38, buf); ++ ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = buf | 0x10; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ ++ _mt_fe_tn_set_reg(state, 0x30, 0x7f); ++ _mt_fe_tn_set_reg(state, 0x30, 0xff); ++ ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = buf & 0xdf; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ _mt_fe_tn_set_reg(state, 0x40, 0x0); ++ ++ _mt_fe_tn_set_reg(state, 0x30, 0x7f); ++ _mt_fe_tn_set_reg(state, 0x30, 0xff); ++ _mt_fe_tn_set_reg(state, 0x31, 0x80); ++ _mt_fe_tn_set_reg(state, 0x31, 0x00); ++ msleep(5); ++ ++ _mt_fe_tn_get_reg(state, 0x39, &buf); ++ buf = buf >> 5; ++ if (buf < 5) { ++ _mt_fe_tn_get_reg(state, 0x39, &buf); ++ buf = buf | 0xa0; ++ buf = buf & 0xbf; ++ _mt_fe_tn_set_reg(state, 0x39, buf); ++ ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = buf | 0x02; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ } ++ ++ _mt_fe_tn_get_reg(state, 0x37, &buf); ++ if (buf > 0x70) { ++ buf = 0x7f; ++ _mt_fe_tn_set_reg(state, 0x40, 0x40); ++ } ++ _mt_fe_tn_set_reg(state, 0x37, buf); ++ ++ ++ _mt_fe_tn_get_reg(state, 0x38, &buf); ++ if (buf < 0x0f) { ++ buf = (buf & 0x0f) << 2; ++ buf = buf + 0x0f; ++ _mt_fe_tn_set_reg(state, 0x37, buf); ++ }else if (buf < 0x1f) { ++ buf= buf + 0x0f; ++ _mt_fe_tn_set_reg(state, 0x37, buf); ++ } ++ ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = (buf | 0x20) & 0xef; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ ++ _mt_fe_tn_set_reg(state, 0x41, 0x00); ++ msleep(5); ++ _mt_fe_tn_set_reg(state, 0x41, 0x02); ++ ++ }else if (state->tuner_mtt == 0xE1){ ++ freq_thres_div2_KHz = 580000; ++ freq_thres_div3r_KHz = 500000; ++ freq_thres_div3_KHz = 440000; ++ _mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, freq_thres_div2_KHz, freq_thres_div3r_KHz, freq_thres_div3_KHz); ++ ++ msleep(3); ++ ++ _mt_fe_tn_get_reg(state, 0x38, &buf); ++ _mt_fe_tn_set_reg(state, 0x38, buf); ++ ++ _mt_fe_tn_set_reg(state, 0x30, 0x7f); ++ _mt_fe_tn_set_reg(state, 0x30, 0xff); ++ _mt_fe_tn_set_reg(state, 0x31, 0x80); ++ _mt_fe_tn_set_reg(state, 0x31, 0x00); ++ msleep(3); ++ _mt_fe_tn_get_reg(state, 0x38, &buf); ++ _mt_fe_tn_set_reg(state, 0x38, buf); ++ ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = buf | 0x10; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ ++ _mt_fe_tn_set_reg(state, 0x30, 0x7f); ++ _mt_fe_tn_set_reg(state, 0x30, 0xff); ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = buf & 0xdf; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ _mt_fe_tn_set_reg(state, 0x31, 0x80); ++ _mt_fe_tn_set_reg(state, 0x31, 0x00); ++ msleep(3); ++ ++ _mt_fe_tn_get_reg(state, 0x37, &buf); ++ _mt_fe_tn_set_reg(state, 0x37, buf); ++ /* ++ if ((freq_KHz == 802000) || (freq_KHz == 826000)) { ++ _mt_fe_tn_set_reg(state, 0x37, 0x5e); ++ } ++ */ ++ ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = (buf & 0xef) | 0x30; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ ++ _mt_fe_tn_set_reg(state, 0x41, 0x00); ++ msleep(2); ++ _mt_fe_tn_set_reg(state, 0x41, 0x02); ++ } else { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int _mt_fe_tn_set_BB_tc2800(struct m88dc2800_state *state) ++{ ++ return 0; ++} ++ ++static int _mt_fe_tn_set_appendix_tc2800(struct m88dc2800_state *state) ++{ ++ u8 buf; ++ const u32 freq_KHz = state->tuner_freq; ++ ++ if (state->tuner_mtt == 0xD1) { ++ if ((freq_KHz == 123000) || (freq_KHz == 147000) || (freq_KHz == 171000) ++ || (freq_KHz == 195000)) ++ _mt_fe_tn_set_reg(state, 0x20, 0x1b); ++ ++ if ((freq_KHz == 371000) || (freq_KHz == 419000) || (freq_KHz == 610000) ++ || (freq_KHz == 730000) || (freq_KHz == 754000) || (freq_KHz == 826000)) { ++ _mt_fe_tn_get_reg(state, 0x0d, &buf); ++ _mt_fe_tn_set_reg(state, 0x0d, (u8)(buf + 1)); ++ } ++ ++ if ((freq_KHz == 522000) || (freq_KHz == 578000) || (freq_KHz == 634000) ++ || (freq_KHz == 690000) || (freq_KHz == 834000)) { ++ _mt_fe_tn_get_reg(state, 0x0d, &buf); ++ _mt_fe_tn_set_reg(state, 0x0d, (u8)(buf - 1)); ++ } ++ } else if (state->tuner_mtt == 0xE1) { ++ _mt_fe_tn_set_reg(state, 0x20, 0xfc); ++ ++ if ((freq_KHz == 123000) || (freq_KHz == 147000) || (freq_KHz == 171000) ++ || (freq_KHz == 195000) || (freq_KHz == 219000) || (freq_KHz == 267000) ++ || (freq_KHz == 291000) || (freq_KHz == 339000) || (freq_KHz == 387000) ++ || (freq_KHz == 435000) || (freq_KHz == 482000) || (freq_KHz == 530000) ++ || (freq_KHz == 722000) ++ || ((state->tuner_custom_cfg == 1) && (freq_KHz == 315000))) { ++ _mt_fe_tn_set_reg(state, 0x20, 0x5c); ++ } ++ } ++ return 0; ++} ++ ++static int _mt_fe_tn_set_DAC_tc2800(struct m88dc2800_state *state) ++{ ++ u8 buf, tempnumber; ++ s32 N; ++ s32 f1f2number, f1, f2, delta1, Totalnum1; ++ s32 cntT, cntin, NCOI, z0, z1, z2, tmp; ++ u32 fc, fadc, fsd, f2d; ++ u32 FreqTrue108_Hz; ++ ++ s32 M = state->tuner_crystal / 4000; ++ ++/* const u8 bandwidth = state->tuner_bandwidth; */ ++ const u16 DAC_fre = 108; ++ const u32 crystal_KHz = state->tuner_crystal; ++ const u32 DACFreq_KHz = state->tuner_dac; ++ ++ const u32 freq_KHz = state->tuner_freq; ++ ++ if (state->tuner_mtt == 0xE1) { ++ _mt_fe_tn_get_reg(state, 0x33, &buf); ++ M = buf & 0x0f; ++ if (M == 0) ++ M = 6; ++ } ++ ++ _mt_fe_tn_get_reg(state, 0x34, &buf); ++ N = buf & 0x07; ++ ++ _mt_fe_tn_get_reg(state, 0x35, &buf); ++ N = (N << 8) + buf; ++ ++ ++ buf = ((N + 256) * crystal_KHz / M / DAC_fre + 500) / 1000; ++ ++ if (state->tuner_mtt == 0xE1) { ++ _mt_fe_tn_set_appendix_tc2800(state); ++ ++ if ((freq_KHz == 187000) || (freq_KHz == 195000) || (freq_KHz == 131000) ++ || (freq_KHz == 211000) || (freq_KHz == 219000) || (freq_KHz == 227000) ++ || (freq_KHz == 267000) || (freq_KHz == 299000) || (freq_KHz == 347000) ++ || (freq_KHz == 363000) || (freq_KHz == 395000) || (freq_KHz == 403000) ++ || (freq_KHz == 435000) || (freq_KHz == 482000) || (freq_KHz == 474000) ++ || (freq_KHz == 490000) || (freq_KHz == 610000) || (freq_KHz == 642000) ++ || (freq_KHz == 666000) || (freq_KHz == 722000) || (freq_KHz == 754000) ++ || (((freq_KHz == 379000) || (freq_KHz == 467000) || (freq_KHz == 762000)) ++ && (state->tuner_custom_cfg != 1))) { ++ buf = buf + 1; ++ } ++ ++ if ((freq_KHz == 123000) || (freq_KHz == 139000) || (freq_KHz == 147000) ++ || (freq_KHz == 171000) || (freq_KHz == 179000) || (freq_KHz == 203000) ++ || (freq_KHz == 235000) || (freq_KHz == 251000) || (freq_KHz == 259000) ++ || (freq_KHz == 283000) || (freq_KHz == 331000) || (freq_KHz == 363000) ++ || (freq_KHz == 371000) || (freq_KHz == 387000) || (freq_KHz == 411000) ++ || (freq_KHz == 427000) || (freq_KHz == 443000) || (freq_KHz == 451000) ++ || (freq_KHz == 459000) || (freq_KHz == 506000) || (freq_KHz == 514000) ++ || (freq_KHz == 538000) || (freq_KHz == 546000) || (freq_KHz == 554000) ++ || (freq_KHz == 562000) || (freq_KHz == 570000) || (freq_KHz == 578000) ++ || (freq_KHz == 602000) || (freq_KHz == 626000) || (freq_KHz == 658000) ++ || (freq_KHz == 690000) || (freq_KHz == 714000) || (freq_KHz == 746000) ++ || (freq_KHz == 522000) || (freq_KHz == 826000) || (freq_KHz == 155000) ++ || (freq_KHz == 530000) ++ || (((freq_KHz == 275000) || (freq_KHz == 355000)) && (state->tuner_custom_cfg != 1)) ++ || (((freq_KHz == 467000) || (freq_KHz == 762000) || (freq_KHz == 778000) ++ || (freq_KHz == 818000)) && (state->tuner_custom_cfg == 1))) { ++ buf = buf - 1; ++ } ++ } ++ ++ _mt_fe_tn_set_reg(state, 0x0e, buf); ++ _mt_fe_tn_set_reg(state, 0x0d, buf); ++ ++ f1f2number = (((DACFreq_KHz * M * buf) / crystal_KHz) << 16) / (N + 256) ++ + (((DACFreq_KHz * M * buf) % crystal_KHz) << 16) / ((N + 256) * crystal_KHz); ++ ++ ++ _mt_fe_tn_set_reg(state, 0xf1, (u8)((f1f2number & 0xff00) >> 8)); ++ _mt_fe_tn_set_reg(state, 0xf2, (u8)(f1f2number & 0x00ff)); ++ ++ FreqTrue108_Hz = (N + 256) * crystal_KHz / (M * buf) * 1000 + (((N + 256) * crystal_KHz) % (M * buf)) * 1000 / (M * buf); ++ ++ f1 = 4096; ++ fc = FreqTrue108_Hz; ++ fadc = fc / 4; ++ fsd = 27000000; ++ f2d = state->tuner_bandwidth * 1000 / 2 -150; ++ f2 = (fsd / 250) * f2d / ((fc + 500) / 1000); ++ delta1 = ((f1 - f2) << 15) / f2; ++ ++ Totalnum1 = ((f1 - f2) << 15) - delta1 * f2; ++ ++ cntT = f2; ++ cntin = Totalnum1; ++ NCOI = delta1; ++ ++ z0 = cntin; ++ z1 = cntT; ++ z2 = NCOI; ++ ++ tempnumber = (z0 & 0xff00) >> 8; ++ _mt_fe_tn_set_reg(state, 0xc9, (u8)(tempnumber & 0x0f)); ++ tempnumber = (z0 & 0xff); ++ _mt_fe_tn_set_reg(state, 0xca, tempnumber); ++ ++ tempnumber = (z1 & 0xff00) >> 8; ++ _mt_fe_tn_set_reg(state, 0xcb, tempnumber); ++ tempnumber = (z1 & 0xff); ++ _mt_fe_tn_set_reg(state, 0xcc, tempnumber); ++ ++ tempnumber = (z2 & 0xff00) >> 8; ++ _mt_fe_tn_set_reg(state, 0xcd, tempnumber); ++ tempnumber = (z2 & 0xff); ++ _mt_fe_tn_set_reg(state, 0xce, tempnumber); ++ ++ tmp = f1; ++ f1 = f2; ++ f2 = tmp / 2; ++ delta1 = ((f1 - f2) << 15) / f2; ++ Totalnum1 = ((f1 - f2) << 15) - delta1 * f2; ++ NCOI = (f1 << 15) / f2 - (1 << 15); ++ cntT = f2; ++ cntin = Totalnum1; ++ z0 = cntin; ++ z1 = cntT; ++ z2 = NCOI; ++ ++ tempnumber = (z0 & 0xff00) >> 8; ++ _mt_fe_tn_set_reg(state, 0xd9, (u8)(tempnumber & 0x0f)); ++ tempnumber = (z0 & 0xff); ++ _mt_fe_tn_set_reg(state, 0xda, tempnumber); ++ ++ tempnumber = (z1 & 0xff00) >> 8; ++ _mt_fe_tn_set_reg(state, 0xdb, tempnumber); ++ tempnumber = (z1 & 0xff); ++ _mt_fe_tn_set_reg(state, 0xdc, tempnumber); ++ ++ tempnumber = (z2 & 0xff00) >> 8; ++ _mt_fe_tn_set_reg(state, 0xdd, tempnumber); ++ tempnumber = (z2 & 0xff); ++ _mt_fe_tn_set_reg(state, 0xde, tempnumber); ++ ++ return 0; ++} ++ ++static int _mt_fe_tn_preset_tc2800(struct m88dc2800_state *state) ++{ ++ if (state->tuner_mtt == 0xD1) { ++ _mt_fe_tn_set_reg(state, 0x19, 0x4a); ++ _mt_fe_tn_set_reg(state, 0x1b, 0x4b); ++ ++ _mt_fe_tn_set_reg(state, 0x04, 0x04); ++ _mt_fe_tn_set_reg(state, 0x17, 0x0d); ++ _mt_fe_tn_set_reg(state, 0x62, 0x6c); ++ _mt_fe_tn_set_reg(state, 0x63, 0xf4); ++ _mt_fe_tn_set_reg(state, 0x1f, 0x0e); ++ _mt_fe_tn_set_reg(state, 0x6b, 0xf4); ++ _mt_fe_tn_set_reg(state, 0x14, 0x01); ++ _mt_fe_tn_set_reg(state, 0x5a, 0x75); ++ _mt_fe_tn_set_reg(state, 0x66, 0x74); ++ _mt_fe_tn_set_reg(state, 0x72, 0xe0); ++ _mt_fe_tn_set_reg(state, 0x70, 0x07); ++ _mt_fe_tn_set_reg(state, 0x15, 0x7b); ++ _mt_fe_tn_set_reg(state, 0x55, 0x71); ++ ++ _mt_fe_tn_set_reg(state, 0x75, 0x55); ++ _mt_fe_tn_set_reg(state, 0x76, 0xac); ++ _mt_fe_tn_set_reg(state, 0x77, 0x6c); ++ _mt_fe_tn_set_reg(state, 0x78, 0x8b); ++ _mt_fe_tn_set_reg(state, 0x79, 0x42); ++ _mt_fe_tn_set_reg(state, 0x7a, 0xd2); ++ ++ _mt_fe_tn_set_reg(state, 0x81, 0x01); ++ _mt_fe_tn_set_reg(state, 0x82, 0x00); ++ _mt_fe_tn_set_reg(state, 0x82, 0x02); ++ _mt_fe_tn_set_reg(state, 0x82, 0x04); ++ _mt_fe_tn_set_reg(state, 0x82, 0x06); ++ _mt_fe_tn_set_reg(state, 0x82, 0x08); ++ _mt_fe_tn_set_reg(state, 0x82, 0x09); ++ _mt_fe_tn_set_reg(state, 0x82, 0x29); ++ _mt_fe_tn_set_reg(state, 0x82, 0x49); ++ _mt_fe_tn_set_reg(state, 0x82, 0x58); ++ _mt_fe_tn_set_reg(state, 0x82, 0x59); ++ _mt_fe_tn_set_reg(state, 0x82, 0x98); ++ _mt_fe_tn_set_reg(state, 0x82, 0x99); ++ ++ ++ _mt_fe_tn_set_reg(state, 0x10, 0x05); ++ _mt_fe_tn_set_reg(state, 0x10, 0x0d); ++ _mt_fe_tn_set_reg(state, 0x11, 0x95); ++ _mt_fe_tn_set_reg(state, 0x11, 0x9d); ++ ++ ++ if (state->tuner_loopthrough != 0) { ++ _mt_fe_tn_set_reg(state, 0x67, 0x25); ++ } else { ++ _mt_fe_tn_set_reg(state, 0x67, 0x05); ++ } ++ } else if (state->tuner_mtt == 0xE1) { ++ _mt_fe_tn_set_reg(state, 0x1b, 0x47); ++ if(state->tuner_mode == 0) // DVB-C ++ { ++ _mt_fe_tn_set_reg(state, 0x66, 0x74); ++ _mt_fe_tn_set_reg(state, 0x62, 0x2c); ++ _mt_fe_tn_set_reg(state, 0x63, 0x54); ++ _mt_fe_tn_set_reg(state, 0x68, 0x0b); ++ _mt_fe_tn_set_reg(state, 0x14, 0x00); ++ } ++ else // CTTB ++ { ++ _mt_fe_tn_set_reg(state, 0x66, 0x74); ++ _mt_fe_tn_set_reg(state, 0x62, 0x0c); ++ _mt_fe_tn_set_reg(state, 0x63, 0x54); ++ _mt_fe_tn_set_reg(state, 0x68, 0x0b); ++ _mt_fe_tn_set_reg(state, 0x14, 0x05); ++ } ++ _mt_fe_tn_set_reg(state, 0x6f, 0x00); ++ _mt_fe_tn_set_reg(state, 0x84, 0x04); ++ _mt_fe_tn_set_reg(state, 0x5e, 0xbe); ++ _mt_fe_tn_set_reg(state, 0x87, 0x07); ++ _mt_fe_tn_set_reg(state, 0x8a, 0x1f); ++ _mt_fe_tn_set_reg(state, 0x8b, 0x1f); ++ _mt_fe_tn_set_reg(state, 0x88, 0x30); ++ _mt_fe_tn_set_reg(state, 0x58, 0x34); ++ _mt_fe_tn_set_reg(state, 0x61, 0x8c); ++ _mt_fe_tn_set_reg(state, 0x6a, 0x42); ++ } ++ return 0; ++} ++ ++static int mt_fe_tn_wakeup_tc2800(struct m88dc2800_state *state) ++{ ++ _mt_fe_tn_set_reg(state, 0x16, 0xb1); ++ _mt_fe_tn_set_reg(state, 0x09, 0x7d); ++ return 0; ++} ++ ++ ++static int mt_fe_tn_sleep_tc2800(struct m88dc2800_state *state) ++{ ++ _mt_fe_tn_set_reg(state, 0x16, 0xb0); ++ _mt_fe_tn_set_reg(state, 0x09, 0x6d); ++ return 0; ++} ++ ++static int mt_fe_tn_init_tc2800(struct m88dc2800_state *state) ++{ ++ if (state->tuner_init_OK != 1) { ++ state->tuner_dev_addr = 0x61; /* TUNER_I2C_ADDR_TC2800 */ ++ state->tuner_freq = 650000; ++ state->tuner_qam = 0; ++ state->tuner_mode = 0; // 0: DVB-C, 1: CTTB ++ ++ state->tuner_bandwidth = 8; ++ state->tuner_loopthrough = 0; ++ state->tuner_crystal = 24000; ++ state->tuner_dac = 7200; ++ state->tuner_mtt = 0x00; ++ state->tuner_custom_cfg = 0; ++ state->tuner_version = 30022; /* Driver version number */ ++ state->tuner_time = 12092611; ++ state->tuner_init_OK = 1; ++ } ++ ++ _mt_fe_tn_set_reg(state, 0x2b, 0x46); ++ _mt_fe_tn_set_reg(state, 0x2c, 0x75); ++ ++ if (state->tuner_mtt == 0x00) { ++ u8 tmp = 0; ++ _mt_fe_tn_get_reg(state, 0x01, &tmp); ++ printk("m88dc2800: tuner id = 0x%02x ", tmp); ++ switch(tmp) { ++ case 0x0d: ++ state->tuner_mtt = 0xD1; ++ break; ++ case 0x8e: ++ default: ++ state->tuner_mtt = 0xE1; ++ break; ++ } ++ } ++ return 0; ++} ++ ++static int mt_fe_tn_set_freq_tc2800(struct m88dc2800_state *state, u32 freq_KHz) ++{ ++ u8 buf; ++ u8 buf1; ++ ++ mt_fe_tn_init_tc2800(state); ++ ++ state->tuner_freq = freq_KHz; ++ ++ if (freq_KHz > 500000) ++ _mt_fe_tn_set_reg(state, 0x21, 0xb9); ++ else ++ _mt_fe_tn_set_reg(state, 0x21, 0x99); ++ ++ mt_fe_tn_wakeup_tc2800(state); ++ ++ _mt_fe_tn_set_reg(state, 0x05, 0x7f); ++ _mt_fe_tn_set_reg(state, 0x06, 0xf8); ++ ++ _mt_fe_tn_set_RF_front_tc2800(state); ++ _mt_fe_tn_set_PLL_freq_tc2800(state); ++ _mt_fe_tn_set_DAC_tc2800(state); ++ _mt_fe_tn_set_BB_tc2800(state); ++ _mt_fe_tn_preset_tc2800(state); ++ ++ _mt_fe_tn_set_reg(state, 0x05, 0x00); ++ _mt_fe_tn_set_reg(state, 0x06, 0x00); ++ ++ if (state->tuner_mtt == 0xD1) { ++ _mt_fe_tn_set_reg(state, 0x00, 0x01); ++ _mt_fe_tn_set_reg(state, 0x00, 0x00); ++ ++ msleep(5); ++ _mt_fe_tn_set_reg(state, 0x41, 0x00); ++ msleep(5); ++ _mt_fe_tn_set_reg(state, 0x41, 0x02); ++ ++ _mt_fe_tn_get_reg(state, 0x69, &buf1); ++ buf1 = buf1 & 0x0f; ++ ++ _mt_fe_tn_get_reg(state, 0x61, &buf); ++ buf = buf & 0x0f; ++ if (buf == 0x0c) ++ { ++ _mt_fe_tn_set_reg(state, 0x6a, 0x59); ++ } ++ ++ if(buf1 > 0x02) ++ { ++ if (freq_KHz > 600000) ++ _mt_fe_tn_set_reg(state, 0x66, 0x44); ++ else if (freq_KHz > 500000) ++ _mt_fe_tn_set_reg(state, 0x66, 0x64); ++ else ++ _mt_fe_tn_set_reg(state, 0x66, 0x74); ++ } ++ ++ if (buf1 < 0x03) ++ { ++ if (freq_KHz > 800000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x64); ++ else if (freq_KHz > 600000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x54); ++ else if (freq_KHz > 500000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x54); ++ else if (freq_KHz > 300000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x43); ++ else if (freq_KHz > 220000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x54); ++ else if (freq_KHz > 110000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x14); ++ else ++ _mt_fe_tn_set_reg(state, 0x87, 0x54); ++ ++ msleep(5); ++ } ++ else if (buf < 0x0c) ++ { ++ if (freq_KHz > 800000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x14); ++ else if (freq_KHz >600000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x14); ++ else if (freq_KHz > 500000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x34); ++ else if (freq_KHz > 300000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x43); ++ else if (freq_KHz > 220000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x54); ++ else if (freq_KHz > 110000) ++ _mt_fe_tn_set_reg(state, 0x87, 0x14); ++ else ++ _mt_fe_tn_set_reg(state, 0x87, 0x54); ++ ++ msleep(5); ++ } ++ } else if ((state->tuner_mtt == 0xE1)) { ++ _mt_fe_tn_set_reg(state, 0x00, 0x01); ++ _mt_fe_tn_set_reg(state, 0x00, 0x00); ++ ++ msleep(20); ++ ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = (buf & 0xef) | 0x28; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ ++ msleep(50); ++ _mt_fe_tn_get_reg(state, 0x38, &buf); ++ _mt_fe_tn_set_reg(state, 0x38, buf); ++ _mt_fe_tn_get_reg(state, 0x32, &buf); ++ buf = (buf & 0xf7)| 0x10 ; ++ _mt_fe_tn_set_reg(state, 0x32, buf); ++ ++ msleep(10); ++ ++ _mt_fe_tn_get_reg(state, 0x69, &buf); ++ buf = buf & 0x03; ++ _mt_fe_tn_set_reg(state, 0x2a, buf); ++ ++ if(buf > 0) ++ { ++ msleep(20); ++ _mt_fe_tn_get_reg(state, 0x84, &buf); ++ buf = buf & 0x1f; ++ _mt_fe_tn_set_reg(state, 0x68, 0x0a); ++ _mt_fe_tn_get_reg(state, 0x88, &buf1); ++ buf1 = buf1 & 0x1f; ++ if(buf <= buf1) ++ _mt_fe_tn_set_reg(state, 0x66, 0x44); ++ else ++ _mt_fe_tn_set_reg(state, 0x66, 0x74); ++ } ++ else ++ { ++ if (freq_KHz <= 600000) ++ { ++ _mt_fe_tn_set_reg(state, 0x68, 0x0c); ++ } ++ else ++ { ++ _mt_fe_tn_set_reg(state, 0x68, 0x0e); ++ } ++ _mt_fe_tn_set_reg(state, 0x30, 0xfb); ++ _mt_fe_tn_set_reg(state, 0x30, 0xff); ++ _mt_fe_tn_set_reg(state, 0x31, 0x04); ++ _mt_fe_tn_set_reg(state, 0x31, 0x00); ++ } ++ if(state->tuner_loopthrough != 0) { ++ _mt_fe_tn_get_reg(state, 0x28, &buf); ++ if (buf == 0) { ++ _mt_fe_tn_set_reg(state, 0x28, 0xff); ++ _mt_fe_tn_get_reg(state, 0x61, &buf); ++ buf = buf & 0x0f; ++ if(buf > 9) ++ _mt_fe_tn_set_reg(state, 0x67, 0x74); ++ else if (buf >6) ++ _mt_fe_tn_set_reg(state, 0x67, 0x64); ++ else if (buf >3) ++ _mt_fe_tn_set_reg(state, 0x67, 0x54); ++ else ++ _mt_fe_tn_set_reg(state, 0x67, 0x44); ++ } ++ } else { ++ _mt_fe_tn_set_reg(state, 0x67, 0x34); ++ } ++ } else { ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++static int mt_fe_tn_set_BB_filter_band_tc2800(struct m88dc2800_state *state, u8 bandwidth) ++{ ++ u8 buf, tmp; ++ ++ _mt_fe_tn_get_reg(state, 0x53, &tmp); ++ ++ if (bandwidth == 6) ++ buf = 0x01 << 1; ++ else if (bandwidth == 7) ++ buf = 0x02 << 1; ++ else if (bandwidth == 8) ++ buf = 0x04 << 1; ++ else ++ buf = 0x04 << 1; ++ ++ tmp &= 0xf1; ++ tmp |= buf; ++ _mt_fe_tn_set_reg(state, 0x53, tmp); ++ state->tuner_bandwidth = bandwidth; ++ return 0; ++} ++*/ ++ ++/*static s64 mt_fe_tn_get_signal_strength_tc2800(struct m88dc2800_state *state)*/ ++static s32 mt_fe_tn_get_signal_strength_tc2800(struct m88dc2800_state *state) ++{ ++ /*s64 level = -107;*/ ++ s32 level = -107; ++ s32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; ++ s32 val1, val2, val; ++ s32 result2, result3, result4, result5, result6; ++ s32 append; ++ u8 tmp; ++ s32 freq_KHz = (s32)state->tuner_freq; ++ ++ if (state->tuner_mtt == 0xD1) { ++ _mt_fe_tn_get_reg(state, 0x61, &tmp); ++ tmp1 = tmp & 0x0f; ++ ++ _mt_fe_tn_get_reg(state, 0x69, &tmp); ++ tmp2 = tmp & 0x0f; ++ ++ _mt_fe_tn_get_reg(state, 0x73, &tmp); ++ tmp3 = tmp & 0x07; ++ ++ _mt_fe_tn_get_reg(state, 0x7c, &tmp); ++ tmp4 = (tmp >> 4) & 0x0f; ++ ++ _mt_fe_tn_get_reg(state, 0x7b, &tmp); ++ tmp5 = tmp & 0x0f; ++ ++ _mt_fe_tn_get_reg(state, 0x7f, &tmp); ++ tmp6 = (tmp >> 5) & 0x01; ++ ++ if (tmp1 > 6) { ++ val1 = 0; ++ if (freq_KHz <= 200000) { ++ val2 = (tmp1 - 6) * 267; ++ } else if (freq_KHz <= 600000) { ++ val2 = (tmp1 - 6) * 280; ++ } else { ++ val2 = (tmp1 - 6) * 290; ++ } ++ val = val1 + val2; ++ } else { ++ if (tmp1 == 0) { ++ val1 = -550; ++ } else { ++ val1 = 0; ++ } ++ if ((tmp1 < 4) && (freq_KHz >= 506000)) { ++ val1 = -850; ++ } ++ val2 = 0; ++ val = val1 + val2; ++ } ++ ++ if (freq_KHz <= 95000) { ++ result2 = tmp2 * 289; ++ } else if (freq_KHz <= 155000) { ++ result2 = tmp2 * 278; ++ } else if (freq_KHz <= 245000) { ++ result2 = tmp2 * 267; ++ } else if (freq_KHz <= 305000) { ++ result2 = tmp2 * 256; ++ } else if (freq_KHz <= 335000) { ++ result2 = tmp2 * 244; ++ } else if (freq_KHz <= 425000) { ++ result2 = tmp2 * 233; ++ } else if (freq_KHz <= 575000) { ++ result2 = tmp2 * 222; ++ } else if (freq_KHz <= 665000) { ++ result2 = tmp2 * 211; ++ } else { ++ result2 = tmp2 * 200; ++ } ++ result3 = (6 - tmp3) * 100; ++ result4 = 300 * tmp4; ++ result5 = 50 * tmp5; ++ result6 = 300 * tmp6; ++ if (freq_KHz < 105000) { ++ append = -450; ++ } else if (freq_KHz <= 227000) { ++ append = -4 * (freq_KHz / 1000 - 100) + 150; ++ } else if (freq_KHz <= 305000) { ++ append = -4 * (freq_KHz / 1000 - 100); ++ } else if (freq_KHz <= 419000) { ++ append = 500 - 40 * (freq_KHz / 1000 - 300) / 17 + 130; ++ } else if (freq_KHz <= 640000) { ++ append = 500 - 40 * (freq_KHz / 1000 - 300) / 17; ++ } else { ++ append = -500; ++ } ++ level = append - (val + result2 + result3 + result4 + result5 + result6); ++ level /= 100; ++ } else if (state->tuner_mtt == 0xE1) { ++ _mt_fe_tn_get_reg(state, 0x61, &tmp); ++ tmp1 = tmp & 0x0f; ++ ++ _mt_fe_tn_get_reg(state, 0x84, &tmp); ++ tmp2 = tmp & 0x1f; ++ ++ _mt_fe_tn_get_reg(state, 0x69, &tmp); ++ tmp3 = tmp & 0x03; ++ ++ _mt_fe_tn_get_reg(state, 0x73, &tmp); ++ tmp4 = tmp & 0x0f; ++ ++ _mt_fe_tn_get_reg(state, 0x7c, &tmp); ++ tmp5 = (tmp >> 4) & 0x0f; ++ ++ _mt_fe_tn_get_reg(state, 0x7b, &tmp); ++ tmp6 = tmp & 0x0f; ++ ++ if (freq_KHz < 151000) { ++ result2 = (1150 - freq_KHz / 100) * 163 / 33 + 4230; ++ result3 = (1150 - freq_KHz / 100) * 115 / 33 + 1850; ++ result4 = -3676 * (freq_KHz / 1000) / 100 + 6115; ++ } else if (freq_KHz < 257000) { ++ result2 = (1540 - freq_KHz / 100) * 11 / 4 + 3870; ++ result3 = (1540 - freq_KHz / 100) * 205 / 96 + 2100; ++ result4 = -21 * freq_KHz / 1000 + 5084; ++ } else if (freq_KHz < 305000) { ++ result2 = (2620 - freq_KHz / 100) * 5 / 3 + 2770; ++ result3 = (2620 - freq_KHz / 100) * 10 / 7 + 1700; ++ result4 = 650; ++ } else if (freq_KHz < 449000) { ++ result2 = (307 - freq_KHz / 1000) * 82 / 27 + 11270; ++ result3 = (3100 - freq_KHz / 100) * 5 / 3 + 10000; ++ result4 = 134 * freq_KHz / 10000 + 11875; ++ } else { ++ result2 = (307 - freq_KHz / 1000) * 82 / 27 + 11270; ++ result3 = 8400; ++ result4 = 5300; ++ } ++ ++ if (tmp1 > 6) { ++ val1 = result2; ++ val2 = 2900; ++ val = 500; ++ } else if (tmp1 > 0) { ++ val1 = result3; ++ val2 = 2700; ++ val = 500; ++ } else { ++ val1 = result4; ++ val2 = 2700; ++ val = 400; ++ } ++ level = val1 - (val2 * tmp1 + 500 * tmp2 + 3000 * tmp3 - 500 * tmp4 + 3000 * tmp5 + val * tmp6) - 1000; ++ level /= 1000; ++ } ++ return level; ++} ++ ++/* m88dc2800 operation functions */ ++u8 M88DC2000GetLock(struct m88dc2800_state *state) ++{ ++ u8 u8ret = 0; ++ ++ if (ReadReg(state, 0x80) < 0x06) { ++ if ((ReadReg(state, 0xdf)&0x80)==0x80 ++ && (ReadReg(state, 0x91)&0x23)==0x03 ++ && (ReadReg(state, 0x43)&0x08)==0x08) ++ u8ret = 1; ++ else ++ u8ret = 0; ++ } else { ++ if ((ReadReg(state, 0x85)&0x08)==0x08) ++ u8ret = 1; ++ else ++ u8ret = 0; ++ } ++ printk("%s, lock=%d\n", __func__,u8ret); ++ return u8ret; ++} ++ ++static int M88DC2000SetTsType(struct m88dc2800_state *state, u8 type) ++{ ++ u8 regC2H; ++ ++ if (type == 3) { ++ WriteReg(state, 0x84, 0x6A); ++ WriteReg(state, 0xC0, 0x43); ++ WriteReg(state, 0xE2, 0x06); ++ regC2H = ReadReg(state, 0xC2); ++ regC2H &= 0xC0; ++ regC2H |= 0x1B; ++ WriteReg(state, 0xC2, regC2H); ++ WriteReg(state, 0xC1, 0x60); /* common interface */ ++ } else if (type == 1) { ++ WriteReg(state, 0x84, 0x6A); ++ WriteReg(state, 0xC0, 0x47); /* serial format */ ++ WriteReg(state, 0xE2, 0x02); ++ regC2H = ReadReg(state, 0xC2); ++ regC2H &= 0xC7; ++ WriteReg(state, 0xC2, regC2H); ++ WriteReg(state, 0xC1, 0x00); ++ } else { ++ WriteReg(state, 0x84, 0x6C); ++ WriteReg(state, 0xC0, 0x43); /* parallel format */ ++ WriteReg(state, 0xE2, 0x06); ++ regC2H = ReadReg(state, 0xC2); ++ regC2H &= 0xC7; ++ WriteReg(state, 0xC2, regC2H); ++ WriteReg(state, 0xC1, 0x00); ++ } ++ return 0; ++} ++ ++static int M88DC2000RegInitial_TC2800(struct m88dc2800_state *state) ++{ ++ u8 RegE3H, RegE4H; ++ ++ WriteReg(state, 0x00, 0x48); ++ WriteReg(state, 0x01, 0x09); ++ WriteReg(state, 0xFB, 0x0A); ++ WriteReg(state, 0xFC, 0x0B); ++ WriteReg(state, 0x02, 0x0B); ++ WriteReg(state, 0x03, 0x18); ++ WriteReg(state, 0x05, 0x0D); ++ WriteReg(state, 0x36, 0x80); ++ WriteReg(state, 0x43, 0x40); ++ WriteReg(state, 0x55, 0x7A); ++ WriteReg(state, 0x56, 0xD9); ++ WriteReg(state, 0x57, 0xDF); ++ WriteReg(state, 0x58, 0x39); ++ WriteReg(state, 0x5A, 0x00); ++ WriteReg(state, 0x5C, 0x71); ++ WriteReg(state, 0x5D, 0x23); ++ WriteReg(state, 0x86, 0x40); ++ WriteReg(state, 0xF9, 0x08); ++ WriteReg(state, 0x61, 0x40); ++ WriteReg(state, 0x62, 0x0A); ++ WriteReg(state, 0x90, 0x06); ++ WriteReg(state, 0xDE, 0x00); ++ WriteReg(state, 0xA0, 0x03); ++ WriteReg(state, 0xDF, 0x81); ++ WriteReg(state, 0xFA, 0x40); ++ WriteReg(state, 0x37, 0x10); ++ WriteReg(state, 0xF0, 0x40); ++ WriteReg(state, 0xF2, 0x9C); ++ WriteReg(state, 0xF3, 0x40); ++ ++ RegE3H = ReadReg(state, 0xE3); ++ RegE4H = ReadReg(state, 0xE4); ++ if (((RegE3H & 0xC0) == 0x00) && ((RegE4H & 0xC0) == 0x00)) { ++ WriteReg(state, 0x30, 0xFF); ++ WriteReg(state, 0x31, 0x00); ++ WriteReg(state, 0x32, 0x00); ++ WriteReg(state, 0x33, 0x00); ++ WriteReg(state, 0x35, 0x32); ++ WriteReg(state, 0x40, 0x00); ++ WriteReg(state, 0x41, 0x10); ++ WriteReg(state, 0xF1, 0x02); ++ WriteReg(state, 0xF4, 0x04); ++ WriteReg(state, 0xF5, 0x00); ++ WriteReg(state, 0x42, 0x14); ++ WriteReg(state, 0xE1, 0x25); ++ } else if (((RegE3H & 0xC0) == 0x80) && ((RegE4H & 0xC0) == 0x40)) { ++ WriteReg(state, 0x30, 0xFF); ++ WriteReg(state, 0x31, 0x00); ++ WriteReg(state, 0x32, 0x00); ++ WriteReg(state, 0x33, 0x00); ++ WriteReg(state, 0x35, 0x32); ++ WriteReg(state, 0x39, 0x00); ++ WriteReg(state, 0x3A, 0x00); ++ WriteReg(state, 0x40, 0x00); ++ WriteReg(state, 0x41, 0x10); ++ WriteReg(state, 0xF1, 0x00); ++ WriteReg(state, 0xF4, 0x00); ++ WriteReg(state, 0xF5, 0x40); ++ WriteReg(state, 0x42, 0x14); ++ WriteReg(state, 0xE1, 0x25); ++ } else if ((RegE3H == 0x80 || RegE3H == 0x81) && (RegE4H == 0x80 || RegE4H == 0x81)) { ++ WriteReg(state, 0x30, 0xFF); ++ WriteReg(state, 0x31, 0x00); ++ WriteReg(state, 0x32, 0x00); ++ WriteReg(state, 0x33, 0x00); ++ WriteReg(state, 0x35, 0x32); ++ WriteReg(state, 0x39, 0x00); ++ WriteReg(state, 0x3A, 0x00); ++ WriteReg(state, 0xF1, 0x00); ++ WriteReg(state, 0xF4, 0x00); ++ WriteReg(state, 0xF5, 0x40); ++ WriteReg(state, 0x42, 0x24); ++ WriteReg(state, 0xE1, 0x25); ++ ++ WriteReg(state, 0x92, 0x7F); ++ WriteReg(state, 0x93, 0x91); ++ WriteReg(state, 0x95, 0x00); ++ WriteReg(state, 0x2B, 0x33); ++ WriteReg(state, 0x2A, 0x2A); ++ WriteReg(state, 0x2E, 0x80); ++ WriteReg(state, 0x25, 0x25); ++ WriteReg(state, 0x2D, 0xFF); ++ WriteReg(state, 0x26, 0xFF); ++ WriteReg(state, 0x27, 0x00); ++ WriteReg(state, 0x24, 0x25); ++ WriteReg(state, 0xA4, 0xFF); ++ WriteReg(state, 0xA3, 0x0D); ++ } else { ++ WriteReg(state, 0x30, 0xFF); ++ WriteReg(state, 0x31, 0x00); ++ WriteReg(state, 0x32, 0x00); ++ WriteReg(state, 0x33, 0x00); ++ WriteReg(state, 0x35, 0x32); ++ WriteReg(state, 0x39, 0x00); ++ WriteReg(state, 0x3A, 0x00); ++ WriteReg(state, 0xF1, 0x00); ++ WriteReg(state, 0xF4, 0x00); ++ WriteReg(state, 0xF5, 0x40); ++ WriteReg(state, 0x42, 0x24); ++ WriteReg(state, 0xE1, 0x27); ++ ++ WriteReg(state, 0x92, 0x7F); ++ WriteReg(state, 0x93, 0x91); ++ WriteReg(state, 0x95, 0x00); ++ WriteReg(state, 0x2B, 0x33); ++ WriteReg(state, 0x2A, 0x2A); ++ WriteReg(state, 0x2E, 0x80); ++ WriteReg(state, 0x25, 0x25); ++ WriteReg(state, 0x2D, 0xFF); ++ WriteReg(state, 0x26, 0xFF); ++ WriteReg(state, 0x27, 0x00); ++ WriteReg(state, 0x24, 0x25); ++ WriteReg(state, 0xA4, 0xFF); ++ WriteReg(state, 0xA3, 0x10); ++ } ++ ++ WriteReg(state, 0xF6, 0x4E); ++ WriteReg(state, 0xF7, 0x20); ++ WriteReg(state, 0x89, 0x02); ++ WriteReg(state, 0x14, 0x08); ++ WriteReg(state, 0x6F, 0x0D); ++ WriteReg(state, 0x10, 0xFF); ++ WriteReg(state, 0x11, 0x00); ++ WriteReg(state, 0x12, 0x30); ++ WriteReg(state, 0x13, 0x23); ++ WriteReg(state, 0x60, 0x00); ++ WriteReg(state, 0x69, 0x00); ++ WriteReg(state, 0x6A, 0x03); ++ WriteReg(state, 0xE0, 0x75); ++ WriteReg(state, 0x8D, 0x29); ++ WriteReg(state, 0x4E, 0xD8); ++ WriteReg(state, 0x88, 0x80); ++ WriteReg(state, 0x52, 0x79); ++ WriteReg(state, 0x53, 0x03); ++ WriteReg(state, 0x59, 0x30); ++ WriteReg(state, 0x5E, 0x02); ++ WriteReg(state, 0x5F, 0x0F); ++ WriteReg(state, 0x71, 0x03); ++ WriteReg(state, 0x72, 0x12); ++ WriteReg(state, 0x73, 0x12); ++ ++ return 0; ++} ++ ++static int M88DC2000AutoTSClock_P(struct m88dc2800_state *state, u32 sym, u16 qam) ++{ ++ u32 dataRate; ++ u8 clk_div, value; ++ printk("m88dc2800: M88DC2000AutoTSClock_P, symrate=%d qam=%d\n",sym,qam); ++ switch(qam) ++ { ++ case 16: ++ dataRate = 4; ++ break; ++ case 32: ++ dataRate = 5; ++ break; ++ case 128: ++ dataRate = 7; ++ break; ++ case 256: ++ dataRate = 8; ++ break; ++ case 64: ++ default: ++ dataRate = 6; ++ break; ++ } ++ dataRate *= sym * 105; ++ dataRate /= 800; ++ ++ if(dataRate <= 4115) ++ clk_div = 0x05; ++ else if(dataRate <= 4800) ++ clk_div = 0x04; ++ else if(dataRate <= 5760) ++ clk_div = 0x03; ++ else if(dataRate <= 7200) ++ clk_div = 0x02; ++ else if(dataRate <= 9600) ++ clk_div = 0x01; ++ else ++ clk_div = 0x00; ++ ++ value = ReadReg(state, 0xC2); ++ value &= 0xc0; ++ value |= clk_div; ++ WriteReg(state, 0xC2, value); ++ return 0; ++} ++ ++static int M88DC2000AutoTSClock_C(struct m88dc2800_state *state, u32 sym, u16 qam) ++{ ++ u32 dataRate; ++ u8 clk_div, value; ++ printk("m88dc2800: M88DC2000AutoTSClock_C, symrate=%d qam=%d\n",sym,qam); ++ switch(qam) ++ { ++ case 16: ++ dataRate = 4; ++ break; ++ case 32: ++ dataRate = 5; ++ break; ++ case 128: ++ dataRate = 7; ++ break; ++ case 256: ++ dataRate = 8; ++ break; ++ case 64: ++ default: ++ dataRate = 6; ++ break; ++ } ++ dataRate *= sym * 105; ++ dataRate /= 800; ++ ++ if(dataRate <= 4115) ++ clk_div = 0x3F; ++ else if(dataRate <= 4800) ++ clk_div = 0x36; ++ else if(dataRate <= 5760) ++ clk_div = 0x2D; ++ else if(dataRate <= 7200) ++ clk_div = 0x24; ++ else if(dataRate <= 9600) ++ clk_div = 0x1B; ++ else ++ clk_div = 0x12; ++ ++ value = ReadReg(state, 0xC2); ++ value &= 0xc0; ++ value |= clk_div; ++ WriteReg(state, 0xC2, value); ++ return 0; ++} ++ ++static int M88DC2000SetTxMode(struct m88dc2800_state *state, u8 inverted, u8 j83) ++{ ++ u8 value = 0; ++ if (inverted) ++ value |= 0x08; /* spectrum inverted */ ++ if (j83) ++ value |= 0x01; /* J83C */ ++ WriteReg(state, 0x83, value); ++ return 0; ++} ++ ++static int M88DC2000SoftReset(struct m88dc2800_state *state) ++{ ++ WriteReg(state, 0x80, 0x01); ++ WriteReg(state, 0x82, 0x00); ++ msleep(1); ++ WriteReg(state, 0x80, 0x00); ++ return 0; ++} ++ ++static int M88DC2000SetSym(struct m88dc2800_state *state, u32 sym, u32 xtal) ++{ ++ u8 value; ++ u8 reg6FH, reg12H; ++ u64 fValue; ++ u32 dwValue; ++ printk("%s, sym=%d, xtal=%d\n", __func__, sym, xtal); ++ ++ fValue = 4294967296 * (sym + 10); ++ do_div(fValue, xtal); ++/* fValue = 4294967296 * (sym + 10) / xtal; */ ++ ++ dwValue = (u32)fValue; ++ printk("%s, fvalue1=%x\n", __func__, dwValue); ++ ++ WriteReg(state, 0x58, (u8)((dwValue >> 24) & 0xff)); ++ WriteReg(state, 0x57, (u8)((dwValue >> 16) & 0xff)); ++ WriteReg(state, 0x56, (u8)((dwValue >> 8) & 0xff)); ++ WriteReg(state, 0x55, (u8)((dwValue >> 0) & 0xff)); ++ ++/* fValue = 2048 * xtal / sym; */ ++ fValue = 2048 * xtal; ++ do_div(fValue, sym); ++ ++ dwValue = (u32)fValue; ++ printk("%s, fvalue2=%x\n", __func__, dwValue); ++ WriteReg(state, 0x5D, (u8)((dwValue >> 8) & 0xff)); ++ WriteReg(state, 0x5C, (u8)((dwValue >> 0) & 0xff)); ++ ++ value = ReadReg(state, 0x5A); ++ if (((dwValue >> 16) & 0x0001) == 0) ++ value &= 0x7F; ++ else ++ value |= 0x80; ++ WriteReg(state, 0x5A, value); ++ ++ value = ReadReg(state, 0x89); ++ if (sym <= 1800) ++ value |= 0x01; ++ else ++ value &= 0xFE; ++ WriteReg(state, 0x89, value); ++ ++ if (sym >= 6700){ ++ reg6FH = 0x0D; ++ reg12H = 0x30; ++ } else if (sym >= 4000) { ++ fValue = 22 * 4096 / sym; ++ reg6FH = (u8)fValue; ++ reg12H = 0x30; ++ } else if (sym >= 2000) { ++ fValue = 14 * 4096 / sym; ++ reg6FH = (u8)fValue; ++ reg12H = 0x20; ++ } else { ++ fValue = 7 * 4096 / sym; ++ reg6FH = (u8)fValue; ++ reg12H = 0x10; ++ } ++ WriteReg(state, 0x6F, reg6FH); ++ WriteReg(state, 0x12, reg12H); ++ ++ if (((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { ++ if(sym < 3000) { ++ WriteReg(state, 0x6C, 0x16); ++ WriteReg(state, 0x6D, 0x10); ++ WriteReg(state, 0x6E, 0x18); ++ } else { ++ WriteReg(state, 0x6C, 0x14); ++ WriteReg(state, 0x6D, 0x0E); ++ WriteReg(state, 0x6E, 0x36); ++ } ++ } else { ++ WriteReg(state, 0x6C, 0x16); ++ WriteReg(state, 0x6D, 0x10); ++ WriteReg(state, 0x6E, 0x18); ++ } ++ return 0; ++} ++ ++static int M88DC2000SetQAM(struct m88dc2800_state *state, u16 qam) ++{ ++ u8 reg00H, reg4AH, regC2H, reg44H, reg4CH, reg4DH, reg74H, value; ++ u8 reg8BH, reg8EH; ++ printk("%s, qam=%d\n", __func__, qam); ++ regC2H = ReadReg(state, 0xC2); ++ regC2H &= 0xF8; ++ switch(qam){ ++ case 16: /* 16 QAM */ ++ reg00H = 0x08; ++ reg4AH = 0x0F; ++ regC2H |= 0x02; ++ reg44H = 0xAA; ++ reg4CH = 0x0C; ++ reg4DH = 0xF7; ++ reg74H = 0x0E; ++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { ++ reg8BH = 0x5A; ++ reg8EH = 0xBD; ++ } else { ++ reg8BH = 0x5B; ++ reg8EH = 0x9D; ++ } ++ WriteReg(state, 0x6E, 0x18); ++ break; ++ case 32: /* 32 QAM */ ++ reg00H = 0x18; ++ reg4AH = 0xFB; ++ regC2H |= 0x02; ++ reg44H = 0xAA; ++ reg4CH = 0x0C; ++ reg4DH = 0xF7; ++ reg74H = 0x0E; ++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { ++ reg8BH = 0x5A; ++ reg8EH = 0xBD; ++ } else { ++ reg8BH = 0x5B; ++ reg8EH = 0x9D; ++ } ++ WriteReg(state, 0x6E, 0x18); ++ break; ++ case 64: /* 64 QAM */ ++ reg00H = 0x48; ++ reg4AH = 0xCD; ++ regC2H |= 0x02; ++ reg44H = 0xAA; ++ reg4CH = 0x0C; ++ reg4DH = 0xF7; ++ reg74H = 0x0E; ++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { ++ reg8BH = 0x5A; ++ reg8EH = 0xBD; ++ } else { ++ reg8BH = 0x5B; ++ reg8EH = 0x9D; ++ } ++ break; ++ case 128: /* 128 QAM */ ++ reg00H = 0x28; ++ reg4AH = 0xFF; ++ regC2H |= 0x02; ++ reg44H = 0xA9; ++ reg4CH = 0x08; ++ reg4DH = 0xF5; ++ reg74H = 0x0E; ++ reg8BH = 0x5B; ++ reg8EH = 0x9D; ++ break; ++ case 256: /* 256 QAM */ ++ reg00H = 0x38; ++ reg4AH = 0xCD; ++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { ++ regC2H |= 0x02; ++ } else { ++ regC2H |= 0x01; ++ } ++ reg44H = 0xA9; ++ reg4CH = 0x08; ++ reg4DH = 0xF5; ++ reg74H = 0x0E; ++ reg8BH = 0x5B; ++ reg8EH = 0x9D; ++ break; ++ default: /* 64 QAM */ ++ reg00H = 0x48; ++ reg4AH = 0xCD; ++ regC2H |= 0x02; ++ reg44H = 0xAA; ++ reg4CH = 0x0C; ++ reg4DH = 0xF7; ++ reg74H = 0x0E; ++ if(((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { ++ reg8BH = 0x5A; ++ reg8EH = 0xBD; ++ } else { ++ reg8BH = 0x5B; ++ reg8EH = 0x9D; ++ } ++ break; ++ } ++ WriteReg(state, 0x00, reg00H); ++ ++ value = ReadReg(state, 0x88); ++ value |= 0x08; ++ WriteReg(state, 0x88, value); ++ WriteReg(state, 0x4B, 0xFF); ++ WriteReg(state, 0x4A, reg4AH); ++ value &= 0xF7; ++ WriteReg(state, 0x88, value); ++ ++ WriteReg(state, 0xC2, regC2H); ++ WriteReg(state, 0x44, reg44H); ++ WriteReg(state, 0x4C, reg4CH); ++ WriteReg(state, 0x4D, reg4DH); ++ WriteReg(state, 0x74, reg74H); ++ WriteReg(state, 0x8B, reg8BH); ++ WriteReg(state, 0x8E, reg8EH); ++ return 0; ++} ++ ++static int M88DC2000WriteTuner_TC2800(struct m88dc2800_state *state, u32 freq_KHz) ++{ ++ printk("%s, freq=%d KHz\n", __func__, freq_KHz); ++ return mt_fe_tn_set_freq_tc2800(state, freq_KHz); ++} ++ ++static int m88dc2800_init(struct dvb_frontend *fe) ++{ ++ dprintk("%s()\n", __func__); ++ return 0; ++} ++ ++static int m88dc2800_set_parameters(struct dvb_frontend *fe) ++{ ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ u8 is_annex_c, is_update; ++ u16 temp_qam; ++ s32 waiting_time; ++ struct m88dc2800_state* state = fe->demodulator_priv; ++ ++ if(c->delivery_system == SYS_DVBC_ANNEX_C) ++ is_annex_c = 1; ++ else ++ is_annex_c = 0; ++ ++ switch (c->modulation) { ++ case QAM_16: ++ temp_qam = 16; ++ break; ++ case QAM_32: ++ temp_qam = 32; ++ break; ++ case QAM_128: ++ temp_qam = 128; ++ break; ++ case QAM_256: ++ temp_qam = 256; ++ break; ++ default: /* QAM_64 */ ++ temp_qam = 64; ++ break; ++ } ++ ++ if(c->inversion == INVERSION_ON) ++ state->inverted = 1; ++ else ++ state->inverted = 0; ++ ++ printk("m88dc2800: state, freq=%d qam=%d sym=%d inverted=%d xtal=%d\n", state->freq,state->qam,state->sym,state->inverted,state->xtal); ++ printk("m88dc2800: set frequency to %d qam=%d symrate=%d annex-c=%d\n", c->frequency,temp_qam,c->symbol_rate,is_annex_c); ++ ++ is_update = 0; ++ WriteReg(state, 0x80, 0x01); ++ if(c->frequency != state->freq){ ++ M88DC2000WriteTuner_TC2800(state, c->frequency/1000); ++ state->freq = c->frequency; ++ } ++ if(c->symbol_rate != state->sym){ ++ M88DC2000SetSym(state, c->symbol_rate/1000, state->xtal); ++ state->sym = c->symbol_rate; ++ is_update = 1; ++ } ++ if(temp_qam != state->qam){ ++ M88DC2000SetQAM(state, temp_qam); ++ state->qam = temp_qam; ++ is_update = 1; ++ } ++ ++ if(is_update != 0){ ++ if(state->config->ts_mode == 3) ++ M88DC2000AutoTSClock_C(state, state->sym/1000, temp_qam); ++ else ++ M88DC2000AutoTSClock_P(state, state->sym/1000, temp_qam); ++ } ++ ++ M88DC2000SetTxMode(state, state->inverted, is_annex_c); ++ M88DC2000SoftReset(state); ++ if (((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) ++ waiting_time = 800; ++ else ++ waiting_time = 500; ++ while (waiting_time > 0) { ++ msleep(50); ++ waiting_time -= 50; ++ if (M88DC2000GetLock(state)) ++ return 0; ++ } ++ ++ if (state->inverted != 0) ++ state->inverted = 0; ++ else ++ state->inverted = 1; ++ M88DC2000SetTxMode(state, state->inverted, is_annex_c); ++ M88DC2000SoftReset(state); ++ if (((ReadReg(state, 0xE3) & 0x80) == 0x80) && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) ++ waiting_time = 800; ++ else ++ waiting_time = 500; ++ while (waiting_time > 0) { ++ msleep(50); ++ waiting_time -= 50; ++ if (M88DC2000GetLock(state)) ++ return 0; ++ } ++ return 0; ++} ++ ++static int m88dc2800_read_status(struct dvb_frontend* fe, fe_status_t* status) ++{ ++ struct m88dc2800_state* state = fe->demodulator_priv; ++ *status = 0; ++ ++ if (M88DC2000GetLock(state)) { ++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER ++ | FE_HAS_SYNC|FE_HAS_VITERBI | FE_HAS_LOCK; ++ } ++ return 0; ++} ++ ++static int m88dc2800_read_ber(struct dvb_frontend* fe, u32* ber) ++{ ++ struct m88dc2800_state* state = fe->demodulator_priv; ++ u16 tmp; ++ ++ if (M88DC2000GetLock(state) == 0) { ++ state->ber = 0; ++ } else if ((ReadReg(state, 0xA0) & 0x80) != 0x80) { ++ tmp = ReadReg(state, 0xA2) << 8; ++ tmp += ReadReg(state, 0xA1); ++ state->ber = tmp; ++ WriteReg(state, 0xA0, 0x05); ++ WriteReg(state, 0xA0, 0x85); ++ } ++ *ber = state->ber; ++ return 0; ++} ++ ++static int m88dc2800_read_signal_strength(struct dvb_frontend* fe, u16* strength) ++{ ++ struct m88dc2800_state* state = fe->demodulator_priv; ++ ++ s16 tuner_strength; ++ tuner_strength = (s16)mt_fe_tn_get_signal_strength_tc2800(state); ++ ++ if(tuner_strength < -107) ++ *strength = 0; ++ else ++ *strength = tuner_strength + 107; ++ ++ return 0; ++} ++ ++static int m88dc2800_read_snr(struct dvb_frontend* fe, u16* snr) ++{ ++ struct m88dc2800_state* state = fe->demodulator_priv; ++ ++ const u32 mes_log[] = { ++ 0, 3010, 4771, 6021, 6990, 7781, 8451, 9031, 9542, 10000, ++ 10414, 10792, 11139, 11461, 11761, 12041, 12304, 12553, 12788, 13010, ++ 13222, 13424, 13617, 13802, 13979, 14150, 14314, 14472, 14624, 14771, ++ 14914, 15052, 15185, 15315, 15441, 15563, 15682, 15798, 15911, 16021, ++ 16128, 16232, 16335, 16435, 16532, 16628, 16721, 16812, 16902, 16990, ++ 17076, 17160, 17243, 17324, 17404, 17482, 17559, 17634, 17709, 17782, ++ 17853, 17924, 17993, 18062, 18129, 18195, 18261, 18325, 18388, 18451, ++ 18513, 18573, 18633, 18692, 18751, 18808, 18865, 18921, 18976, 19031 ++ }; ++ u8 i; ++ u32 _snr, mse; ++ ++ if ((ReadReg(state, 0x91)&0x23)!=0x03) { ++ *snr = 0; ++ return 0; ++ } ++ ++ mse = 0; ++ for (i=0; i<30; i++) { ++ mse += (ReadReg(state, 0x08) << 8) + ReadReg(state, 0x07); ++ } ++ mse /= 30; ++ if (mse > 80) ++ mse = 80; ++ ++ switch (state->qam) { ++ case 16: _snr = 34080; break; /* 16QAM */ ++ case 32: _snr = 37600; break; /* 32QAM */ ++ case 64: _snr = 40310; break; /* 64QAM */ ++ case 128: _snr = 43720; break; /* 128QAM */ ++ case 256: _snr = 46390; break; /* 256QAM */ ++ default: _snr = 40310; break; ++ } ++ _snr -= mes_log[mse-1]; /* C - 10*log10(MSE) */ ++ _snr /= 1000; ++ if (_snr > 0xff) ++ _snr = 0xff; ++ ++ *snr = _snr; ++ return 0; ++} ++ ++static int m88dc2800_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) ++{ ++ struct m88dc2800_state* state = fe->demodulator_priv; ++ u8 u8Value; ++ ++ u8Value = ReadReg(state, 0xdf); ++ u8Value |= 0x02; /* Hold */ ++ WriteReg(state, 0xdf, u8Value); ++ ++ *ucblocks = ReadReg(state, 0xd5); ++ *ucblocks = (*ucblocks << 8) | ReadReg(state, 0xd4); ++ ++ u8Value &= 0xfe; /* Clear */ ++ WriteReg(state, 0xdf, u8Value); ++ u8Value &= 0xfc; /* Update */ ++ u8Value |= 0x01; ++ WriteReg(state, 0xdf, u8Value); ++ ++ return 0; ++} ++ ++static int m88dc2800_sleep(struct dvb_frontend* fe) ++{ ++ struct m88dc2800_state* state = fe->demodulator_priv; ++ ++ mt_fe_tn_sleep_tc2800(state); ++ state->freq = 0; ++ ++ return 0; ++} ++ ++static void m88dc2800_release(struct dvb_frontend* fe) ++{ ++ struct m88dc2800_state* state = fe->demodulator_priv; ++ kfree(state); ++} ++ ++static struct dvb_frontend_ops m88dc2800_ops; ++ ++struct dvb_frontend* m88dc2800_attach(const struct m88dc2800_config* config, ++ struct i2c_adapter* i2c) ++{ ++ struct m88dc2800_state* state = NULL; ++ ++ /* allocate memory for the internal state */ ++ state = kzalloc(sizeof(struct m88dc2800_state), GFP_KERNEL); ++ if (state == NULL) goto error; ++ ++ /* setup the state */ ++ state->config = config; ++ state->i2c = i2c; ++ state->xtal = 28800; ++ ++ WriteReg(state, 0x80, 0x01); ++ M88DC2000RegInitial_TC2800(state); ++ M88DC2000SetTsType(state, state->config->ts_mode); ++ mt_fe_tn_init_tc2800(state); ++ ++ /* create dvb_frontend */ ++ memcpy(&state->frontend.ops, &m88dc2800_ops, sizeof(struct dvb_frontend_ops)); ++ state->frontend.demodulator_priv = state; ++ return &state->frontend; ++ ++error: ++ kfree(state); ++ return NULL; ++} ++EXPORT_SYMBOL(m88dc2800_attach); ++ ++static struct dvb_frontend_ops m88dc2800_ops = { ++ .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C }, ++ .info = { ++ .name = "Montage M88DC2800 DVB-C", ++ .frequency_stepsize = 62500, ++ .frequency_min = 48000000, ++ .frequency_max = 870000000, ++ .symbol_rate_min = 870000, ++ .symbol_rate_max = 9000000, ++ .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | ++ FE_CAN_QAM_128 | FE_CAN_QAM_256 | ++ FE_CAN_FEC_AUTO ++ }, ++ ++ .release = m88dc2800_release, ++ .init = m88dc2800_init, ++ .sleep = m88dc2800_sleep, ++ .set_frontend = m88dc2800_set_parameters, ++ .read_status = m88dc2800_read_status, ++ .read_ber = m88dc2800_read_ber, ++ .read_signal_strength = m88dc2800_read_signal_strength, ++ .read_snr = m88dc2800_read_snr, ++ .read_ucblocks = m88dc2800_read_ucblocks, ++}; ++ ++MODULE_DESCRIPTION("Montage DVB-C demodulator driver"); ++MODULE_AUTHOR("Max nibble"); ++MODULE_LICENSE("GPL"); +diff -urN a/drivers/media/dvb/frontends/m88dc2800.h b/drivers/media/dvb/frontends/m88dc2800.h +--- a/drivers/media/dvb/frontends/m88dc2800.h 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/media/dvb/frontends/m88dc2800.h 2012-11-18 23:23:23.993155429 +0800 +@@ -0,0 +1,43 @@ ++/* ++ M88DC2800/M88TC2800 - DVB-C demodulator and tuner from Montage ++ ++ Copyright (C) 2012 Max nibble ++ Copyright (C) 2011 Montage Technology ++ ++ 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; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#ifndef M88DC2800_H ++#define M88DC2800_H ++ ++#include ++ ++struct m88dc2800_config { ++ u8 demod_address; ++ u8 ts_mode; ++}; ++ ++#if defined(CONFIG_DVB_M88DC2800) || (defined(CONFIG_DVB_M88DC2800_MODULE) && defined(MODULE)) ++extern struct dvb_frontend* m88dc2800_attach(const struct m88dc2800_config* config, ++ struct i2c_adapter* i2c); ++#else ++static inline struct dvb_frontend* m88dc2800_attach(const struct m88dc2800_config* config, ++ struct i2c_adapter* i2c) ++{ ++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); ++ return NULL; ++} ++#endif // CONFIG_DVB_M88DC2800 ++#endif // M88DC2800_H +diff -urN a/drivers/media/dvb/frontends/m88ds3103.c b/drivers/media/dvb/frontends/m88ds3103.c +--- a/drivers/media/dvb/frontends/m88ds3103.c 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/media/dvb/frontends/m88ds3103.c 2012-11-18 23:23:27.661155528 +0800 +@@ -0,0 +1,1710 @@ ++/* ++ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver ++ ++ Copyright (C) 2011 Max nibble ++ Copyright (C) 2010 Montage Technology ++ Copyright (C) 2009 Konstantin Dimitrov. ++ ++ 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; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dvb_frontend.h" ++#include "m88ds3103.h" ++#include "m88ds3103_priv.h" ++ ++static int debug; ++module_param(debug, int, 0644); ++MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); ++ ++#define dprintk(args...) \ ++ do { \ ++ if (debug) \ ++ printk(KERN_INFO "m88ds3103: " args); \ ++ } while (0) ++ ++/*demod register operations.*/ ++static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data) ++{ ++ u8 buf[] = { reg, data }; ++ struct i2c_msg msg = { .addr = state->config->demod_address, ++ .flags = 0, .buf = buf, .len = 2 }; ++ int err; ++ ++ if (debug > 1) ++ printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n", ++ __func__, reg, data); ++ ++ err = i2c_transfer(state->i2c, &msg, 1); ++ if (err != 1) { ++ printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," ++ " value == 0x%02x)\n", __func__, err, reg, data); ++ return -EREMOTEIO; ++ } ++ return 0; ++} ++ ++static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg) ++{ ++ int ret; ++ u8 b0[] = { reg }; ++ u8 b1[] = { 0 }; ++ struct i2c_msg msg[] = { ++ { .addr = state->config->demod_address, .flags = 0, ++ .buf = b0, .len = 1 }, ++ { .addr = state->config->demod_address, .flags = I2C_M_RD, ++ .buf = b1, .len = 1 } ++ }; ++ ret = i2c_transfer(state->i2c, msg, 2); ++ ++ if (ret != 2) { ++ printk(KERN_ERR "%s: reg=0x%x (error=%d)\n", ++ __func__, reg, ret); ++ return ret; ++ } ++ ++ if (debug > 1) ++ printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n", ++ reg, b1[0]); ++ ++ return b1[0]; ++} ++ ++/*tuner register operations.*/ ++static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, int data) ++{ ++ u8 buf[] = { reg, data }; ++ struct i2c_msg msg = { .addr = 0x60, ++ .flags = 0, .buf = buf, .len = 2 }; ++ int err; ++ ++ m88ds3103_writereg(state, 0x03, 0x11); ++ err = i2c_transfer(state->i2c, &msg, 1); ++ ++ if (err != 1) { ++ printk("%s: writereg error(err == %i, reg == 0x%02x," ++ " value == 0x%02x)\n", __func__, err, reg, data); ++ return -EREMOTEIO; ++ } ++ ++ return 0; ++} ++ ++static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg) ++{ ++ int ret; ++ u8 b0[] = { reg }; ++ u8 b1[] = { 0 }; ++ struct i2c_msg msg[] = { ++ { .addr = 0x60, .flags = 0, ++ .buf = b0, .len = 1 }, ++ { .addr = 0x60, .flags = I2C_M_RD, ++ .buf = b1, .len = 1 } ++ }; ++ ++ m88ds3103_writereg(state, 0x03, 0x11); ++ ret = i2c_transfer(state->i2c, msg, 2); ++ ++ if (ret != 2) { ++ printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret); ++ return ret; ++ } ++ ++ return b1[0]; ++} ++ ++/* Bulk demod I2C write, for firmware download. */ ++static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg, ++ const u8 *data, u16 len) ++{ ++ int ret = -EREMOTEIO; ++ struct i2c_msg msg; ++ u8 *buf; ++ ++ buf = kmalloc(len + 1, GFP_KERNEL); ++ if (buf == NULL) { ++ printk("Unable to kmalloc\n"); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ *(buf) = reg; ++ memcpy(buf + 1, data, len); ++ ++ msg.addr = state->config->demod_address; ++ msg.flags = 0; ++ msg.buf = buf; ++ msg.len = len + 1; ++ ++ if (debug > 1) ++ printk(KERN_INFO "m88ds3103: %s: write regN 0x%02x, len = %d\n", ++ __func__, reg, len); ++ ++ ret = i2c_transfer(state->i2c, &msg, 1); ++ if (ret != 1) { ++ printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n", ++ __func__, ret, reg); ++ ret = -EREMOTEIO; ++ } ++ ++error: ++ kfree(buf); ++ ++ return ret; ++} ++ ++static int m88ds3103_load_firmware(struct dvb_frontend *fe) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ const struct firmware *fw; ++ int i, ret = 0; ++ ++ dprintk("%s()\n", __func__); ++ ++ if (state->skip_fw_load) ++ return 0; ++ /* Load firmware */ ++ /* request the firmware, this will block until someone uploads it */ ++ if(state->demod_id == DS3000_ID){ ++ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, ++ DS3000_DEFAULT_FIRMWARE); ++ ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE, ++ state->i2c->dev.parent); ++ }else if(state->demod_id == DS3103_ID){ ++ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, ++ DS3103_DEFAULT_FIRMWARE); ++ ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE, ++ state->i2c->dev.parent); ++ } ++ ++ printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); ++ if (ret) { ++ printk(KERN_ERR "%s: No firmware uploaded (timeout or file not " ++ "found?)\n", __func__); ++ return ret; ++ } ++ ++ /* Make sure we don't recurse back through here during loading */ ++ state->skip_fw_load = 1; ++ ++ dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", ++ fw->size, ++ fw->data[0], ++ fw->data[1], ++ fw->data[fw->size - 2], ++ fw->data[fw->size - 1]); ++ ++ /* stop internal mcu. */ ++ m88ds3103_writereg(state, 0xb2, 0x01); ++ /* split firmware to download.*/ ++ for(i = 0; i < FW_DOWN_LOOP; i++){ ++ ret = m88ds3103_writeregN(state, 0xb0, &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE); ++ if(ret != 1) break; ++ } ++ /* start internal mcu. */ ++ if(ret == 1) ++ m88ds3103_writereg(state, 0xb2, 0x00); ++ ++ release_firmware(fw); ++ ++ dprintk("%s: Firmware upload %s\n", __func__, ++ ret == 1 ? "complete" : "failed"); ++ ++ if(ret == 1) ret = 0; ++ ++ /* Ensure firmware is always loaded if required */ ++ state->skip_fw_load = 0; ++ ++ return ret; ++} ++ ++ ++static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u8 data; ++ ++ dprintk("%s(%d)\n", __func__, voltage); ++ ++ dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl); ++ ++ if(state->config->set_voltage) ++ state->config->set_voltage(fe, voltage); ++ ++ data = m88ds3103_readreg(state, 0xa2); ++ ++ if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/ ++ data &= ~0x03; /* bit0 V/H, bit1 off/on */ ++ if(state->config->pin_ctrl & 0x02) ++ data |= 0x02; ++ ++ switch (voltage) { ++ case SEC_VOLTAGE_18: ++ if((state->config->pin_ctrl & 0x01) == 0) ++ data |= 0x01; ++ break; ++ case SEC_VOLTAGE_13: ++ if(state->config->pin_ctrl & 0x01) ++ data |= 0x01; ++ break; ++ case SEC_VOLTAGE_OFF: ++ if(state->config->pin_ctrl & 0x02) ++ data &= ~0x02; ++ else ++ data |= 0x02; ++ break; ++ } ++ } ++ ++ m88ds3103_writereg(state, 0xa2, data); ++ ++ return 0; ++} ++ ++static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* status) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ int lock = 0; ++ ++ *status = 0; ++ ++ switch (state->delivery_system){ ++ case SYS_DVBS: ++ lock = m88ds3103_readreg(state, 0xd1); ++ dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock); ++ ++ if ((lock & 0x07) == 0x07){ ++ /*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/ ++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER ++ | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; ++ ++ } ++ break; ++ case SYS_DVBS2: ++ lock = m88ds3103_readreg(state, 0x0d); ++ dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock); ++ ++ if ((lock & 0x8f) == 0x8f) ++ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER ++ | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; ++ ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u8 tmp1, tmp2, tmp3; ++ u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0; ++ ++ dprintk("%s()\n", __func__); ++ ++ switch (state->delivery_system) { ++ case SYS_DVBS: ++ m88ds3103_writereg(state, 0xf9, 0x04); ++ tmp3 = m88ds3103_readreg(state, 0xf8); ++ if ((tmp3&0x10) == 0){ ++ tmp1 = m88ds3103_readreg(state, 0xf7); ++ tmp2 = m88ds3103_readreg(state, 0xf6); ++ tmp3 |= 0x10; ++ m88ds3103_writereg(state, 0xf8, tmp3); ++ state->preBer = (tmp1<<8) | tmp2; ++ } ++ break; ++ case SYS_DVBS2: ++ tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f; ++ switch(tmp1){ ++ case 0: code_rate_fac = 16008 - 80; break; ++ case 1: code_rate_fac = 21408 - 80; break; ++ case 2: code_rate_fac = 25728 - 80; break; ++ case 3: code_rate_fac = 32208 - 80; break; ++ case 4: code_rate_fac = 38688 - 80; break; ++ case 5: code_rate_fac = 43040 - 80; break; ++ case 6: code_rate_fac = 48408 - 80; break; ++ case 7: code_rate_fac = 51648 - 80; break; ++ case 8: code_rate_fac = 53840 - 80; break; ++ case 9: code_rate_fac = 57472 - 80; break; ++ case 10: code_rate_fac = 58192 - 80; break; ++ } ++ ++ tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff; ++ tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff; ++ tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff; ++ ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3; ++ ++ tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff; ++ tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff; ++ pre_err_packags = tmp1<<8 | tmp2; ++ ++ if (ldpc_frame_cnt > 1000){ ++ m88ds3103_writereg(state, 0xd1, 0x01); ++ m88ds3103_writereg(state, 0xf9, 0x01); ++ m88ds3103_writereg(state, 0xf9, 0x00); ++ m88ds3103_writereg(state, 0xd1, 0x00); ++ state->preBer = pre_err_packags; ++ } ++ break; ++ default: ++ break; ++ } ++ *ber = state->preBer; ++ ++ return 0; ++} ++ ++static int m88ds3103_read_signal_strength(struct dvb_frontend *fe, ++ u16 *signal_strength) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u16 gain; ++ u8 gain1, gain2, gain3 = 0; ++ ++ dprintk("%s()\n", __func__); ++ ++ gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f; ++ dprintk("%s: gain1 = 0x%02x \n", __func__, gain1); ++ ++ if (gain1 > 15) gain1 = 15; ++ gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f; ++ dprintk("%s: gain2 = 0x%02x \n", __func__, gain2); ++ ++ if(state->tuner_id == TS2022_ID){ ++ gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07; ++ dprintk("%s: gain3 = 0x%02x \n", __func__, gain3); ++ ++ if (gain2 > 16) gain2 = 16; ++ if (gain2 < 2) gain2 = 2; ++ if (gain3 > 6) gain3 = 6; ++ }else{ ++ if (gain2 > 13) gain2 = 13; ++ gain3 = 0; ++ } ++ ++ gain = gain1*23 + gain2*35 + gain3*29; ++ *signal_strength = 60000 - gain*55; ++ ++ return 0; ++} ++ ++ ++static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u8 val, npow1, npow2, spow1, cnt; ++ u16 tmp, snr; ++ u32 npow, spow, snr_total; ++ static const u16 mes_log10[] ={ ++ 0, 3010, 4771, 6021, 6990, 7781, 8451, 9031, 9542, 10000, ++ 10414, 10792, 11139, 11461, 11761, 12041, 12304, 12553, 12788, 13010, ++ 13222, 13424, 13617, 13802, 13979, 14150, 14314, 14472, 14624, 14771, ++ 14914, 15052, 15185, 15315, 15441, 15563, 15682, 15798, 15911, 16021, ++ 16128, 16232, 16335, 16435, 16532, 16628, 16721, 16812, 16902, 16990, ++ 17076, 17160, 17243, 17324, 17404, 17482, 17559, 17634, 17709, 17782, ++ 17853, 17924, 17993, 18062, 18129, 18195, 18261, 18325, 18388, 18451, ++ 18513, 18573, 18633, 18692, 18751, 18808, 18865, 18921, 18976, 19031 ++ }; ++ static const u16 mes_loge[] ={ ++ 0, 6931, 10986, 13863, 16094, 17918, 19459, 20794, 21972, 23026, ++ 23979, 24849, 25649, 26391, 27081, 27726, 28332, 28904, 29444, 29957, ++ 30445, 30910, 31355, 31781, 32189, 32581, 32958, 33322, 33673, 34012, ++ 34340, 34657, ++ }; ++ ++ dprintk("%s()\n", __func__); ++ ++ snr = 0; ++ ++ switch (state->delivery_system){ ++ case SYS_DVBS: ++ cnt = 10; snr_total = 0; ++ while(cnt > 0){ ++ val = m88ds3103_readreg(state, 0xff); ++ snr_total += val; ++ cnt--; ++ } ++ tmp = (u16)(snr_total/80); ++ if(tmp > 0){ ++ if (tmp > 32) tmp = 32; ++ snr = (mes_loge[tmp - 1] * 100) / 45; ++ }else{ ++ snr = 0; ++ } ++ break; ++ case SYS_DVBS2: ++ cnt = 10; npow = 0; spow = 0; ++ while(cnt >0){ ++ npow1 = m88ds3103_readreg(state, 0x8c) & 0xff; ++ npow2 = m88ds3103_readreg(state, 0x8d) & 0xff; ++ npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2); ++ ++ spow1 = m88ds3103_readreg(state, 0x8e) & 0xff; ++ spow += ((spow1 * spow1) >> 1); ++ cnt--; ++ } ++ npow /= 10; spow /= 10; ++ if(spow == 0){ ++ snr = 0; ++ }else if(npow == 0){ ++ snr = 19; ++ }else{ ++ if(spow > npow){ ++ tmp = (u16)(spow / npow); ++ if (tmp > 80) tmp = 80; ++ snr = mes_log10[tmp - 1]*3; ++ }else{ ++ tmp = (u16)(npow / spow); ++ if (tmp > 80) tmp = 80; ++ snr = -(mes_log10[tmp - 1] / 1000); ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ *p_snr = snr; ++ ++ return 0; ++} ++ ++ ++static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u8 tmp1, tmp2, tmp3, data; ++ ++ dprintk("%s()\n", __func__); ++ ++ switch (state->delivery_system) { ++ case SYS_DVBS: ++ data = m88ds3103_readreg(state, 0xf8); ++ data |= 0x40; ++ m88ds3103_writereg(state, 0xf8, data); ++ tmp1 = m88ds3103_readreg(state, 0xf5); ++ tmp2 = m88ds3103_readreg(state, 0xf4); ++ *ucblocks = (tmp1 <<8) | tmp2; ++ data &= ~0x20; ++ m88ds3103_writereg(state, 0xf8, data); ++ data |= 0x20; ++ m88ds3103_writereg(state, 0xf8, data); ++ data &= ~0x40; ++ m88ds3103_writereg(state, 0xf8, data); ++ break; ++ case SYS_DVBS2: ++ tmp1 = m88ds3103_readreg(state, 0xda); ++ tmp2 = m88ds3103_readreg(state, 0xd9); ++ tmp3 = m88ds3103_readreg(state, 0xd8); ++ *ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3; ++ data = m88ds3103_readreg(state, 0xd1); ++ data |= 0x01; ++ m88ds3103_writereg(state, 0xd1, data); ++ data &= ~0x01; ++ m88ds3103_writereg(state, 0xd1, data); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u8 data_a1, data_a2; ++ ++ dprintk("%s(%d)\n", __func__, tone); ++ if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { ++ printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); ++ return -EINVAL; ++ } ++ ++ data_a1 = m88ds3103_readreg(state, 0xa1); ++ data_a2 = m88ds3103_readreg(state, 0xa2); ++ if(state->demod_id == DS3103_ID) ++ data_a2 &= 0xdf; /* Normal mode */ ++ switch (tone) { ++ case SEC_TONE_ON: ++ dprintk("%s: SEC_TONE_ON\n", __func__); ++ data_a1 |= 0x04; ++ data_a1 &= ~0x03; ++ data_a1 &= ~0x40; ++ data_a2 &= ~0xc0; ++ break; ++ case SEC_TONE_OFF: ++ dprintk("%s: SEC_TONE_OFF\n", __func__); ++ data_a2 &= ~0xc0; ++ data_a2 |= 0x80; ++ break; ++ } ++ m88ds3103_writereg(state, 0xa2, data_a2); ++ m88ds3103_writereg(state, 0xa1, data_a1); ++ return 0; ++} ++ ++static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe, ++ struct dvb_diseqc_master_cmd *d) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ int i, ret = 0; ++ u8 tmp, time_out; ++ ++ /* Dump DiSEqC message */ ++ if (debug) { ++ printk(KERN_INFO "m88ds3103: %s(", __func__); ++ for (i = 0 ; i < d->msg_len ;) { ++ printk(KERN_INFO "0x%02x", d->msg[i]); ++ if (++i < d->msg_len) ++ printk(KERN_INFO ", "); ++ } ++ } ++ ++ tmp = m88ds3103_readreg(state, 0xa2); ++ tmp &= ~0xc0; ++ if(state->demod_id == DS3103_ID) ++ tmp &= ~0x20; ++ m88ds3103_writereg(state, 0xa2, tmp); ++ ++ for (i = 0; i < d->msg_len; i ++) ++ m88ds3103_writereg(state, (0xa3+i), d->msg[i]); ++ ++ tmp = m88ds3103_readreg(state, 0xa1); ++ tmp &= ~0x38; ++ tmp &= ~0x40; ++ tmp |= ((d->msg_len-1) << 3) | 0x07; ++ tmp &= ~0x80; ++ m88ds3103_writereg(state, 0xa1, tmp); ++ /* 1.5 * 9 * 8 = 108ms */ ++ time_out = 150; ++ while (time_out > 0){ ++ msleep(10); ++ time_out -= 10; ++ tmp = m88ds3103_readreg(state, 0xa1); ++ if ((tmp & 0x40) == 0) ++ break; ++ } ++ if (time_out == 0){ ++ tmp = m88ds3103_readreg(state, 0xa1); ++ tmp &= ~0x80; ++ tmp |= 0x40; ++ m88ds3103_writereg(state, 0xa1, tmp); ++ ret = 1; ++ } ++ tmp = m88ds3103_readreg(state, 0xa2); ++ tmp &= ~0xc0; ++ tmp |= 0x80; ++ m88ds3103_writereg(state, 0xa2, tmp); ++ return ret; ++} ++ ++ ++static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, ++ fe_sec_mini_cmd_t burst) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u8 val, time_out; ++ ++ dprintk("%s()\n", __func__); ++ ++ val = m88ds3103_readreg(state, 0xa2); ++ val &= ~0xc0; ++ if(state->demod_id == DS3103_ID) ++ val &= 0xdf; /* Normal mode */ ++ m88ds3103_writereg(state, 0xa2, val); ++ /* DiSEqC burst */ ++ if (burst == SEC_MINI_B) ++ m88ds3103_writereg(state, 0xa1, 0x01); ++ else ++ m88ds3103_writereg(state, 0xa1, 0x02); ++ ++ msleep(13); ++ ++ time_out = 5; ++ do{ ++ val = m88ds3103_readreg(state, 0xa1); ++ if ((val & 0x40) == 0) ++ break; ++ msleep(1); ++ time_out --; ++ } while (time_out > 0); ++ ++ val = m88ds3103_readreg(state, 0xa2); ++ val &= ~0xc0; ++ val |= 0x80; ++ m88ds3103_writereg(state, 0xa2, val); ++ ++ return 0; ++} ++ ++static void m88ds3103_release(struct dvb_frontend *fe) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ ++ dprintk("%s\n", __func__); ++ kfree(state); ++} ++ ++static int m88ds3103_check_id(struct m88ds3103_state *state) ++{ ++ int val_00, val_01; ++ ++ /*check demod id*/ ++ val_01 = m88ds3103_readreg(state, 0x01); ++ printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01); ++ ++ if(val_01 == 0xD0) ++ state->demod_id = DS3103_ID; ++ else if(val_01 == 0xC0) ++ state->demod_id = DS3000_ID; ++ else ++ state->demod_id = UNKNOW_ID; ++ ++ /*check tuner id*/ ++ val_00 = m88ds3103_tuner_readreg(state, 0x00); ++ printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00); ++ val_00 &= 0x03; ++ if(val_00 == 0) ++ { ++ m88ds3103_tuner_writereg(state, 0x00, 0x01); ++ msleep(3); ++ } ++ m88ds3103_tuner_writereg(state, 0x00, 0x03); ++ msleep(5); ++ ++ val_00 = m88ds3103_tuner_readreg(state, 0x00); ++ printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00); ++ val_00 &= 0xff; ++ if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81)) ++ state->tuner_id = TS2020_ID; ++ else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83)) ++ state->tuner_id = TS2022_ID; ++ else ++ state->tuner_id = UNKNOW_ID; ++ ++ return state->demod_id; ++} ++ ++static struct dvb_frontend_ops m88ds3103_ops; ++static int m88ds3103_initilaze(struct dvb_frontend *fe); ++ ++struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config, ++ struct i2c_adapter *i2c) ++{ ++ struct m88ds3103_state *state = NULL; ++ ++ dprintk("%s\n", __func__); ++ ++ /* allocate memory for the internal state */ ++ state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL); ++ if (state == NULL) { ++ printk(KERN_ERR "Unable to kmalloc\n"); ++ goto error2; ++ } ++ ++ state->config = config; ++ state->i2c = i2c; ++ state->preBer = 0xffff; ++ state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/ ++ ++ /* check demod id */ ++ if(m88ds3103_check_id(state) == UNKNOW_ID){ ++ printk(KERN_ERR "Unable to find Montage chip\n"); ++ goto error3; ++ } ++ ++ memcpy(&state->frontend.ops, &m88ds3103_ops, ++ sizeof(struct dvb_frontend_ops)); ++ state->frontend.demodulator_priv = state; ++ ++ m88ds3103_initilaze(&state->frontend); ++ ++ return &state->frontend; ++ ++error3: ++ kfree(state); ++error2: ++ return NULL; ++} ++EXPORT_SYMBOL(m88ds3103_attach); ++ ++static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe, ++ s32 carrier_offset_khz) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ s32 tmp; ++ ++ tmp = carrier_offset_khz; ++ tmp *= 65536; ++ ++ tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ); ++ ++ if (tmp < 0) ++ tmp += 65536; ++ ++ m88ds3103_writereg(state, 0x5f, tmp >> 8); ++ m88ds3103_writereg(state, 0x5e, tmp & 0xff); ++ ++ return 0; ++} ++ ++static int m88ds3103_set_symrate(struct dvb_frontend *fe) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ u16 value; ++ ++ value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2); ++ m88ds3103_writereg(state, 0x61, value & 0x00ff); ++ m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8); ++ ++ return 0; ++} ++ ++static int m88ds3103_set_CCI(struct dvb_frontend *fe) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u8 tmp; ++ ++ tmp = m88ds3103_readreg(state, 0x56); ++ tmp &= ~0x01; ++ m88ds3103_writereg(state, 0x56, tmp); ++ ++ tmp = m88ds3103_readreg(state, 0x76); ++ tmp &= ~0x80; ++ m88ds3103_writereg(state, 0x76, tmp); ++ ++ return 0; ++} ++ ++static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 *p_reg_tab, u32 size) ++{ ++ u32 i; ++ ++ for(i = 0; i < size; i+=2) ++ m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]); ++ ++ return 0; ++} ++ ++static int m88ds3103_get_locked_sym_rate(struct m88ds3103_state *state, u32 *sym_rate_KSs) ++{ ++ u16 tmp; ++ u32 sym_rate_tmp; ++ u8 val_0x6d, val_0x6e; ++ ++ val_0x6d = m88ds3103_readreg(state, 0x6d); ++ val_0x6e = m88ds3103_readreg(state, 0x6e); ++ ++ tmp = (u16)((val_0x6e<<8) | val_0x6d); ++ ++ sym_rate_tmp = (u32)(tmp * MT_FE_MCLK_KHZ); ++ sym_rate_tmp = (u32)(sym_rate_tmp / (1<<16)); ++ *sym_rate_KSs = sym_rate_tmp; ++ ++ return 0; ++} ++ ++static int m88ds3103_get_channel_info(struct m88ds3103_state *state, u8 *p_mode, u8 *p_coderate) ++{ ++ u8 tmp, val_0x7E; ++ ++ if(state->delivery_system == SYS_DVBS2){ ++ val_0x7E = m88ds3103_readreg(state, 0x7e); ++ tmp = (u8)((val_0x7E&0xC0) >> 6); ++ *p_mode = tmp; ++ tmp = (u8)(val_0x7E & 0x0f); ++ *p_coderate = tmp; ++ } else { ++ *p_mode = 0; ++ tmp = m88ds3103_readreg(state, 0xe6); ++ tmp = (u8)(tmp >> 5); ++ *p_coderate = tmp; ++ } ++ ++ return 0; ++} ++ ++static int m88ds3103_set_clock_ratio(struct m88ds3103_state *state) ++{ ++ u8 val, mod_fac, tmp1, tmp2; ++ u32 input_datarate, locked_sym_rate_KSs; ++ u32 MClk_KHz = 96000; ++ u8 mod_mode, code_rate, divid_ratio = 0; ++ ++ locked_sym_rate_KSs = 0; ++ m88ds3103_get_locked_sym_rate(state, &locked_sym_rate_KSs); ++ if(locked_sym_rate_KSs == 0) ++ return 0; ++ ++ m88ds3103_get_channel_info(state, &mod_mode, &code_rate); ++ ++ if (state->delivery_system == SYS_DVBS2) ++ { ++ switch(mod_mode) { ++ case 1: mod_fac = 3; break; ++ case 2: mod_fac = 4; break; ++ case 3: mod_fac = 5; break; ++ default: mod_fac = 2; break; ++ } ++ ++ switch(code_rate) { ++ case 0: input_datarate = locked_sym_rate_KSs*mod_fac/8/4; break; ++ case 1: input_datarate = locked_sym_rate_KSs*mod_fac/8/3; break; ++ case 2: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/5; break; ++ case 3: input_datarate = locked_sym_rate_KSs*mod_fac/8/2; break; ++ case 4: input_datarate = locked_sym_rate_KSs*mod_fac*3/8/5; break; ++ case 5: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break; ++ case 6: input_datarate = locked_sym_rate_KSs*mod_fac*3/8/4; break; ++ case 7: input_datarate = locked_sym_rate_KSs*mod_fac*4/8/5; break; ++ case 8: input_datarate = locked_sym_rate_KSs*mod_fac*5/8/6; break; ++ case 9: input_datarate = locked_sym_rate_KSs*mod_fac*8/8/9; break; ++ case 10: input_datarate = locked_sym_rate_KSs*mod_fac*9/8/10; break; ++ default: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break; ++ } ++ ++ if(state->demod_id == DS3000_ID) ++ input_datarate = input_datarate * 115 / 100; ++ ++ if(input_datarate < 4800) {tmp1 = 15;tmp2 = 15;} //4.8MHz TS clock ++ else if(input_datarate < 4966) {tmp1 = 14;tmp2 = 15;} //4.966MHz TS clock ++ else if(input_datarate < 5143) {tmp1 = 14;tmp2 = 14;} //5.143MHz TS clock ++ else if(input_datarate < 5333) {tmp1 = 13;tmp2 = 14;} //5.333MHz TS clock ++ else if(input_datarate < 5538) {tmp1 = 13;tmp2 = 13;} //5.538MHz TS clock ++ else if(input_datarate < 5760) {tmp1 = 12;tmp2 = 13;} //5.76MHz TS clock allan 0809 ++ else if(input_datarate < 6000) {tmp1 = 12;tmp2 = 12;} //6MHz TS clock ++ else if(input_datarate < 6260) {tmp1 = 11;tmp2 = 12;} //6.26MHz TS clock ++ else if(input_datarate < 6545) {tmp1 = 11;tmp2 = 11;} //6.545MHz TS clock ++ else if(input_datarate < 6857) {tmp1 = 10;tmp2 = 11;} //6.857MHz TS clock ++ else if(input_datarate < 7200) {tmp1 = 10;tmp2 = 10;} //7.2MHz TS clock ++ else if(input_datarate < 7578) {tmp1 = 9;tmp2 = 10;} //7.578MHz TS clock ++ else if(input_datarate < 8000) {tmp1 = 9;tmp2 = 9;} //8MHz TS clock ++ else if(input_datarate < 8470) {tmp1 = 8;tmp2 = 9;} //8.47MHz TS clock ++ else if(input_datarate < 9000) {tmp1 = 8;tmp2 = 8;} //9MHz TS clock ++ else if(input_datarate < 9600) {tmp1 = 7;tmp2 = 8;} //9.6MHz TS clock ++ else if(input_datarate < 10285) {tmp1 = 7;tmp2 = 7;} //10.285MHz TS clock ++ else if(input_datarate < 12000) {tmp1 = 6;tmp2 = 6;} //12MHz TS clock ++ else if(input_datarate < 14400) {tmp1 = 5;tmp2 = 5;} //14.4MHz TS clock ++ else if(input_datarate < 18000) {tmp1 = 4;tmp2 = 4;} //18MHz TS clock ++ else {tmp1 = 3;tmp2 = 3;} //24MHz TS clock ++ ++ if(state->demod_id == DS3000_ID) { ++ val = (u8)((tmp1<<4) + tmp2); ++ m88ds3103_writereg(state, 0xfe, val); ++ } else { ++ tmp1 = m88ds3103_readreg(state, 0x22); ++ tmp2 = m88ds3103_readreg(state, 0x24); ++ ++ tmp1 >>= 6; ++ tmp1 &= 0x03; ++ tmp2 >>= 6; ++ tmp2 &= 0x03; ++ ++ if((tmp1 == 0x00) && (tmp2 == 0x01)) ++ MClk_KHz = 144000; ++ else if((tmp1 == 0x00) && (tmp2 == 0x03)) ++ MClk_KHz = 72000; ++ else if((tmp1 == 0x01) && (tmp2 == 0x01)) ++ MClk_KHz = 115200; ++ else if((tmp1 == 0x02) && (tmp2 == 0x01)) ++ MClk_KHz = 96000; ++ else if((tmp1 == 0x03) && (tmp2 == 0x00)) ++ MClk_KHz = 192000; ++ else ++ return 0; ++ ++ if(input_datarate < 5200) /*Max. 2011-12-23 11:55*/ ++ input_datarate = 5200; ++ ++ if(input_datarate != 0) ++ divid_ratio = (u8)(MClk_KHz / input_datarate); ++ else ++ divid_ratio = 0xFF; ++ ++ if(divid_ratio > 128) ++ divid_ratio = 128; ++ ++ if(divid_ratio < 2) ++ divid_ratio = 2; ++ ++ tmp1 = (u8)(divid_ratio / 2); ++ tmp2 = (u8)(divid_ratio / 2); ++ ++ if((divid_ratio % 2) != 0) ++ tmp2 += 1; ++ ++ tmp1 -= 1; ++ tmp2 -= 1; ++ ++ tmp1 &= 0x3f; ++ tmp2 &= 0x3f; ++ ++ val = m88ds3103_readreg(state, 0xfe); ++ val &= 0xF0; ++ val |= (tmp2 >> 2) & 0x0f; ++ m88ds3103_writereg(state, 0xfe, val); ++ ++ val = (u8)((tmp2 & 0x03) << 6); ++ val |= tmp1; ++ m88ds3103_writereg(state, 0xea, val); ++ } ++ } else { ++ mod_fac = 2; ++ ++ switch(code_rate) { ++ case 4: input_datarate = locked_sym_rate_KSs*mod_fac/2/8; break; ++ case 3: input_datarate = locked_sym_rate_KSs*mod_fac*2/3/8; break; ++ case 2: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8; break; ++ case 1: input_datarate = locked_sym_rate_KSs*mod_fac*5/6/8; break; ++ case 0: input_datarate = locked_sym_rate_KSs*mod_fac*7/8/8; break; ++ default: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8; break; ++ } ++ ++ if(state->demod_id == DS3000_ID) ++ input_datarate = input_datarate * 115 / 100; ++ ++ if(input_datarate < 6857) {tmp1 = 7;tmp2 = 7;} //6.857MHz TS clock ++ else if(input_datarate < 7384) {tmp1 = 6;tmp2 = 7;} //7.384MHz TS clock ++ else if(input_datarate < 8000) {tmp1 = 6;tmp2 = 6;} //8MHz TS clock ++ else if(input_datarate < 8727) {tmp1 = 5;tmp2 = 6;} //8.727MHz TS clock ++ else if(input_datarate < 9600) {tmp1 = 5;tmp2 = 5;} //9.6MHz TS clock ++ else if(input_datarate < 10666) {tmp1 = 4;tmp2 = 5;} //10.666MHz TS clock ++ else if(input_datarate < 12000) {tmp1 = 4;tmp2 = 4;} //12MHz TS clock ++ else if(input_datarate < 13714) {tmp1 = 3;tmp2 = 4;} //13.714MHz TS clock ++ else if(input_datarate < 16000) {tmp1 = 3;tmp2 = 3;} //16MHz TS clock ++ else if(input_datarate < 19200) {tmp1 = 2;tmp2 = 3;} //19.2MHz TS clock ++ else {tmp1 = 2;tmp2 = 2;} //24MHz TS clock ++ ++ if(state->demod_id == DS3000_ID) { ++ val = m88ds3103_readreg(state, 0xfe); ++ val &= 0xc0; ++ val |= ((u8)((tmp1<<3) + tmp2)); ++ m88ds3103_writereg(state, 0xfe, val); ++ } else { ++ if(input_datarate < 5200) /*Max. 2011-12-23 11:55*/ ++ input_datarate = 5200; ++ ++ if(input_datarate != 0) ++ divid_ratio = (u8)(MClk_KHz / input_datarate); ++ else ++ divid_ratio = 0xFF; ++ ++ if(divid_ratio > 128) ++ divid_ratio = 128; ++ ++ if(divid_ratio < 2) ++ divid_ratio = 2; ++ ++ tmp1 = (u8)(divid_ratio / 2); ++ tmp2 = (u8)(divid_ratio / 2); ++ ++ if((divid_ratio % 2) != 0) ++ tmp2 += 1; ++ ++ tmp1 -= 1; ++ tmp2 -= 1; ++ ++ tmp1 &= 0x3f; ++ tmp2 &= 0x3f; ++ ++ val = m88ds3103_readreg(state, 0xfe); ++ val &= 0xF0; ++ val |= (tmp2 >> 2) & 0x0f; ++ m88ds3103_writereg(state, 0xfe, val); ++ ++ val = (u8)((tmp2 & 0x03) << 6); ++ val |= tmp1; ++ m88ds3103_writereg(state, 0xea, val); ++ } ++ } ++ return 0; ++} ++ ++static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 carrier_offset_khz) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ u16 value; ++ u8 val1,val2,data; ++ ++ dprintk("connect delivery system = %d\n", state->delivery_system); ++ ++ /* ds3000 global reset */ ++ m88ds3103_writereg(state, 0x07, 0x80); ++ m88ds3103_writereg(state, 0x07, 0x00); ++ /* ds3000 build-in uC reset */ ++ m88ds3103_writereg(state, 0xb2, 0x01); ++ /* ds3000 software reset */ ++ m88ds3103_writereg(state, 0x00, 0x01); ++ ++ switch (state->delivery_system) { ++ case SYS_DVBS: ++ /* initialise the demod in DVB-S mode */ ++ if(state->demod_id == DS3000_ID){ ++ m88ds3103_init_reg(state, ds3000_dvbs_init_tab, sizeof(ds3000_dvbs_init_tab)); ++ ++ value = m88ds3103_readreg(state, 0xfe); ++ value &= 0xc0; ++ value |= 0x1b; ++ m88ds3103_writereg(state, 0xfe, value); ++ ++ if(state->config->ci_mode) ++ val1 = 0x80; ++ else if(state->config->ts_mode) ++ val1 = 0x60; ++ else ++ val1 = 0x20; ++ m88ds3103_writereg(state, 0xfd, val1); ++ ++ }else if(state->demod_id == DS3103_ID){ ++ m88ds3103_init_reg(state, ds3103_dvbs_init_tab, sizeof(ds3103_dvbs_init_tab)); ++ ++ /* set ts clock */ ++ if(state->config->ci_mode == 2){ ++ val1 = 6; val2 = 6; ++ }else if(state->config->ts_mode == 0) { ++ val1 = 3; val2 = 3; ++ }else{ ++ val1 = 0; val2 = 0; ++ } ++ val1 -= 1; val2 -= 1; ++ val1 &= 0x3f; val2 &= 0x3f; ++ data = m88ds3103_readreg(state, 0xfe); ++ data &= 0xf0; ++ data |= (val2 >> 2) & 0x0f; ++ m88ds3103_writereg(state, 0xfe, data); ++ data = (val2 & 0x03) << 6; ++ data |= val1; ++ m88ds3103_writereg(state, 0xea, data); ++ ++ m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d)); ++ m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30)); ++ ++ /* set master clock */ ++ val1 = m88ds3103_readreg(state, 0x22); ++ val2 = m88ds3103_readreg(state, 0x24); ++ ++ val1 &= 0x3f; ++ val2 &= 0x3f; ++ val1 |= 0x80; ++ val2 |= 0x40; ++ ++ m88ds3103_writereg(state, 0x22, val1); ++ m88ds3103_writereg(state, 0x24, val2); ++ ++ if(state->config->ci_mode) ++ val1 = 0x03; ++ else if(state->config->ts_mode) ++ val1 = 0x06; ++ else ++ val1 = 0x42; ++ m88ds3103_writereg(state, 0xfd, val1); ++ } ++ break; ++ case SYS_DVBS2: ++ /* initialise the demod in DVB-S2 mode */ ++ if(state->demod_id == DS3000_ID){ ++ m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, sizeof(ds3000_dvbs2_init_tab)); ++ ++ if (c->symbol_rate >= 30000000) ++ m88ds3103_writereg(state, 0xfe, 0x54); ++ else ++ m88ds3103_writereg(state, 0xfe, 0x98); ++ ++ }else if(state->demod_id == DS3103_ID){ ++ m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, sizeof(ds3103_dvbs2_init_tab)); ++ ++ /* set ts clock */ ++ if(state->config->ci_mode == 2){ ++ val1 = 6; val2 = 6; ++ }else if(state->config->ts_mode == 0){ ++ val1 = 5; val2 = 4; ++ }else{ ++ val1 = 0; val2 = 0; ++ } ++ val1 -= 1; val2 -= 1; ++ val1 &= 0x3f; val2 &= 0x3f; ++ data = m88ds3103_readreg(state, 0xfe); ++ data &= 0xf0; ++ data |= (val2 >> 2) & 0x0f; ++ m88ds3103_writereg(state, 0xfe, data); ++ data = (val2 & 0x03) << 6; ++ data |= val1; ++ m88ds3103_writereg(state, 0xea, data); ++ ++ m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d)); ++ m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30)); ++ ++ /* set master clock */ ++ val1 = m88ds3103_readreg(state, 0x22); ++ val2 = m88ds3103_readreg(state, 0x24); ++ ++ val1 &= 0x3f; ++ val2 &= 0x3f; ++ if((state->config->ci_mode == 2) || (state->config->ts_mode == 1)){ ++ val1 |= 0x80; ++ val2 |= 0x40; ++ }else{ ++ if (c->symbol_rate >= 28000000){ ++ val1 |= 0xc0; ++ }else if (c->symbol_rate >= 18000000){ ++ val2 |= 0x40; ++ }else{ ++ val1 |= 0x80; ++ val2 |= 0x40; ++ } ++ } ++ m88ds3103_writereg(state, 0x22, val1); ++ m88ds3103_writereg(state, 0x24, val2); ++ } ++ ++ if(state->config->ci_mode) ++ val1 = 0x03; ++ else if(state->config->ts_mode) ++ val1 = 0x06; ++ else ++ val1 = 0x42; ++ m88ds3103_writereg(state, 0xfd, val1); ++ ++ break; ++ default: ++ return 1; ++ } ++ /* disable 27MHz clock output */ ++ m88ds3103_writereg(state, 0x29, 0x80); ++ /* enable ac coupling */ ++ m88ds3103_writereg(state, 0x25, 0x8a); ++ ++ if ((c->symbol_rate / 1000) <= 3000){ ++ m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 400*/ ++ m88ds3103_writereg(state, 0xc8, 0x20); ++ m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/ ++ m88ds3103_writereg(state, 0xc7, 0x00); ++ }else if((c->symbol_rate / 1000) <= 10000){ ++ m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 200*/ ++ m88ds3103_writereg(state, 0xc8, 0x10); ++ m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/ ++ m88ds3103_writereg(state, 0xc7, 0x00); ++ }else{ ++ m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 75*/ ++ m88ds3103_writereg(state, 0xc8, 0x06); ++ m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/ ++ m88ds3103_writereg(state, 0xc7, 0x00); ++ } ++ ++ m88ds3103_set_symrate(fe); ++ ++ m88ds3103_set_CCI(fe); ++ ++ m88ds3103_set_carrier_offset(fe, carrier_offset_khz); ++ ++ /* ds3000 out of software reset */ ++ m88ds3103_writereg(state, 0x00, 0x00); ++ /* start ds3000 build-in uC */ ++ m88ds3103_writereg(state, 0xb2, 0x00); ++ ++ return 0; ++} ++ ++static int m88ds3103_set_frontend(struct dvb_frontend *fe) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ struct dtv_frontend_properties *c = &fe->dtv_property_cache; ++ ++ int i; ++ fe_status_t status; ++ u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL; ++ s32 offset_khz, lpf_offset_KHz; ++ u16 value, ndiv, lpf_coeff; ++ u32 f3db, gdiv28, realFreq; ++ u8 RFgain; ++ ++ dprintk("%s() ", __func__); ++ dprintk("c frequency = %d\n", c->frequency); ++ dprintk("symbol rate = %d\n", c->symbol_rate); ++ dprintk("delivery system = %d\n", c->delivery_system); ++ ++ realFreq = c->frequency; ++ lpf_offset_KHz = 0; ++ if(c->symbol_rate < 5000000){ ++ lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz; ++ realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz; ++ } ++ ++ if (state->config->set_ts_params) ++ state->config->set_ts_params(fe, 0); ++ ++ div4 = 0; ++ RFgain = 0; ++ if(state->tuner_id == TS2022_ID){ ++ m88ds3103_tuner_writereg(state, 0x10, 0x0a); ++ m88ds3103_tuner_writereg(state, 0x11, 0x40); ++ if (realFreq < 1103000) { ++ m88ds3103_tuner_writereg(state, 0x10, 0x1b); ++ div4 = 1; ++ ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ; ++ }else { ++ ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ; ++ } ++ ndiv = ndiv + ndiv%2; ++ if(ndiv < 4095) ++ ndiv = ndiv - 1024; ++ else if (ndiv < 6143) ++ ndiv = ndiv + 1024; ++ else ++ ndiv = ndiv + 3072; ++ ++ m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8); ++ }else{ ++ m88ds3103_tuner_writereg(state, 0x10, 0x00); ++ if (realFreq < 1146000){ ++ m88ds3103_tuner_writereg(state, 0x10, 0x11); ++ div4 = 1; ++ ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ; ++ }else{ ++ m88ds3103_tuner_writereg(state, 0x10, 0x01); ++ ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ; ++ } ++ ndiv = ndiv + ndiv%2; ++ ndiv = ndiv - 1024; ++ m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f); ++ } ++ /* set pll */ ++ m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff); ++ m88ds3103_tuner_writereg(state, 0x03, 0x06); ++ m88ds3103_tuner_writereg(state, 0x51, 0x0f); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x10); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ ++ if(state->tuner_id == TS2022_ID){ ++ if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){ ++ msleep(5); ++ value = m88ds3103_tuner_readreg(state, 0x14); ++ value &= 0x7f; ++ if(value < 64){ ++ m88ds3103_tuner_writereg(state, 0x10, 0x82); ++ m88ds3103_tuner_writereg(state, 0x11, 0x6f); ++ ++ m88ds3103_tuner_writereg(state, 0x51, 0x0f); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x10); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ } ++ } ++ msleep(5); ++ value = m88ds3103_tuner_readreg(state, 0x14); ++ value &= 0x1f; ++ ++ if(value > 19){ ++ value = m88ds3103_tuner_readreg(state, 0x10); ++ value &= 0x1d; ++ m88ds3103_tuner_writereg(state, 0x10, value); ++ } ++ }else{ ++ msleep(5); ++ value = m88ds3103_tuner_readreg(state, 0x66); ++ changePLL = (((value & 0x80) >> 7) != div4); ++ ++ if(changePLL){ ++ m88ds3103_tuner_writereg(state, 0x10, 0x11); ++ div4 = 1; ++ ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ; ++ ndiv = ndiv + ndiv%2; ++ ndiv = ndiv - 1024; ++ ++ m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f); ++ m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff); ++ ++ m88ds3103_tuner_writereg(state, 0x51, 0x0f); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x10); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ } ++ } ++ /*set the RF gain*/ ++ if(state->tuner_id == TS2020_ID) ++ m88ds3103_tuner_writereg(state, 0x60, 0x79); ++ ++ m88ds3103_tuner_writereg(state, 0x51, 0x17); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x08); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ msleep(5); ++ ++ if(state->tuner_id == TS2020_ID){ ++ RFgain = m88ds3103_tuner_readreg(state, 0x3d); ++ RFgain &= 0x0f; ++ if(RFgain < 15){ ++ if(RFgain < 4) ++ RFgain = 0; ++ else ++ RFgain = RFgain -3; ++ value = ((RFgain << 3) | 0x01) & 0x79; ++ m88ds3103_tuner_writereg(state, 0x60, value); ++ m88ds3103_tuner_writereg(state, 0x51, 0x17); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x08); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ } ++ } ++ ++ /* set the LPF */ ++ if(state->tuner_id == TS2022_ID){ ++ m88ds3103_tuner_writereg(state, 0x25, 0x00); ++ m88ds3103_tuner_writereg(state, 0x27, 0x70); ++ m88ds3103_tuner_writereg(state, 0x41, 0x09); ++ m88ds3103_tuner_writereg(state, 0x08, 0x0b); ++ } ++ ++ f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000; ++ f3db += lpf_offset_KHz; ++ if (f3db < 7000) ++ f3db = 7000; ++ if (f3db > 40000) ++ f3db = 40000; ++ ++ gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000; ++ m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1b); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x04); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ msleep(5); ++ ++ value = m88ds3103_tuner_readreg(state, 0x26); ++ capCode = value & 0x3f; ++ if(state->tuner_id == TS2022_ID){ ++ m88ds3103_tuner_writereg(state, 0x41, 0x0d); ++ ++ m88ds3103_tuner_writereg(state, 0x51, 0x1b); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x04); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ ++ msleep(2); ++ ++ value = m88ds3103_tuner_readreg(state, 0x26); ++ value &= 0x3f; ++ value = (capCode + value) / 2; ++ } ++ else ++ value = capCode; ++ ++ gdiv28 = gdiv28 * 207 / (value * 2 + 151); ++ mlpf_max = gdiv28 * 135 / 100; ++ mlpf_min = gdiv28 * 78 / 100; ++ if (mlpf_max > 63) ++ mlpf_max = 63; ++ ++ if(state->tuner_id == TS2022_ID) ++ lpf_coeff = 3200; ++ else ++ lpf_coeff = 2766; ++ ++ nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000) + 1) / 2 ; ++ if (nlpf > 23) nlpf = 23; ++ if (nlpf < 1) nlpf = 1; ++ ++ lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2; ++ ++ if (lpf_mxdiv < mlpf_min){ ++ nlpf++; ++ lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2; ++ } ++ ++ if (lpf_mxdiv > mlpf_max) ++ lpf_mxdiv = mlpf_max; ++ ++ m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv); ++ m88ds3103_tuner_writereg(state, 0x06, nlpf); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1b); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x04); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ msleep(5); ++ ++ if(state->tuner_id == TS2022_ID){ ++ msleep(2); ++ value = m88ds3103_tuner_readreg(state, 0x26); ++ capCode = value & 0x3f; ++ ++ m88ds3103_tuner_writereg(state, 0x41, 0x09); ++ ++ m88ds3103_tuner_writereg(state, 0x51, 0x1b); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x04); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ ++ msleep(2); ++ value = m88ds3103_tuner_readreg(state, 0x26); ++ value &= 0x3f; ++ value = (capCode + value) / 2; ++ ++ value = value | 0x80; ++ m88ds3103_tuner_writereg(state, 0x25, value); ++ m88ds3103_tuner_writereg(state, 0x27, 0x30); ++ ++ m88ds3103_tuner_writereg(state, 0x08, 0x09); ++ } ++ ++ /* Set the BB gain */ ++ m88ds3103_tuner_writereg(state, 0x51, 0x1e); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x01); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ if(state->tuner_id == TS2020_ID){ ++ if(RFgain == 15){ ++ msleep(40); ++ value = m88ds3103_tuner_readreg(state, 0x21); ++ value &= 0x0f; ++ if(value < 3){ ++ m88ds3103_tuner_writereg(state, 0x60, 0x61); ++ m88ds3103_tuner_writereg(state, 0x51, 0x17); ++ m88ds3103_tuner_writereg(state, 0x51, 0x1f); ++ m88ds3103_tuner_writereg(state, 0x50, 0x08); ++ m88ds3103_tuner_writereg(state, 0x50, 0x00); ++ } ++ } ++ } ++ msleep(60); ++ ++ offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ ++ / (6 + 8) / (div4 + 1) / 2 - realFreq; ++ ++ m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz); ++ ++ for (i = 0; i < 30 ; i++) { ++ m88ds3103_read_status(fe, &status); ++ if (status & FE_HAS_LOCK){ ++ break; ++ } ++ msleep(20); ++ } ++ ++ if((status & FE_HAS_LOCK) == 0){ ++ state->delivery_system = (state->delivery_system == SYS_DVBS) ? SYS_DVBS2 : SYS_DVBS; ++ m88ds3103_demod_connect(fe, offset_khz); ++ ++ for (i = 0; i < 30 ; i++) { ++ m88ds3103_read_status(fe, &status); ++ if (status & FE_HAS_LOCK){ ++ break; ++ } ++ msleep(20); ++ } ++ } ++ ++ if (status & FE_HAS_LOCK){ ++ if(state->config->ci_mode == 2) ++ m88ds3103_set_clock_ratio(state); ++ if(state->config->start_ctrl){ ++ if(state->first_lock == 0){ ++ state->config->start_ctrl(fe); ++ state->first_lock = 1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int m88ds3103_tune(struct dvb_frontend *fe, ++ bool re_tune, ++ unsigned int mode_flags, ++ unsigned int *delay, ++ fe_status_t *status) ++{ ++ *delay = HZ / 5; ++ ++ dprintk("%s() ", __func__); ++ dprintk("re_tune = %d\n", re_tune); ++ ++ if (re_tune) { ++ int ret = m88ds3103_set_frontend(fe); ++ if (ret) ++ return ret; ++ } ++ ++ return m88ds3103_read_status(fe, status); ++} ++ ++static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe) ++{ ++ return DVBFE_ALGO_HW; ++} ++ ++ /* ++ * Power config will reset and load initial firmware if required ++ */ ++static int m88ds3103_initilaze(struct dvb_frontend *fe) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ int ret; ++ ++ dprintk("%s()\n", __func__); ++ /* hard reset */ ++ m88ds3103_writereg(state, 0x07, 0x80); ++ m88ds3103_writereg(state, 0x07, 0x00); ++ msleep(1); ++ ++ m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08)); ++ msleep(1); ++ ++ if(state->tuner_id == TS2020_ID){ ++ /* TS2020 init */ ++ m88ds3103_tuner_writereg(state, 0x42, 0x73); ++ msleep(2); ++ m88ds3103_tuner_writereg(state, 0x05, 0x01); ++ m88ds3103_tuner_writereg(state, 0x62, 0xb5); ++ m88ds3103_tuner_writereg(state, 0x07, 0x02); ++ m88ds3103_tuner_writereg(state, 0x08, 0x01); ++ } ++ else if(state->tuner_id == TS2022_ID){ ++ /* TS2022 init */ ++ m88ds3103_tuner_writereg(state, 0x62, 0x6c); ++ msleep(2); ++ m88ds3103_tuner_writereg(state, 0x42, 0x6c); ++ msleep(2); ++ m88ds3103_tuner_writereg(state, 0x7d, 0x9d); ++ m88ds3103_tuner_writereg(state, 0x7c, 0x9a); ++ m88ds3103_tuner_writereg(state, 0x7a, 0x76); ++ ++ m88ds3103_tuner_writereg(state, 0x3b, 0x01); ++ m88ds3103_tuner_writereg(state, 0x63, 0x88); ++ ++ m88ds3103_tuner_writereg(state, 0x61, 0x85); ++ m88ds3103_tuner_writereg(state, 0x22, 0x30); ++ m88ds3103_tuner_writereg(state, 0x30, 0x40); ++ m88ds3103_tuner_writereg(state, 0x20, 0x23); ++ m88ds3103_tuner_writereg(state, 0x24, 0x02); ++ m88ds3103_tuner_writereg(state, 0x12, 0xa0); ++ } ++ ++ if(state->demod_id == DS3103_ID){ ++ m88ds3103_writereg(state, 0x07, 0xe0); ++ m88ds3103_writereg(state, 0x07, 0x00); ++ msleep(1); ++ } ++ m88ds3103_writereg(state, 0xb2, 0x01); ++ ++ /* Load the firmware if required */ ++ ret = m88ds3103_load_firmware(fe); ++ if (ret != 0){ ++ printk(KERN_ERR "%s: Unable initialize firmware\n", __func__); ++ return ret; ++ } ++ if(state->demod_id == DS3103_ID){ ++ m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d)); ++ m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30)); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Initialise or wake up device ++ */ ++static int m88ds3103_initfe(struct dvb_frontend *fe) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ u8 val; ++ ++ dprintk("%s()\n", __func__); ++ ++ /* 1st step to wake up demod */ ++ m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08)); ++ m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04)); ++ m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23)); ++ ++ /* 2nd step to wake up tuner */ ++ val = m88ds3103_tuner_readreg(state, 0x00) & 0xff; ++ if((val & 0x01) == 0){ ++ m88ds3103_tuner_writereg(state, 0x00, 0x01); ++ msleep(50); ++ } ++ m88ds3103_tuner_writereg(state, 0x00, 0x03); ++ msleep(50); ++ ++ return 0; ++} ++ ++/* Put device to sleep */ ++static int m88ds3103_sleep(struct dvb_frontend *fe) ++{ ++ struct m88ds3103_state *state = fe->demodulator_priv; ++ ++ dprintk("%s()\n", __func__); ++ ++ /* 1st step to sleep tuner */ ++ m88ds3103_tuner_writereg(state, 0x00, 0x00); ++ ++ /* 2nd step to sleep demod */ ++ m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08)); ++ m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04)); ++ m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23)); ++ ++ ++ return 0; ++} ++ ++static struct dvb_frontend_ops m88ds3103_ops = { ++ .delsys = { SYS_DVBS, SYS_DVBS2}, ++ .info = { ++ .name = "Montage DS3103/TS2022", ++ .type = FE_QPSK, ++ .frequency_min = 950000, ++ .frequency_max = 2150000, ++ .frequency_stepsize = 1011, /* kHz for QPSK frontends */ ++ .frequency_tolerance = 5000, ++ .symbol_rate_min = 1000000, ++ .symbol_rate_max = 45000000, ++ .caps = FE_CAN_INVERSION_AUTO | ++ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | ++ FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | ++ FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | ++ FE_CAN_2G_MODULATION | ++ FE_CAN_QPSK | FE_CAN_RECOVER ++ }, ++ ++ .release = m88ds3103_release, ++ ++ .init = m88ds3103_initfe, ++ .sleep = m88ds3103_sleep, ++ .read_status = m88ds3103_read_status, ++ .read_ber = m88ds3103_read_ber, ++ .read_signal_strength = m88ds3103_read_signal_strength, ++ .read_snr = m88ds3103_read_snr, ++ .read_ucblocks = m88ds3103_read_ucblocks, ++ .set_tone = m88ds3103_set_tone, ++ .set_voltage = m88ds3103_set_voltage, ++ .diseqc_send_master_cmd = m88ds3103_send_diseqc_msg, ++ .diseqc_send_burst = m88ds3103_diseqc_send_burst, ++ .get_frontend_algo = m88ds3103_get_algo, ++ .tune = m88ds3103_tune, ++ .set_frontend = m88ds3103_set_frontend, ++}; ++ ++MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware"); ++MODULE_AUTHOR("Max nibble"); ++MODULE_LICENSE("GPL"); +diff -urN a/drivers/media/dvb/frontends/m88ds3103.h b/drivers/media/dvb/frontends/m88ds3103.h +--- a/drivers/media/dvb/frontends/m88ds3103.h 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/media/dvb/frontends/m88ds3103.h 2012-11-18 23:23:38.173155809 +0800 +@@ -0,0 +1,53 @@ ++/* ++ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver ++ ++ 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; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef M88DS3103_H ++#define M88DS3103_H ++ ++#include ++ ++struct m88ds3103_config { ++ /* the demodulator's i2c address */ ++ u8 demod_address; ++ u8 ci_mode; ++ u8 pin_ctrl; ++ u8 ts_mode; /* 0: Parallel, 1: Serial */ ++ ++ /* Set device param to start dma */ ++ int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); ++ /* Start to transfer data */ ++ int (*start_ctrl)(struct dvb_frontend *fe); ++ /* Set LNB voltage */ ++ int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); ++}; ++ ++#if defined(CONFIG_DVB_M88DS3103) || \ ++ (defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE)) ++extern struct dvb_frontend *m88ds3103_attach( ++ const struct m88ds3103_config *config, ++ struct i2c_adapter *i2c); ++#else ++static inline struct dvb_frontend *m88ds3103_attach( ++ const struct m88ds3103_config *config, ++ struct i2c_adapter *i2c) ++{ ++ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); ++ return NULL; ++} ++#endif /* CONFIG_DVB_M88DS3103 */ ++#endif /* M88DS3103_H */ +diff -urN a/drivers/media/dvb/frontends/m88ds3103_priv.h b/drivers/media/dvb/frontends/m88ds3103_priv.h +--- a/drivers/media/dvb/frontends/m88ds3103_priv.h 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/media/dvb/frontends/m88ds3103_priv.h 2012-11-18 23:23:42.173155920 +0800 +@@ -0,0 +1,403 @@ ++/* ++ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver ++ ++ 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; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef M88DS3103_PRIV_H ++#define M88DS3103_PRIV_H ++ ++#define FW_DOWN_SIZE 32 ++#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE) ++#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw" ++#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw" ++#define MT_FE_MCLK_KHZ 96000 /* in kHz */ ++#define MT_FE_CRYSTAL_KHZ 27000 /* in kHz */ ++#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000 ++#define DS3000_ID 0x3000 ++#define DS3103_ID 0x3103 ++#define TS2020_ID 0x2020 ++#define TS2022_ID 0x2022 ++#define UNKNOW_ID 0x0000 ++ ++struct m88ds3103_state { ++ struct i2c_adapter *i2c; ++ const struct m88ds3103_config *config; ++ ++ struct dvb_frontend frontend; ++ ++ u32 preBer; ++ u8 skip_fw_load; ++ u8 first_lock; /* The first time of signal lock */ ++ u16 demod_id; /* demod chip type */ ++ u16 tuner_id; /* tuner chip type */ ++ fe_delivery_system_t delivery_system; ++}; ++ ++/* For M88DS3103 demod dvbs mode.*/ ++static u8 ds3103_dvbs_init_tab[] = { ++ 0x23, 0x07, ++ 0x08, 0x03, ++ 0x0c, 0x02, ++ 0x21, 0x54, ++ 0x25, 0x82, ++ 0x27, 0x31, ++ 0x30, 0x08, ++ 0x31, 0x40, ++ 0x32, 0x32, ++ 0x33, 0x35, ++ 0x35, 0xff, ++ 0x3a, 0x00, ++ 0x37, 0x10, ++ 0x38, 0x10, ++ 0x39, 0x02, ++ 0x42, 0x60, ++ 0x4a, 0x80, ++ 0x4b, 0x04, ++ 0x4d, 0x91, ++ 0x5d, 0xc8, ++ 0x50, 0x36, ++ 0x51, 0x36, ++ 0x52, 0x36, ++ 0x53, 0x36, ++ 0x63, 0x0f, ++ 0x64, 0x30, ++ 0x65, 0x40, ++ 0x68, 0x26, ++ 0x69, 0x4c, ++ 0x70, 0x20, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x40, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x60, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x80, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0xa0, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x1f, ++ 0x76, 0x38, ++ 0x77, 0xa6, ++ 0x78, 0x0c, ++ 0x79, 0x80, ++ 0x7f, 0x14, ++ 0x7c, 0x00, ++ 0xae, 0x82, ++ 0x80, 0x64, ++ 0x81, 0x66, ++ 0x82, 0x44, ++ 0x85, 0x04, ++ 0xcd, 0xf4, ++ 0x90, 0x33, ++ 0xa0, 0x44, ++ 0xc0, 0x08, ++ 0xc3, 0x10, ++ 0xc4, 0x08, ++ 0xc5, 0xf0, ++ 0xc6, 0xff, ++ 0xc7, 0x00, ++ 0xc8, 0x1a, ++ 0xc9, 0x80, ++ 0xe0, 0xf8, ++ 0xe6, 0x8b, ++ 0xd0, 0x40, ++ 0xf8, 0x20, ++ 0xfa, 0x0f, ++ 0x00, 0x00, ++ 0xbd, 0x01, ++ 0xb8, 0x00, ++}; ++/* For M88DS3103 demod dvbs2 mode.*/ ++static u8 ds3103_dvbs2_init_tab[] = { ++ 0x23, 0x07, ++ 0x08, 0x07, ++ 0x0c, 0x02, ++ 0x21, 0x54, ++ 0x25, 0x82, ++ 0x27, 0x31, ++ 0x30, 0x08, ++ 0x32, 0x32, ++ 0x33, 0x35, ++ 0x35, 0xff, ++ 0x3a, 0x00, ++ 0x37, 0x10, ++ 0x38, 0x10, ++ 0x39, 0x02, ++ 0x42, 0x60, ++ 0x4a, 0x80, ++ 0x4b, 0x04, ++ 0x4d, 0x91, ++ 0x5d, 0xc8, ++ 0x50, 0x36, ++ 0x51, 0x36, ++ 0x52, 0x36, ++ 0x53, 0x36, ++ 0x63, 0x0f, ++ 0x64, 0x10, ++ 0x65, 0x20, ++ 0x68, 0x46, ++ 0x69, 0xcd, ++ 0x70, 0x20, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x40, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x60, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x80, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0xa0, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x1f, ++ 0x76, 0x38, ++ 0x77, 0xa6, ++ 0x78, 0x0c, ++ 0x79, 0x80, ++ 0x7f, 0x14, ++ 0x85, 0x08, ++ 0xcd, 0xf4, ++ 0x90, 0x33, ++ 0x86, 0x00, ++ 0x87, 0x0f, ++ 0x89, 0x00, ++ 0x8b, 0x44, ++ 0x8c, 0x66, ++ 0x9d, 0xc1, ++ 0x8a, 0x10, ++ 0xad, 0x40, ++ 0xa0, 0x44, ++ 0xc0, 0x08, ++ 0xc1, 0x10, ++ 0xc2, 0x08, ++ 0xc3, 0x10, ++ 0xc4, 0x08, ++ 0xc5, 0xf0, ++ 0xc6, 0xff, ++ 0xc7, 0x00, ++ 0xc8, 0x1a, ++ 0xc9, 0x80, ++ 0xca, 0x23, ++ 0xcb, 0x24, ++ 0xcc, 0xf4, ++ 0xce, 0x74, ++ 0x00, 0x00, ++ 0xbd, 0x01, ++ 0xb8, 0x00, ++}; ++ ++/* For M88DS3000 demod dvbs mode.*/ ++static u8 ds3000_dvbs_init_tab[] = { ++ 0x23, 0x05, ++ 0x08, 0x03, ++ 0x0c, 0x02, ++ 0x21, 0x54, ++ 0x25, 0x82, ++ 0x27, 0x31, ++ 0x30, 0x08, ++ 0x31, 0x40, ++ 0x32, 0x32, ++ 0x33, 0x35, ++ 0x35, 0xff, ++ 0x3a, 0x00, ++ 0x37, 0x10, ++ 0x38, 0x10, ++ 0x39, 0x02, ++ 0x42, 0x60, ++ 0x4a, 0x40, ++ 0x4b, 0x04, ++ 0x4d, 0x91, ++ 0x5d, 0xc8, ++ 0x50, 0x77, ++ 0x51, 0x77, ++ 0x52, 0x36, ++ 0x53, 0x36, ++ 0x56, 0x01, ++ 0x63, 0x47, ++ 0x64, 0x30, ++ 0x65, 0x40, ++ 0x68, 0x26, ++ 0x69, 0x4c, ++ 0x70, 0x20, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x40, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x60, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x80, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0xa0, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x1f, ++ 0x76, 0x00, ++ 0x77, 0xd1, ++ 0x78, 0x0c, ++ 0x79, 0x80, ++ 0x7f, 0x04, ++ 0x7c, 0x00, ++ 0x80, 0x86, ++ 0x81, 0xa6, ++ 0x85, 0x04, ++ 0xcd, 0xf4, ++ 0x90, 0x33, ++ 0xa0, 0x44, ++ 0xc0, 0x18, ++ 0xc3, 0x10, ++ 0xc4, 0x08, ++ 0xc5, 0x80, ++ 0xc6, 0x80, ++ 0xc7, 0x0a, ++ 0xc8, 0x1a, ++ 0xc9, 0x80, ++ 0xfe, 0xb6, ++ 0xe0, 0xf8, ++ 0xe6, 0x8b, ++ 0xd0, 0x40, ++ 0xf8, 0x20, ++ 0xfa, 0x0f, ++ 0xad, 0x20, ++ 0xae, 0x07, ++ 0xb8, 0x00, ++}; ++ ++/* For M88DS3000 demod dvbs2 mode.*/ ++static u8 ds3000_dvbs2_init_tab[] = { ++ 0x23, 0x0f, ++ 0x08, 0x07, ++ 0x0c, 0x02, ++ 0x21, 0x54, ++ 0x25, 0x82, ++ 0x27, 0x31, ++ 0x30, 0x08, ++ 0x31, 0x32, ++ 0x32, 0x32, ++ 0x33, 0x35, ++ 0x35, 0xff, ++ 0x3a, 0x00, ++ 0x37, 0x10, ++ 0x38, 0x10, ++ 0x39, 0x02, ++ 0x42, 0x60, ++ 0x4a, 0x80, ++ 0x4b, 0x04, ++ 0x4d, 0x91, ++ 0x5d, 0x88, ++ 0x50, 0x36, ++ 0x51, 0x36, ++ 0x52, 0x36, ++ 0x53, 0x36, ++ 0x63, 0x60, ++ 0x64, 0x10, ++ 0x65, 0x10, ++ 0x68, 0x04, ++ 0x69, 0x29, ++ 0x70, 0x20, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x40, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x60, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x80, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0xa0, ++ 0x71, 0x70, ++ 0x72, 0x04, ++ 0x73, 0x00, ++ 0x70, 0x1f, ++ 0xa0, 0x44, ++ 0xc0, 0x08, ++ 0xc1, 0x10, ++ 0xc2, 0x08, ++ 0xc3, 0x10, ++ 0xc4, 0x08, ++ 0xc5, 0xf0, ++ 0xc6, 0xf0, ++ 0xc7, 0x0a, ++ 0xc8, 0x1a, ++ 0xc9, 0x80, ++ 0xca, 0x23, ++ 0xcb, 0x24, ++ 0xce, 0x74, ++ 0x56, 0x01, ++ 0x90, 0x03, ++ 0x76, 0x80, ++ 0x77, 0x42, ++ 0x78, 0x0a, ++ 0x79, 0x80, ++ 0xad, 0x40, ++ 0xae, 0x07, ++ 0x7f, 0xd4, ++ 0x7c, 0x00, ++ 0x80, 0xa8, ++ 0x81, 0xda, ++ 0x7c, 0x01, ++ 0x80, 0xda, ++ 0x81, 0xec, ++ 0x7c, 0x02, ++ 0x80, 0xca, ++ 0x81, 0xeb, ++ 0x7c, 0x03, ++ 0x80, 0xba, ++ 0x81, 0xdb, ++ 0x85, 0x08, ++ 0x86, 0x00, ++ 0x87, 0x02, ++ 0x89, 0x80, ++ 0x8b, 0x44, ++ 0x8c, 0xaa, ++ 0x8a, 0x10, ++ 0xba, 0x00, ++ 0xf5, 0x04, ++ 0xd2, 0x32, ++ 0xb8, 0x00, ++}; ++ ++#endif /* M88DS3103_PRIV_H */ +diff -urN a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile +--- a/drivers/media/dvb/frontends/Makefile 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/dvb/frontends/Makefile 2012-11-18 23:23:46.929156046 +0800 +@@ -102,4 +102,7 @@ + obj-$(CONFIG_DVB_RTL2832) += rtl2832.o + obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o + obj-$(CONFIG_DVB_AF9033) += af9033.o ++obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o ++obj-$(CONFIG_DVB_M88DC2800) += m88dc2800.o ++ + +diff -urN a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +--- a/drivers/media/rc/keymaps/Makefile 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/rc/keymaps/Makefile 2012-11-18 23:24:05.477156546 +0800 +@@ -27,6 +27,7 @@ + rc-dm1105-nec.o \ + rc-dntv-live-dvb-t.o \ + rc-dntv-live-dvbt-pro.o \ ++ rc-dvbsky.o \ + rc-em-terratec.o \ + rc-encore-enltv2.o \ + rc-encore-enltv.o \ +diff -urN a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c +--- a/drivers/media/rc/keymaps/rc-dvbsky.c 1970-01-01 08:00:00.000000000 +0800 ++++ b/drivers/media/rc/keymaps/rc-dvbsky.c 2012-11-18 23:24:09.673156652 +0800 +@@ -0,0 +1,78 @@ ++/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers ++ * ++ * keymap imported from ir-keymaps.c ++ * ++ * ++ * Copyright (c) 2010-2011 by Mauro Carvalho Chehab ++ * ++ * 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; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++/* ++ * This table contains the complete RC5 code, instead of just the data part ++ */ ++ ++static struct rc_map_table rc5_dvbsky[] = { ++ { 0x0000, KEY_0 }, ++ { 0x0001, KEY_1 }, ++ { 0x0002, KEY_2 }, ++ { 0x0003, KEY_3 }, ++ { 0x0004, KEY_4 }, ++ { 0x0005, KEY_5 }, ++ { 0x0006, KEY_6 }, ++ { 0x0007, KEY_7 }, ++ { 0x0008, KEY_8 }, ++ { 0x0009, KEY_9 }, ++ { 0x000a, KEY_MUTE }, ++ { 0x000d, KEY_OK }, ++ { 0x000b, KEY_STOP }, ++ { 0x000c, KEY_EXIT }, ++ { 0x000e, KEY_CAMERA }, /*Snap shot*/ ++ { 0x000f, KEY_SUBTITLE }, /*PIP*/ ++ { 0x0010, KEY_VOLUMEUP }, ++ { 0x0011, KEY_VOLUMEDOWN }, ++ { 0x0012, KEY_FAVORITES }, ++ { 0x0013, KEY_LIST }, /*Info*/ ++ { 0x0016, KEY_PAUSE }, ++ { 0x0017, KEY_PLAY }, ++ { 0x001f, KEY_RECORD }, ++ { 0x0020, KEY_CHANNELDOWN }, ++ { 0x0021, KEY_CHANNELUP }, ++ { 0x0025, KEY_POWER2 }, ++ { 0x0026, KEY_REWIND }, ++ { 0x0027, KEY_FASTFORWARD }, ++ { 0x0029, KEY_LAST }, ++ { 0x002b, KEY_MENU }, ++ { 0x002c, KEY_EPG }, ++ { 0x002d, KEY_ZOOM }, ++}; ++ ++static struct rc_map_list rc5_dvbsky_map = { ++ .map = { ++ .scan = rc5_dvbsky, ++ .size = ARRAY_SIZE(rc5_dvbsky), ++ .rc_type = RC_TYPE_RC5, ++ .name = RC_MAP_DVBSKY, ++ } ++}; ++ ++static int __init init_rc_map_rc5_dvbsky(void) ++{ ++ return rc_map_register(&rc5_dvbsky_map); ++} ++ ++static void __exit exit_rc_map_rc5_dvbsky(void) ++{ ++ rc_map_unregister(&rc5_dvbsky_map); ++} ++ ++module_init(init_rc_map_rc5_dvbsky) ++module_exit(exit_rc_map_rc5_dvbsky) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mauro Carvalho Chehab "); +diff -urN a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c +--- a/drivers/media/video/cx23885/cimax2.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cimax2.c 2012-11-18 23:24:25.949157092 +0800 +@@ -412,7 +412,7 @@ + return state->status; + } + +-int netup_ci_init(struct cx23885_tsport *port) ++int netup_ci_init(struct cx23885_tsport *port, bool isDVBSky) + { + struct netup_ci_state *state; + u8 cimax_init[34] = { +@@ -461,6 +461,11 @@ + goto err; + } + ++ if(isDVBSky) { ++ cimax_init[32] = 0x22; ++ cimax_init[33] = 0x00; ++ } ++ + port->port_priv = state; + + switch (port->nr) { +@@ -534,3 +539,19 @@ + dvb_ca_en50221_release(&state->ca); + kfree(state); + } ++ ++/* CI irq handler for DVBSky board*/ ++int dvbsky_ci_slot_status(struct cx23885_dev *dev) ++{ ++ struct cx23885_tsport *port = NULL; ++ struct netup_ci_state *state = NULL; ++ ++ ci_dbg_print("%s:\n", __func__); ++ ++ port = &dev->ts1; ++ state = port->port_priv; ++ schedule_work(&state->work); ++ ci_dbg_print("%s: Wakeup CI0\n", __func__); ++ ++ return 1; ++} +diff -urN a/drivers/media/video/cx23885/cimax2.h b/drivers/media/video/cx23885/cimax2.h +--- a/drivers/media/video/cx23885/cimax2.h 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cimax2.h 2012-11-18 23:24:32.629157268 +0800 +@@ -41,7 +41,9 @@ + extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status); + extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, + int slot, int open); +-extern int netup_ci_init(struct cx23885_tsport *port); ++extern int netup_ci_init(struct cx23885_tsport *port, bool isDVBSky); + extern void netup_ci_exit(struct cx23885_tsport *port); + ++extern int dvbsky_ci_slot_status(struct cx23885_dev *dev); ++ + #endif +diff -urN a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c +--- a/drivers/media/video/cx23885/cx23885-cards.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cx23885-cards.c 2012-11-18 23:24:41.985157518 +0800 +@@ -564,7 +564,30 @@ + [CX23885_BOARD_TEVII_S471] = { + .name = "TeVii S471", + .portb = CX23885_MPEG_DVB, +- } ++ }, ++ [CX23885_BOARD_BST_PS8512] = { ++ .name = "Bestunar PS8512", ++ .portb = CX23885_MPEG_DVB, ++ }, ++ [CX23885_BOARD_DVBSKY_S950] = { ++ .name = "DVBSKY S950", ++ .portb = CX23885_MPEG_DVB, ++ }, ++ [CX23885_BOARD_DVBSKY_S952] = { ++ .name = "DVBSKY S952", ++ .portb = CX23885_MPEG_DVB, ++ .portc = CX23885_MPEG_DVB, ++ }, ++ [CX23885_BOARD_DVBSKY_S950_CI] = { ++ .ci_type = 3, ++ .name = "DVBSKY S950CI DVB-S2 CI", ++ .portb = CX23885_MPEG_DVB, ++ }, ++ [CX23885_BOARD_DVBSKY_C2800E_CI] = { ++ .ci_type = 3, ++ .name = "DVBSKY C2800E DVB-C CI", ++ .portb = CX23885_MPEG_DVB, ++ }, + }; + const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); + +@@ -776,6 +799,26 @@ + .subvendor = 0xd471, + .subdevice = 0x9022, + .card = CX23885_BOARD_TEVII_S471, ++ }, { ++ .subvendor = 0x14f1, ++ .subdevice = 0x8512, ++ .card = CX23885_BOARD_BST_PS8512, ++ }, { ++ .subvendor = 0x4254, ++ .subdevice = 0x0950, ++ .card = CX23885_BOARD_DVBSKY_S950, ++ }, { ++ .subvendor = 0x4254, ++ .subdevice = 0x0952, ++ .card = CX23885_BOARD_DVBSKY_S952, ++ }, { ++ .subvendor = 0x4254, ++ .subdevice = 0x950C, ++ .card = CX23885_BOARD_DVBSKY_S950_CI, ++ }, { ++ .subvendor = 0x4254, ++ .subdevice = 0x2800, ++ .card = CX23885_BOARD_DVBSKY_C2800E_CI, + }, + }; + const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); +@@ -1288,9 +1331,83 @@ + /* enable irq */ + cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ + break; ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_BST_PS8512: ++ cx23885_gpio_enable(dev, GPIO_2, 1); ++ cx23885_gpio_clear(dev, GPIO_2); ++ msleep(100); ++ cx23885_gpio_set(dev, GPIO_2); ++ break; ++ case CX23885_BOARD_DVBSKY_S952: ++ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */ ++ ++ cx23885_gpio_enable(dev, GPIO_2, 1); ++ cx23885_gpio_enable(dev, GPIO_11, 1); ++ ++ cx23885_gpio_clear(dev, GPIO_2); ++ cx23885_gpio_clear(dev, GPIO_11); ++ msleep(100); ++ cx23885_gpio_set(dev, GPIO_2); ++ cx23885_gpio_set(dev, GPIO_11); ++ break; ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: ++ /* GPIO-0 INTA from CiMax, input ++ GPIO-1 reset CiMax, output, high active ++ GPIO-2 reset demod, output, low active ++ GPIO-3 to GPIO-10 data/addr for CAM ++ GPIO-11 ~CS0 to CiMax1 ++ GPIO-12 ~CS1 to CiMax2 ++ GPIO-13 ADL0 load LSB addr ++ GPIO-14 ADL1 load MSB addr ++ GPIO-15 ~RDY from CiMax ++ GPIO-17 ~RD to CiMax ++ GPIO-18 ~WR to CiMax ++ */ ++ cx_set(GP0_IO, 0x00060002); /* GPIO 1/2 as output */ ++ cx_clear(GP0_IO, 0x00010004); /*GPIO 0 as input*/ ++ mdelay(100);/* reset delay */ ++ cx_set(GP0_IO, 0x00060004); /* GPIO as out, reset high */ ++ cx_clear(GP0_IO, 0x00010002); ++ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */ ++ /* GPIO-15 IN as ~ACK, rest as OUT */ ++ cx_write(MC417_OEN, 0x00001000); ++ /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */ ++ cx_write(MC417_RWD, 0x0000c300); ++ /* enable irq */ ++ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ ++ break; + } + } + ++static int cx23885_ir_patch(struct i2c_adapter *i2c, u8 reg, u8 mask) ++{ ++ struct i2c_msg msgs[2]; ++ u8 tx_buf[2], rx_buf[1]; ++ /* Write register address */ ++ tx_buf[0] = reg; ++ msgs[0].addr = 0x4c; ++ msgs[0].flags = 0; ++ msgs[0].len = 1; ++ msgs[0].buf = (char *) tx_buf; ++ /* Read data from register */ ++ msgs[1].addr = 0x4c; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = 1; ++ msgs[1].buf = (char *) rx_buf; ++ ++ i2c_transfer(i2c, msgs, 2); ++ ++ tx_buf[0] = reg; ++ tx_buf[1] = rx_buf[0] | mask; ++ msgs[0].addr = 0x4c; ++ msgs[0].flags = 0; ++ msgs[0].len = 2; ++ msgs[0].buf = (char *) tx_buf; ++ ++ return i2c_transfer(i2c, msgs, 1); ++} ++ + int cx23885_ir_init(struct cx23885_dev *dev) + { + static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = { +@@ -1374,6 +1491,22 @@ + v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, + ir_rx_pin_cfg_count, ir_rx_pin_cfg); + break; ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S952: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: ++ dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); ++ if (dev->sd_ir == NULL) { ++ ret = -ENODEV; ++ break; ++ } ++ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, ++ ir_rx_pin_cfg_count, ir_rx_pin_cfg); ++ ++ cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x1f,0x80); ++ cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x23,0x80); ++ break; + case CX23885_BOARD_HAUPPAUGE_HVR1250: + if (!enable_885_ir) + break; +@@ -1405,6 +1538,11 @@ + break; + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_HAUPPAUGE_HVR1250: ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S952: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: + cx23885_irq_remove(dev, PCI_MSK_AV_CORE); + /* sd_ir is a duplicate pointer to the AV Core, just clear it */ + dev->sd_ir = NULL; +@@ -1448,6 +1586,11 @@ + break; + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_HAUPPAUGE_HVR1250: ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S952: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: + if (dev->sd_ir) + cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE); + break; +@@ -1533,6 +1676,10 @@ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_TEVII_S471: + case CX23885_BOARD_DVBWORLD_2005: +@@ -1564,6 +1711,14 @@ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; ++ case CX23885_BOARD_DVBSKY_S952: ++ ts1->gen_ctrl_val = 0x5; /* Parallel */ ++ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ++ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; ++ ts2->gen_ctrl_val = 0xe; /* Serial bus + punctured clock */ ++ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ++ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; ++ break; + case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: +@@ -1619,6 +1774,11 @@ + case CX23885_BOARD_MPX885: + case CX23885_BOARD_MYGICA_X8507: + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S952: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: + dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[2].i2c_adap, + "cx25840", 0x88 >> 1, NULL); +diff -urN a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c +--- a/drivers/media/video/cx23885/cx23885-core.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cx23885-core.c 2012-11-18 23:24:52.437157796 +0800 +@@ -1911,6 +1911,10 @@ + (pci_status & PCI_MSK_GPIO0)) + handled += altera_ci_irq(dev); + ++ if (cx23885_boards[dev->board].ci_type == 3 && ++ (pci_status & PCI_MSK_GPIO0)) ++ handled += dvbsky_ci_slot_status(dev); ++ + if (ts1_status) { + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + handled += cx23885_irq_ts(ts1, ts1_status); +@@ -2146,6 +2150,8 @@ + cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0); + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: + cx23885_irq_add_enable(dev, PCI_MSK_GPIO0); + break; + } +diff -urN a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c +--- a/drivers/media/video/cx23885/cx23885-dvb.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cx23885-dvb.c 2012-11-18 23:24:57.401157930 +0800 +@@ -51,6 +51,8 @@ + #include "stv6110.h" + #include "lnbh24.h" + #include "cx24116.h" ++#include "m88ds3103.h" ++#include "m88dc2800.h" + #include "cimax2.h" + #include "lgs8gxx.h" + #include "netup-eeprom.h" +@@ -489,6 +491,42 @@ + .if_khz = 5380, + }; + ++/* bestunar single dvb-s2 */ ++static struct m88ds3103_config bst_ds3103_config = { ++ .demod_address = 0x68, ++ .ci_mode = 0, ++ .pin_ctrl = 0x82, ++ .ts_mode = 0, ++ .set_voltage = bst_set_voltage, ++}; ++/* DVBSKY dual dvb-s2 */ ++static struct m88ds3103_config dvbsky_ds3103_config_pri = { ++ .demod_address = 0x68, ++ .ci_mode = 0, ++ .pin_ctrl = 0x82, ++ .ts_mode = 0, ++ .set_voltage = bst_set_voltage, ++}; ++static struct m88ds3103_config dvbsky_ds3103_config_sec = { ++ .demod_address = 0x68, ++ .ci_mode = 0, ++ .pin_ctrl = 0x82, ++ .ts_mode = 1, ++ .set_voltage = dvbsky_set_voltage_sec, ++}; ++ ++static struct m88ds3103_config dvbsky_ds3103_ci_config = { ++ .demod_address = 0x68, ++ .ci_mode = 2, ++ .pin_ctrl = 0x82, ++ .ts_mode = 0, ++}; ++ ++static struct m88dc2800_config dvbsky_dc2800_config = { ++ .demod_address = 0x1c, ++ .ts_mode = 3, ++}; ++ + static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) + { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; +@@ -1186,6 +1224,47 @@ + &tevii_ds3000_config, + &i2c_bus->i2c_adap); + break; ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ i2c_bus = &dev->i2c_bus[1]; ++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach, ++ &bst_ds3103_config, ++ &i2c_bus->i2c_adap); ++ break; ++ ++ case CX23885_BOARD_DVBSKY_S952: ++ switch (port->nr) { ++ /* port B */ ++ case 1: ++ i2c_bus = &dev->i2c_bus[1]; ++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach, ++ &dvbsky_ds3103_config_pri, ++ &i2c_bus->i2c_adap); ++ break; ++ /* port C */ ++ case 2: ++ i2c_bus = &dev->i2c_bus[0]; ++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach, ++ &dvbsky_ds3103_config_sec, ++ &i2c_bus->i2c_adap); ++ break; ++ } ++ break; ++ ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ i2c_bus = &dev->i2c_bus[1]; ++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach, ++ &dvbsky_ds3103_ci_config, ++ &i2c_bus->i2c_adap); ++ break; ++ ++ case CX23885_BOARD_DVBSKY_C2800E_CI: ++ i2c_bus = &dev->i2c_bus[1]; ++ fe0->dvb.frontend = dvb_attach(m88dc2800_attach, ++ &dvbsky_dc2800_config, ++ &i2c_bus->i2c_adap); ++ break; ++ + default: + printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " + " isn't supported yet\n", +@@ -1234,7 +1313,7 @@ + printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", + port->nr, port->frontends.adapter.proposed_mac); + +- netup_ci_init(port); ++ netup_ci_init(port, false); + break; + } + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { +@@ -1261,6 +1340,40 @@ + memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); + break; + } ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S952:{ ++ u8 eeprom[256]; /* 24C02 i2c eeprom */ ++ ++ if(port->nr > 2) ++ break; ++ ++ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; ++ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); ++ printk(KERN_INFO "DVBSKY PCIe MAC= %pM\n", eeprom + 0xc0+(port->nr-1)*8); ++ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 + ++ (port->nr-1)*8, 6); ++ break; ++ } ++ case CX23885_BOARD_DVBSKY_S950_CI: { ++ u8 eeprom[256]; /* 24C02 i2c eeprom */ ++ ++ if(port->nr > 2) ++ break; ++ ++ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; ++ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); ++ printk(KERN_INFO "DVBSKY PCIe MAC= %pM\n", eeprom + 0xc0+(port->nr-1)*8); ++ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 + ++ (port->nr-1)*8, 6); ++ ++ netup_ci_init(port, true); ++ break; ++ } ++ case CX23885_BOARD_DVBSKY_C2800E_CI: { ++ netup_ci_init(port, true); ++ break; ++ } + } + + return ret; +@@ -1343,6 +1456,8 @@ + + switch (port->dev->board) { + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: + netup_ci_exit(port); + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: +diff -urN a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/video/cx23885/cx23885-f300.c +--- a/drivers/media/video/cx23885/cx23885-f300.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cx23885-f300.c 2012-11-18 23:25:02.869158076 +0800 +@@ -175,3 +175,58 @@ + + return f300_xfer(fe, buf); + } ++ ++/* bst control */ ++int bst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) ++{ ++ struct cx23885_tsport *port = fe->dvb->priv; ++ struct cx23885_dev *dev = port->dev; ++ ++ cx23885_gpio_enable(dev, GPIO_1, 1); ++ cx23885_gpio_enable(dev, GPIO_0, 1); ++ ++ switch (voltage) { ++ case SEC_VOLTAGE_13: ++ cx23885_gpio_set(dev, GPIO_1); ++ cx23885_gpio_clear(dev, GPIO_0); ++ break; ++ case SEC_VOLTAGE_18: ++ cx23885_gpio_set(dev, GPIO_1); ++ cx23885_gpio_set(dev, GPIO_0); ++ break; ++ case SEC_VOLTAGE_OFF: ++ cx23885_gpio_clear(dev, GPIO_1); ++ cx23885_gpio_clear(dev, GPIO_0); ++ break; ++ } ++ ++ ++ return 0; ++} ++ ++int dvbsky_set_voltage_sec(struct dvb_frontend *fe, fe_sec_voltage_t voltage) ++{ ++ struct cx23885_tsport *port = fe->dvb->priv; ++ struct cx23885_dev *dev = port->dev; ++ ++ cx23885_gpio_enable(dev, GPIO_12, 1); ++ cx23885_gpio_enable(dev, GPIO_13, 1); ++ ++ switch (voltage) { ++ case SEC_VOLTAGE_13: ++ cx23885_gpio_set(dev, GPIO_13); ++ cx23885_gpio_clear(dev, GPIO_12); ++ break; ++ case SEC_VOLTAGE_18: ++ cx23885_gpio_set(dev, GPIO_13); ++ cx23885_gpio_set(dev, GPIO_12); ++ break; ++ case SEC_VOLTAGE_OFF: ++ cx23885_gpio_clear(dev, GPIO_13); ++ cx23885_gpio_clear(dev, GPIO_12); ++ break; ++ } ++ ++ ++ return 0; ++} +\ No newline at end of file +diff -urN a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/video/cx23885/cx23885-f300.h +--- a/drivers/media/video/cx23885/cx23885-f300.h 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cx23885-f300.h 2012-11-18 23:25:22.493158602 +0800 +@@ -1,2 +1,8 @@ ++extern int dvbsky_set_voltage_sec(struct dvb_frontend *fe, ++ fe_sec_voltage_t voltage); ++ ++extern int bst_set_voltage(struct dvb_frontend *fe, ++ fe_sec_voltage_t voltage); ++ + extern int f300_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); +diff -urN a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h +--- a/drivers/media/video/cx23885/cx23885.h 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cx23885.h 2012-11-18 23:24:37.021157384 +0800 +@@ -90,6 +90,11 @@ + #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34 + #define CX23885_BOARD_TEVII_S471 35 + #define CX23885_BOARD_HAUPPAUGE_HVR1255_22111 36 ++#define CX23885_BOARD_BST_PS8512 37 ++#define CX23885_BOARD_DVBSKY_S952 38 ++#define CX23885_BOARD_DVBSKY_S950 39 ++#define CX23885_BOARD_DVBSKY_S950_CI 40 ++#define CX23885_BOARD_DVBSKY_C2800E_CI 41 + + #define GPIO_0 0x00000001 + #define GPIO_1 0x00000002 +@@ -228,7 +233,7 @@ + */ + u32 clk_freq; + struct cx23885_input input[MAX_CX23885_INPUT]; +- int ci_type; /* for NetUP */ ++ int ci_type; /* 1 and 2 for NetUP, 3 for DVBSky. */ + /* Force bottom field first during DMA (888 workaround) */ + u32 force_bff; + }; +diff -urN a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c +--- a/drivers/media/video/cx23885/cx23885-input.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/cx23885-input.c 2012-11-18 23:25:34.089158915 +0800 +@@ -87,6 +87,11 @@ + case CX23885_BOARD_HAUPPAUGE_HVR1290: + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_HAUPPAUGE_HVR1250: ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S952: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: + /* + * The only boards we handle right now. However other boards + * using the CX2388x integrated IR controller should be similar +@@ -138,6 +143,11 @@ + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: + case CX23885_BOARD_HAUPPAUGE_HVR1250: ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S952: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: + /* + * The IR controller on this board only returns pulse widths. + * Any other mode setting will fail to set up the device. +@@ -279,6 +289,17 @@ + /* A guess at the remote */ + rc_map = RC_MAP_TEVII_NEC; + break; ++ case CX23885_BOARD_BST_PS8512: ++ case CX23885_BOARD_DVBSKY_S950: ++ case CX23885_BOARD_DVBSKY_S952: ++ case CX23885_BOARD_DVBSKY_S950_CI: ++ case CX23885_BOARD_DVBSKY_C2800E_CI: ++ /* Integrated CX2388[58] IR controller */ ++ driver_type = RC_DRIVER_IR_RAW; ++ allowed_protos = RC_TYPE_ALL; ++ /* A guess at the remote */ ++ rc_map = RC_MAP_DVBSKY; ++ break; + default: + return -ENODEV; + } +diff -urN a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig +--- a/drivers/media/video/cx23885/Kconfig 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx23885/Kconfig 2012-11-18 23:25:39.221159051 +0800 +@@ -20,6 +20,8 @@ + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE ++ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE ++ select DVB_M88DC2800 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STV0367 if !DVB_FE_CUSTOMISE +diff -urN a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c +--- a/drivers/media/video/cx88/cx88-cards.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx88/cx88-cards.c 2012-11-18 23:26:46.493160850 +0800 +@@ -2309,6 +2309,18 @@ + } }, + .mpeg = CX88_MPEG_DVB, + }, ++ [CX88_BOARD_BST_PS8312] = { ++ .name = "Bestunar PS8312 DVB-S/S2", ++ .tuner_type = UNSET, ++ .radio_type = UNSET, ++ .tuner_addr = ADDR_UNSET, ++ .radio_addr = ADDR_UNSET, ++ .input = {{ ++ .type = CX88_VMUX_DVB, ++ .vmux = 0, ++ } }, ++ .mpeg = CX88_MPEG_DVB, ++ }, + }; + + /* ------------------------------------------------------------------ */ +@@ -2813,6 +2825,10 @@ + .subvendor = 0x1822, + .subdevice = 0x0023, + .card = CX88_BOARD_TWINHAN_VP1027_DVBS, ++ }, { ++ .subvendor = 0x14f1, ++ .subdevice = 0x8312, ++ .card = CX88_BOARD_BST_PS8312, + }, + }; + +@@ -3547,6 +3563,12 @@ + cx_write(MO_SRST_IO, 1); + msleep(100); + break; ++ case CX88_BOARD_BST_PS8312: ++ cx_write(MO_GP1_IO, 0x808000); ++ msleep(100); ++ cx_write(MO_GP1_IO, 0x808080); ++ msleep(100); ++ break; + } /*end switch() */ + + +diff -urN a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c +--- a/drivers/media/video/cx88/cx88-dvb.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx88/cx88-dvb.c 2012-11-18 23:26:51.733160994 +0800 +@@ -54,6 +54,7 @@ + #include "stv0288.h" + #include "stb6000.h" + #include "cx24116.h" ++#include "m88ds3103.h" + #include "stv0900.h" + #include "stb6100.h" + #include "stb6100_proc.h" +@@ -458,6 +459,56 @@ + return core->prev_set_voltage(fe, voltage); + return 0; + } ++/*CX88_BOARD_BST_PS8312*/ ++static int bst_dvbs_set_voltage(struct dvb_frontend *fe, ++ fe_sec_voltage_t voltage) ++{ ++ struct cx8802_dev *dev= fe->dvb->priv; ++ struct cx88_core *core = dev->core; ++ ++ cx_write(MO_GP1_IO, 0x111111); ++ switch (voltage) { ++ case SEC_VOLTAGE_13: ++ cx_write(MO_GP1_IO, 0x020200); ++ break; ++ case SEC_VOLTAGE_18: ++ cx_write(MO_GP1_IO, 0x020202); ++ break; ++ case SEC_VOLTAGE_OFF: ++ cx_write(MO_GP1_IO, 0x111100); ++ break; ++ } ++ ++ if (core->prev_set_voltage) ++ return core->prev_set_voltage(fe, voltage); ++ return 0; ++} ++ ++static int bst_dvbs_set_voltage_v2(struct dvb_frontend *fe, ++ fe_sec_voltage_t voltage) ++{ ++ struct cx8802_dev *dev= fe->dvb->priv; ++ struct cx88_core *core = dev->core; ++ ++ cx_write(MO_GP1_IO, 0x111101); ++ switch (voltage) { ++ case SEC_VOLTAGE_13: ++ cx_write(MO_GP1_IO, 0x020200); ++ break; ++ case SEC_VOLTAGE_18: ++ ++ cx_write(MO_GP1_IO, 0x020202); ++ break; ++ case SEC_VOLTAGE_OFF: ++ ++ cx_write(MO_GP1_IO, 0x111110); ++ break; ++ } ++ ++ if (core->prev_set_voltage) ++ return core->prev_set_voltage(fe, voltage); ++ return 0; ++} + + static int vp1027_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +@@ -700,6 +751,11 @@ + .set_ts_params = ds3000_set_ts_param, + }; + ++static struct m88ds3103_config dvbsky_ds3103_config = { ++ .demod_address = 0x68, ++ .set_ts_params = ds3000_set_ts_param, ++}; ++ + static const struct stv0900_config prof_7301_stv0900_config = { + .demod_address = 0x6a, + /* demod_mode = 0,*/ +@@ -1470,6 +1526,35 @@ + fe0->dvb.frontend->ops.set_voltage = + tevii_dvbs_set_voltage; + break; ++ case CX88_BOARD_BST_PS8312: ++ fe0->dvb.frontend = dvb_attach(m88ds3103_attach, ++ &dvbsky_ds3103_config, ++ &core->i2c_adap); ++ if (fe0->dvb.frontend != NULL){ ++ int ret; ++ u8 b0[] = { 0x60 }; ++ u8 b1[2] = { 0 }; ++ struct i2c_msg msg[] = { ++ { ++ .addr = 0x50, ++ .flags = 0, ++ .buf = b0, ++ .len = 1 ++ }, { ++ .addr = 0x50, ++ .flags = I2C_M_RD, ++ .buf = b1, ++ .len = 2 ++ } ++ }; ++ ret = i2c_transfer(&core->i2c_adap, msg, 2); ++ printk("PS8312: config = %02x, %02x", b1[0],b1[1]); ++ if(b1[0] == 0xaa) ++ fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage_v2; ++ else ++ fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage; ++ } ++ break; + case CX88_BOARD_OMICOM_SS4_PCI: + case CX88_BOARD_TBS_8920: + case CX88_BOARD_PROF_7300: +diff -urN a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h +--- a/drivers/media/video/cx88/cx88.h 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx88/cx88.h 2012-11-18 23:26:40.701160685 +0800 +@@ -238,6 +238,7 @@ + #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88 + #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89 + #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90 ++#define CX88_BOARD_BST_PS8312 91 + + enum cx88_itype { + CX88_VMUX_COMPOSITE1 = 1, +diff -urN a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c +--- a/drivers/media/video/cx88/cx88-input.c 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx88/cx88-input.c 2012-11-18 23:26:56.589161123 +0800 +@@ -419,6 +419,10 @@ + rc_type = RC_TYPE_NEC; + ir->sampling = 0xff00; /* address */ + break; ++ case CX88_BOARD_BST_PS8312: ++ ir_codes = RC_MAP_DVBSKY; ++ ir->sampling = 0xff00; /* address */ ++ break; + } + + if (!ir_codes) { +diff -urN a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig +--- a/drivers/media/video/cx88/Kconfig 2012-11-05 16:57:06.000000000 +0800 ++++ b/drivers/media/video/cx88/Kconfig 2012-11-18 23:27:01.261161247 +0800 +@@ -57,6 +57,7 @@ + select DVB_ISL6421 if !DVB_FE_CUSTOMISE + select DVB_S5H1411 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE ++ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE +diff -urN a/include/media/rc-map.h b/include/media/rc-map.h +--- a/include/media/rc-map.h 2012-11-05 16:57:06.000000000 +0800 ++++ b/include/media/rc-map.h 2012-11-18 23:22:21.777153765 +0800 +@@ -86,6 +86,7 @@ + #define RC_MAP_DM1105_NEC "rc-dm1105-nec" + #define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" + #define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t" ++#define RC_MAP_DVBSKY "rc-dvbsky" + #define RC_MAP_EMPTY "rc-empty" + #define RC_MAP_EM_TERRATEC "rc-em-terratec" + #define RC_MAP_ENCORE_ENLTV2 "rc-encore-enltv2"