This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "IPFire 2.x development tree".
The branch, thirteen has been updated via 330e81cd9d08d47699032b5eb972c72a0c150ab5 (commit) from 0338cdb0f82a5385924bdee7983556f1b8773f42 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit 330e81cd9d08d47699032b5eb972c72a0c150ab5 Author: Arne Fitzenreiter arne_f@ipfire.org Date: Sat Nov 24 19:25:23 2012 +0100
v4l_dvb: add Bestunar US638x HD driver.
-----------------------------------------------------------------------
Summary of changes: lfs/v4l-dvb | 1 + src/patches/v4l-dvb_bestunar_us638x.patch | 2810 +++++++++++++++++++++++++++++ 2 files changed, 2811 insertions(+) create mode 100644 src/patches/v4l-dvb_bestunar_us638x.patch
Difference in files: diff --git a/lfs/v4l-dvb b/lfs/v4l-dvb index 0256cc3..ef0f383 100644 --- a/lfs/v4l-dvb +++ b/lfs/v4l-dvb @@ -81,6 +81,7 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/v4l-dvb_rtl28xx_commented_usb_clear_halt.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/v4l-dvb_usbv2_dont_report_pidfilter_fail.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/v4l-dvb_fix_tua6034_pll.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/v4l-dvb_bestunar_us638x.patch
cd $(DIR_APP) && make allyesconfig KERNELRELEASE=$(KVER)-$(VERSUFIX) VER=$(XVER) ifeq "$(KCFG)" "-omap" diff --git a/src/patches/v4l-dvb_bestunar_us638x.patch b/src/patches/v4l-dvb_bestunar_us638x.patch new file mode 100644 index 0000000..e3ac8d2 --- /dev/null +++ b/src/patches/v4l-dvb_bestunar_us638x.patch @@ -0,0 +1,2810 @@ +diff -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/Kconfig v4l-dvb-20120916/linux/drivers/media/dvb-frontends/Kconfig +--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/Kconfig 2012-08-22 05:45:23.000000000 +0200 ++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/Kconfig 2012-11-24 13:35:19.220030262 +0100 +@@ -200,6 +200,13 @@ + 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_SI21XX + tristate "Silicon Labs SI21XX based" + depends on DVB_CORE && I2C +diff -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103.c v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103.c +--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103.c 1970-01-01 01:00:00.000000000 +0100 ++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103.c 2012-11-24 13:34:43.713346302 +0100 +@@ -0,0 +1,1710 @@ ++/* ++ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver ++ ++ Copyright (C) 2011 Max nibblenibble.max@gmail.com ++ Copyright (C) 2010 Montage Technology<www.montage-tech.com> ++ 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 <linux/slab.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/firmware.h> ++ ++#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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103.h v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103.h +--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103.h 1970-01-01 01:00:00.000000000 +0100 ++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103.h 2012-11-24 13:34:43.716679774 +0100 +@@ -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 <linux/dvb/frontend.h> ++ ++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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103_priv.h v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103_priv.h +--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/m88ds3103_priv.h 1970-01-01 01:00:00.000000000 +0100 ++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/m88ds3103_priv.h 2012-11-24 13:34:43.716679774 +0100 +@@ -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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/Makefile v4l-dvb-20120916/linux/drivers/media/dvb-frontends/Makefile +--- v4l-dvb-20120916.ORG/linux/drivers/media/dvb-frontends/Makefile 2012-08-17 05:45:27.000000000 +0200 ++++ v4l-dvb-20120916/linux/drivers/media/dvb-frontends/Makefile 2012-11-24 13:34:43.716679774 +0100 +@@ -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 ++ ++ + +diff -Naur v4l-dvb-20120916.ORG/linux/drivers/media/rc/keymaps/Makefile v4l-dvb-20120916/linux/drivers/media/rc/keymaps/Makefile +--- v4l-dvb-20120916.ORG/linux/drivers/media/rc/keymaps/Makefile 2012-05-21 05:45:41.000000000 +0200 ++++ v4l-dvb-20120916/linux/drivers/media/rc/keymaps/Makefile 2012-11-24 13:34:43.716679774 +0100 +@@ -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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/rc/keymaps/rc-dvbsky.c v4l-dvb-20120916/linux/drivers/media/rc/keymaps/rc-dvbsky.c +--- v4l-dvb-20120916.ORG/linux/drivers/media/rc/keymaps/rc-dvbsky.c 1970-01-01 01:00:00.000000000 +0100 ++++ v4l-dvb-20120916/linux/drivers/media/rc/keymaps/rc-dvbsky.c 2012-11-24 13:34:43.716679774 +0100 +@@ -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 mchehab@redhat.com ++ * ++ * 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 <media/rc-map.h> ++#include <linux/module.h> ++/* ++ * 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 mchehab@redhat.com"); +diff -Naur v4l-dvb-20120916.ORG/linux/drivers/media/usb/dvb-usb/dw2102.c v4l-dvb-20120916/linux/drivers/media/usb/dvb-usb/dw2102.c +--- v4l-dvb-20120916.ORG/linux/drivers/media/usb/dvb-usb/dw2102.c 2012-08-14 05:45:22.000000000 +0200 ++++ v4l-dvb-20120916/linux/drivers/media/usb/dvb-usb/dw2102.c 2012-11-24 15:44:13.269971182 +0100 +@@ -3,6 +3,7 @@ + * TeVii S600, S630, S650, S660, S480, + * Prof 1100, 7500, + * Geniatech SU3000 Cards ++ * Bestunar US683x HD, DVBsky S860, S960 USB + * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by) + * + * This program is free software; you can redistribute it and/or modify it +@@ -19,6 +20,7 @@ + #include "stb6000.h" + #include "eds1547.h" + #include "cx24116.h" ++#include "m88ds3103.h" + #include "tda1002x.h" + #include "mt312.h" + #include "zl10039.h" +@@ -786,7 +788,7 @@ + struct su3000_state *state = (struct su3000_state *)d->priv; + u8 obuf[] = {0xde, 0}; + +- info("%s: %d, initialized %d\n", __func__, i, state->initialized); ++ info("%s: %d, initialized %d", __func__, i, state->initialized); + + if (i && !state->initialized) { + state->initialized = 1; +@@ -824,7 +826,40 @@ + else + mac[i] = ibuf[0]; + +- debug_dump(mac, 6, printk); ++ debug_dump(mac, 6, deb_xfer); ++ } ++ ++ 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, deb_xfer); + } + + return 0; +@@ -835,7 +870,7 @@ + struct dvb_usb_device_description **desc, + int *cold) + { +- info("%s\n", __func__); ++ info("%s", __func__); + + *cold = 0; + return 0; +@@ -878,6 +913,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!", __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, 0, 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 +1055,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; +@@ -1000,7 +1090,7 @@ + tuner_ops->set_bandwidth = stb6100_set_bandw; + tuner_ops->get_bandwidth = stb6100_get_bandw; + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; +- info("Attached STV0900+STB6100!\n"); ++ info("Attached STV0900+STB6100!"); + return 0; + } + } +@@ -1014,7 +1104,7 @@ + &dw2104_stv6110_config, + &d->dev->i2c_adap)) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; +- info("Attached STV0900+STV6110A!\n"); ++ info("Attached STV0900+STV6110A!"); + return 0; + } + } +@@ -1025,7 +1115,7 @@ + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; +- info("Attached cx24116!\n"); ++ info("Attached cx24116!"); + return 0; + } + } +@@ -1034,7 +1124,7 @@ + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; +- info("Attached DS3000!\n"); ++ info("Attached DS3000!"); + return 0; + } + +@@ -1053,7 +1143,7 @@ + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; +- info("Attached si21xx!\n"); ++ info("Attached si21xx!"); + return 0; + } + } +@@ -1065,7 +1155,7 @@ + if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, + &d->dev->i2c_adap)) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; +- info("Attached stv0288!\n"); ++ info("Attached stv0288!"); + return 0; + } + } +@@ -1077,7 +1167,7 @@ + &d->dev->i2c_adap); + if (d->fe_adap[0].fe != NULL) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; +- info("Attached stv0299!\n"); ++ info("Attached stv0299!"); + return 0; + } + } +@@ -1089,7 +1179,7 @@ + d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, + &d->dev->i2c_adap, 0x48); + if (d->fe_adap[0].fe != NULL) { +- info("Attached tda10023!\n"); ++ info("Attached tda10023!"); + return 0; + } + return -EIO; +@@ -1103,7 +1193,7 @@ + if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60, + &d->dev->i2c_adap)) { + d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage; +- info("Attached zl100313+zl10039!\n"); ++ info("Attached zl100313+zl10039!"); + return 0; + } + } +@@ -1128,7 +1218,7 @@ + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + +- info("Attached stv0288+stb6000!\n"); ++ info("Attached stv0288+stb6000!"); + + return 0; + +@@ -1150,7 +1240,7 @@ + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + +- info("Attached ds3000+ds2020!\n"); ++ info("Attached ds3000+ds2020!"); + + return 0; + } +@@ -1168,7 +1258,7 @@ + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + +- info("Attached STV0900+STB6100A!\n"); ++ info("Attached STV0900+STB6100A!"); + + return 0; + } +@@ -1205,7 +1295,88 @@ + if (d->fe_adap[0].fe == NULL) + return -EIO; + +- info("Attached DS3000!\n"); ++ info("Attached DS3000!"); ++ ++ 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!"); ++ ++ return 0; ++} ++ ++static int US6832_frontend_attach(struct dvb_usb_adapter *d) ++{ ++ u8 obuf[3] = { 0xe, 0x04, 1 }; ++ u8 ibuf[] = { 0 }; ++ ++ info("US6832: %s!", __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!"); + + return 0; + } +@@ -1447,6 +1618,9 @@ + TEVII_S480_1, + TEVII_S480_2, + X3M_SPC1400HD, ++ BST_US6830HD, ++ BST_US6831HD, ++ BST_US6832HD, + }; + + static struct usb_device_id dw2102_table[] = { +@@ -1465,6 +1639,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 +2047,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 +2203,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 -Naur v4l-dvb-20120916.ORG/linux/drivers/media/usb/dvb-usb/Kconfig v4l-dvb-20120916/linux/drivers/media/usb/dvb-usb/Kconfig +--- v4l-dvb-20120916.ORG/linux/drivers/media/usb/dvb-usb/Kconfig 2012-08-22 05:45:23.000000000 +0200 ++++ v4l-dvb-20120916/linux/drivers/media/usb/dvb-usb/Kconfig 2012-11-24 13:34:43.716679774 +0100 +@@ -1,3 +1,4 @@ +++ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE + config DVB_USB + tristate "Support for various USB DVB devices" + depends on DVB_CORE && USB && I2C && RC_CORE +@@ -261,6 +262,7 @@ + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT ++ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT +diff -Naur v4l-dvb-20120916.ORG/linux/include/media/rc-map.h v4l-dvb-20120916/linux/include/media/rc-map.h +--- v4l-dvb-20120916.ORG/linux/include/media/rc-map.h 2012-05-21 05:45:41.000000000 +0200 ++++ v4l-dvb-20120916/linux/include/media/rc-map.h 2012-11-24 13:34:43.716679774 +0100 +@@ -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"
hooks/post-receive -- IPFire 2.x development tree