You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6529 lines
180 KiB
6529 lines
180 KiB
5 years ago
|
diff -urN a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
|
||
|
--- a/drivers/media/dvb-frontends/Kconfig 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/dvb-frontends/Kconfig 2013-05-03 17:03:57.000000000 +0800
|
||
|
@@ -200,6 +200,20 @@
|
||
|
help
|
||
|
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||
|
|
||
|
+config DVB_M88DS3103
|
||
|
+ tristate "Montage M88DS3103 based"
|
||
|
+ depends on DVB_CORE && I2C
|
||
|
+ default m if !MEDIA_SUBDRV_AUTOSELECT
|
||
|
+ help
|
||
|
+ A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||
|
+
|
||
|
+config DVB_M88DC2800
|
||
|
+ tristate "Montage M88DC2800 based"
|
||
|
+ depends on DVB_CORE && I2C
|
||
|
+ default m if !MEDIA_SUBDRV_AUTOSELECT
|
||
|
+ 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 2013-01-26 16:03:21.000000000 +0800
|
||
|
@@ -0,0 +1,2124 @@
|
||
|
+/*
|
||
|
+ M88DC2800/M88TC2800 - DVB-C demodulator and tuner from Montage
|
||
|
+
|
||
|
+ Copyright (C) 2012 Max nibble<nibble.max@gmail.com>
|
||
|
+ Copyright (C) 2011 Montage Technology / www.montage-tech.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.
|
||
|
+
|
||
|
+ 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/delay.h>
|
||
|
+#include <linux/errno.h>
|
||
|
+#include <linux/init.h>
|
||
|
+#include <linux/kernel.h>
|
||
|
+#include <linux/module.h>
|
||
|
+#include <linux/string.h>
|
||
|
+#include <linux/slab.h>
|
||
|
+#include <asm/div64.h>
|
||
|
+#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;
|
||
|
+
|
||
|
+ dprintk("%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);
|
||
|
+
|
||
|
+ dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, 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;
|
||
|
+ u8 a, b, c;
|
||
|
+ if (state->tuner_mtt == 0xD1) { /* D1 */
|
||
|
+ if (freq_KHz <= 123000) {
|
||
|
+ if (freq_KHz <= 56000) {
|
||
|
+ a = 0x00; b = 0x00; c = 0x00;
|
||
|
+ } else if (freq_KHz <= 64000) {
|
||
|
+ a = 0x10; b = 0x01; c = 0x08;
|
||
|
+ } else if (freq_KHz <= 72000) {
|
||
|
+ a = 0x20; b = 0x02; c = 0x10;
|
||
|
+ } else if (freq_KHz <= 80000) {
|
||
|
+ a = 0x30; b = 0x03; c = 0x18;
|
||
|
+ } else if (freq_KHz <= 88000) {
|
||
|
+ a = 0x40; b = 0x04; c = 0x20;
|
||
|
+ } else if (freq_KHz <= 96000) {
|
||
|
+ a = 0x50; b = 0x05; c = 0x28;
|
||
|
+ } else if (freq_KHz <= 104000) {
|
||
|
+ a = 0x60; b = 0x06; c = 0x30;
|
||
|
+ } else {
|
||
|
+ a = 0x70; b = 0x07; c = 0x38;
|
||
|
+ }
|
||
|
+ _mt_fe_tn_set_reg(state, 0x58, 0x9b);
|
||
|
+ _mt_fe_tn_set_reg(state, 0x59, a);
|
||
|
+ _mt_fe_tn_set_reg(state, 0x5d, b);
|
||
|
+ _mt_fe_tn_set_reg(state, 0x5e, c);
|
||
|
+ _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, (f1f2number & 0xff00) >> 8);
|
||
|
+ _mt_fe_tn_set_reg(state, 0xf2, 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(KERN_INFO "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;
|
||
|
+ _mt_fe_tn_set_reg(state, 0x21, freq_KHz > 500000 ? 0xb9 : 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 s32 mt_fe_tn_get_signal_strength_tc2800(struct m88dc2800_state
|
||
|
+ *state)
|
||
|
+{
|
||
|
+ 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;
|
||
|
+ }
|
||
|
+ dprintk("%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(KERN_INFO
|
||
|
+ "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(KERN_INFO
|
||
|
+ "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(KERN_INFO "%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(KERN_INFO "%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(KERN_INFO "%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(KERN_INFO "%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(KERN_INFO "%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;
|
||
|
+
|
||
|
+ is_annex_c = c->delivery_system == SYS_DVBC_ANNEX_C ? 1 : 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;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->inverted = c->inversion == INVERSION_ON ? 1 : 0;
|
||
|
+
|
||
|
+ printk(KERN_INFO
|
||
|
+ "m88dc2800: state, freq=%d qam=%d sym=%d inverted=%d xtal=%d\n",
|
||
|
+ state->freq, state->qam, state->sym, state->inverted,
|
||
|
+ state->xtal);
|
||
|
+ printk(KERN_INFO
|
||
|
+ "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;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->inverted = (state->inverted != 0) ? 0 : 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 = mt_fe_tn_get_signal_strength_tc2800(state);
|
||
|
+ *strength = tuner_strength < -107 ? 0 : tuner_strength + 107;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int m88dc2800_read_snr(struct dvb_frontend *fe, u16 * snr)
|
||
|
+{
|
||
|
+ static 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
|
||
|
+ };
|
||
|
+ struct m88dc2800_state *state = fe->demodulator_priv;
|
||
|
+ 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 <nibble.max@gmail.com>");
|
||
|
+MODULE_LICENSE("GPL");
|
||
|
+MODULE_VERSION("1.00");
|
||
|
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 2013-01-26 14:57:32.000000000 +0800
|
||
|
@@ -0,0 +1,43 @@
|
||
|
+/*
|
||
|
+ M88DC2800/M88TC2800 - DVB-C demodulator and tuner from Montage
|
||
|
+
|
||
|
+ Copyright (C) 2012 Max Nibble <nibble.max@gmail.com>
|
||
|
+ Copyright (C) 2011 Montage Technology - www.montage-tech.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.
|
||
|
+
|
||
|
+ 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 <linux/dvb/frontend.h>
|
||
|
+
|
||
|
+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 2013-01-30 12:33:47.000000000 +0800
|
||
|
@@ -0,0 +1,1710 @@
|
||
|
+/*
|
||
|
+ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
|
||
|
+
|
||
|
+ Copyright (C) 2011 Max nibble<nibble.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 -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 2013-01-30 12:33:51.000000000 +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 <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 -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 2013-01-30 12:33:56.000000000 +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 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/dvb-frontends/Makefile 2013-05-03 17:04:31.000000000 +0800
|
||
|
@@ -103,4 +103,5 @@
|
||
|
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/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c
|
||
|
--- a/drivers/media/pci/cx23885/cimax2.c 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx23885/cimax2.c 2013-03-31 22:03:29.000000000 +0800
|
||
|
@@ -415,7 +415,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] = {
|
||
|
@@ -464,6 +464,11 @@
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
+ if(isDVBSky) {
|
||
|
+ cimax_init[32] = 0x22;
|
||
|
+ cimax_init[33] = 0x00;
|
||
|
+ }
|
||
|
+
|
||
|
port->port_priv = state;
|
||
|
|
||
|
switch (port->nr) {
|
||
|
@@ -537,3 +542,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/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h
|
||
|
--- a/drivers/media/pci/cx23885/cimax2.h 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx23885/cimax2.h 2013-01-30 12:34:37.000000000 +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/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
|
||
|
--- a/drivers/media/pci/cx23885/cx23885-cards.c 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx23885/cx23885-cards.c 2013-05-03 17:34:46.000000000 +0800
|
||
|
@@ -569,6 +569,34 @@
|
||
|
.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,
|
||
|
+ },
|
||
|
+ [CX23885_BOARD_DVBSKY_T9580] = {
|
||
|
+ .name = "DVBSKY T9580",
|
||
|
+ .portb = CX23885_MPEG_DVB,
|
||
|
+ .portc = CX23885_MPEG_DVB,
|
||
|
+ },
|
||
|
[CX23885_BOARD_PROF_8000] = {
|
||
|
.name = "Prof Revolution DVB-S2 8000",
|
||
|
.portb = CX23885_MPEG_DVB,
|
||
|
@@ -605,7 +633,7 @@
|
||
|
CX25840_NONE1_CH3,
|
||
|
.amux = CX25840_AUDIO6,
|
||
|
} },
|
||
|
- }
|
||
|
+ }
|
||
|
};
|
||
|
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
|
||
|
|
||
|
@@ -818,6 +846,30 @@
|
||
|
.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,
|
||
|
+ }, {
|
||
|
+ .subvendor = 0x4254,
|
||
|
+ .subdevice = 0x9580,
|
||
|
+ .card = CX23885_BOARD_DVBSKY_T9580,
|
||
|
+ }, {
|
||
|
.subvendor = 0x8000,
|
||
|
.subdevice = 0x3034,
|
||
|
.card = CX23885_BOARD_PROF_8000,
|
||
|
@@ -1224,7 +1276,7 @@
|
||
|
cx_set(GP0_IO, 0x00040004);
|
||
|
break;
|
||
|
case CX23885_BOARD_TBS_6920:
|
||
|
- case CX23885_BOARD_PROF_8000:
|
||
|
+ case CX23885_BOARD_PROF_8000:
|
||
|
cx_write(MC417_CTL, 0x00000036);
|
||
|
cx_write(MC417_OEN, 0x00001000);
|
||
|
cx_set(MC417_RWD, 0x00000002);
|
||
|
@@ -1394,9 +1446,84 @@
|
||
|
cx_set(GP0_IO, 0x00040004);
|
||
|
mdelay(60);
|
||
|
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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
+ 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[] = {
|
||
|
@@ -1482,6 +1609,23 @@
|
||
|
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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
+ 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;
|
||
|
@@ -1511,9 +1655,15 @@
|
||
|
cx23888_ir_remove(dev);
|
||
|
dev->sd_ir = NULL;
|
||
|
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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
|
||
|
case CX23885_BOARD_TEVII_S470:
|
||
|
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
||
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
||
|
case CX23885_BOARD_MYGICA_X8507:
|
||
|
cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
|
||
|
/* sd_ir is a duplicate pointer to the AV Core, just clear it */
|
||
|
@@ -1556,6 +1706,12 @@
|
||
|
if (dev->sd_ir)
|
||
|
cx23885_irq_add_enable(dev, PCI_MSK_IR);
|
||
|
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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
|
||
|
case CX23885_BOARD_TEVII_S470:
|
||
|
case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
||
|
@@ -1657,6 +1813,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:
|
||
|
@@ -1694,6 +1854,22 @@
|
||
|
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
|
||
|
ts1->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_DVBSKY_T9580:
|
||
|
+ 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 = 0x8; /* Serial bus */
|
||
|
+ 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:
|
||
|
@@ -1749,6 +1925,12 @@
|
||
|
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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
case CX23885_BOARD_AVERMEDIA_HC81R:
|
||
|
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
||
|
&dev->i2c_bus[2].i2c_adap,
|
||
|
diff -urN a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
|
||
|
--- a/drivers/media/pci/cx23885/cx23885-core.c 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx23885/cx23885-core.c 2013-05-03 17:36:31.000000000 +0800
|
||
|
@@ -1909,6 +1909,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);
|
||
|
@@ -2144,6 +2148,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/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
|
||
|
--- a/drivers/media/pci/cx23885/cx23885-dvb.c 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c 2013-05-03 17:38:34.000000000 +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"
|
||
|
@@ -64,8 +66,8 @@
|
||
|
#include "stv0367.h"
|
||
|
#include "drxk.h"
|
||
|
#include "mt2063.h"
|
||
|
-#include "stv090x.h"
|
||
|
-#include "stb6100.h"
|
||
|
+#include "stv090x.h"
|
||
|
+#include "stb6100.h"
|
||
|
#include "stb6100_cfg.h"
|
||
|
#include "tda10071.h"
|
||
|
#include "a8293.h"
|
||
|
@@ -500,42 +502,130 @@
|
||
|
.if_khz = 5380,
|
||
|
};
|
||
|
|
||
|
-static struct stv090x_config prof_8000_stv090x_config = {
|
||
|
- .device = STV0903,
|
||
|
- .demod_mode = STV090x_SINGLE,
|
||
|
- .clk_mode = STV090x_CLK_EXT,
|
||
|
- .xtal = 27000000,
|
||
|
- .address = 0x6A,
|
||
|
- .ts1_mode = STV090x_TSMODE_PARALLEL_PUNCTURED,
|
||
|
- .repeater_level = STV090x_RPTLEVEL_64,
|
||
|
- .adc1_range = STV090x_ADC_2Vpp,
|
||
|
- .diseqc_envelope_mode = false,
|
||
|
-
|
||
|
- .tuner_get_frequency = stb6100_get_frequency,
|
||
|
- .tuner_set_frequency = stb6100_set_frequency,
|
||
|
- .tuner_set_bandwidth = stb6100_set_bandwidth,
|
||
|
- .tuner_get_bandwidth = stb6100_get_bandwidth,
|
||
|
-};
|
||
|
|
||
|
-static struct stb6100_config prof_8000_stb6100_config = {
|
||
|
- .tuner_address = 0x60,
|
||
|
- .refclock = 27000000,
|
||
|
-};
|
||
|
-
|
||
|
-static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||
|
+/* 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;
|
||
|
+}
|
||
|
|
||
|
- if (voltage == SEC_VOLTAGE_18)
|
||
|
- cx_write(MC417_RWD, 0x00001e00);
|
||
|
- else if (voltage == SEC_VOLTAGE_13)
|
||
|
- cx_write(MC417_RWD, 0x00001a00);
|
||
|
- else
|
||
|
- cx_write(MC417_RWD, 0x00001800);
|
||
|
+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;
|
||
|
}
|
||
|
|
||
|
+/* 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 struct stv090x_config prof_8000_stv090x_config = {
|
||
|
+ .device = STV0903,
|
||
|
+ .demod_mode = STV090x_SINGLE,
|
||
|
+ .clk_mode = STV090x_CLK_EXT,
|
||
|
+ .xtal = 27000000,
|
||
|
+ .address = 0x6A,
|
||
|
+ .ts1_mode = STV090x_TSMODE_PARALLEL_PUNCTURED,
|
||
|
+ .repeater_level = STV090x_RPTLEVEL_64,
|
||
|
+ .adc1_range = STV090x_ADC_2Vpp,
|
||
|
+ .diseqc_envelope_mode = false,
|
||
|
+
|
||
|
+ .tuner_get_frequency = stb6100_get_frequency,
|
||
|
+ .tuner_set_frequency = stb6100_set_frequency,
|
||
|
+ .tuner_set_bandwidth = stb6100_set_bandwidth,
|
||
|
+ .tuner_get_bandwidth = stb6100_get_bandwidth,
|
||
|
+};
|
||
|
+
|
||
|
+static struct stb6100_config prof_8000_stb6100_config = {
|
||
|
+ .tuner_address = 0x60,
|
||
|
+ .refclock = 27000000,
|
||
|
+};
|
||
|
+
|
||
|
+static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||
|
+{
|
||
|
+ struct cx23885_tsport *port = fe->dvb->priv;
|
||
|
+ struct cx23885_dev *dev = port->dev;
|
||
|
+
|
||
|
+ if (voltage == SEC_VOLTAGE_18)
|
||
|
+ cx_write(MC417_RWD, 0x00001e00);
|
||
|
+ else if (voltage == SEC_VOLTAGE_13)
|
||
|
+ cx_write(MC417_RWD, 0x00001a00);
|
||
|
+ else
|
||
|
+ cx_write(MC417_RWD, 0x00001800);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
|
||
|
{
|
||
|
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||
|
@@ -1250,23 +1340,79 @@
|
||
|
&tevii_ds3000_config,
|
||
|
&i2c_bus->i2c_adap);
|
||
|
break;
|
||
|
- case CX23885_BOARD_PROF_8000:
|
||
|
- i2c_bus = &dev->i2c_bus[0];
|
||
|
+ 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;
|
||
|
|
||
|
- fe0->dvb.frontend = dvb_attach(stv090x_attach,
|
||
|
- &prof_8000_stv090x_config,
|
||
|
- &i2c_bus->i2c_adap,
|
||
|
- STV090x_DEMODULATOR_0);
|
||
|
- if (fe0->dvb.frontend != NULL) {
|
||
|
- if (!dvb_attach(stb6100_attach,
|
||
|
- fe0->dvb.frontend,
|
||
|
- &prof_8000_stb6100_config,
|
||
|
- &i2c_bus->i2c_adap))
|
||
|
- goto frontend_detach;
|
||
|
+ 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;
|
||
|
|
||
|
- fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage;
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
+ 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:
|
||
|
+ break;
|
||
|
}
|
||
|
break;
|
||
|
+
|
||
|
+ case CX23885_BOARD_PROF_8000:
|
||
|
+ i2c_bus = &dev->i2c_bus[0];
|
||
|
+
|
||
|
+ fe0->dvb.frontend = dvb_attach(stv090x_attach,
|
||
|
+ &prof_8000_stv090x_config,
|
||
|
+ &i2c_bus->i2c_adap,
|
||
|
+ STV090x_DEMODULATOR_0);
|
||
|
+ if (fe0->dvb.frontend != NULL) {
|
||
|
+ if (!dvb_attach(stb6100_attach,
|
||
|
+ fe0->dvb.frontend,
|
||
|
+ &prof_8000_stb6100_config,
|
||
|
+ &i2c_bus->i2c_adap))
|
||
|
+ goto frontend_detach;
|
||
|
+
|
||
|
+ fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage;
|
||
|
+ }
|
||
|
+ break;
|
||
|
case CX23885_BOARD_HAUPPAUGE_HVR4400:
|
||
|
i2c_bus = &dev->i2c_bus[0];
|
||
|
fe0->dvb.frontend = dvb_attach(tda10071_attach,
|
||
|
@@ -1325,7 +1471,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: {
|
||
|
@@ -1352,6 +1498,41 @@
|
||
|
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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:{
|
||
|
+ 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;
|
||
|
@@ -1434,6 +1615,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/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
|
||
|
--- a/drivers/media/pci/cx23885/cx23885.h 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx23885/cx23885.h 2013-05-03 17:14:20.000000000 +0800
|
||
|
@@ -94,6 +94,14 @@
|
||
|
#define CX23885_BOARD_HAUPPAUGE_HVR4400 38
|
||
|
#define CX23885_BOARD_AVERMEDIA_HC81R 39
|
||
|
|
||
|
+#define CX23885_BOARD_BASE_INDEX 40
|
||
|
+#define CX23885_BOARD_BST_PS8512 (CX23885_BOARD_BASE_INDEX)
|
||
|
+#define CX23885_BOARD_DVBSKY_S952 (CX23885_BOARD_BASE_INDEX+1)
|
||
|
+#define CX23885_BOARD_DVBSKY_S950 (CX23885_BOARD_BASE_INDEX+2)
|
||
|
+#define CX23885_BOARD_DVBSKY_S950_CI (CX23885_BOARD_BASE_INDEX+3)
|
||
|
+#define CX23885_BOARD_DVBSKY_C2800E_CI (CX23885_BOARD_BASE_INDEX+4)
|
||
|
+#define CX23885_BOARD_DVBSKY_T9580 (CX23885_BOARD_BASE_INDEX+5)
|
||
|
+
|
||
|
#define GPIO_0 0x00000001
|
||
|
#define GPIO_1 0x00000002
|
||
|
#define GPIO_2 0x00000004
|
||
|
@@ -231,7 +239,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/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
|
||
|
--- a/drivers/media/pci/cx23885/cx23885-input.c 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx23885/cx23885-input.c 2013-05-03 17:42:09.000000000 +0800
|
||
|
@@ -89,6 +89,12 @@
|
||
|
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
|
||
|
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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
case CX23885_BOARD_MYGICA_X8507:
|
||
|
/*
|
||
|
* The only boards we handle right now. However other boards
|
||
|
@@ -141,6 +147,12 @@
|
||
|
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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
case CX23885_BOARD_MYGICA_X8507:
|
||
|
/*
|
||
|
* The IR controller on this board only returns pulse widths.
|
||
|
@@ -291,6 +303,18 @@
|
||
|
/* 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:
|
||
|
+ case CX23885_BOARD_DVBSKY_T9580:
|
||
|
+ /* Integrated CX2388[58] IR controller */
|
||
|
+ driver_type = RC_DRIVER_IR_RAW;
|
||
|
+ allowed_protos = RC_BIT_ALL;
|
||
|
+ /* A guess at the remote */
|
||
|
+ rc_map = RC_MAP_DVBSKY;
|
||
|
+ break;
|
||
|
case CX23885_BOARD_MYGICA_X8507:
|
||
|
/* Integrated CX23885 IR controller */
|
||
|
driver_type = RC_DRIVER_IR_RAW;
|
||
|
diff -urN a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
|
||
|
--- a/drivers/media/pci/cx23885/Kconfig 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx23885/Kconfig 2013-05-03 17:43:05.000000000 +0800
|
||
|
@@ -23,6 +23,8 @@
|
||
|
select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
+ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
+ select DVB_M88DC2800 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
diff -urN a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
|
||
|
--- a/drivers/media/pci/cx88/cx88-cards.c 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx88/cx88-cards.c 2013-05-03 17:06:55.000000000 +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/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
|
||
|
--- a/drivers/media/pci/cx88/cx88-dvb.c 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx88/cx88-dvb.c 2013-05-03 17:09:09.000000000 +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"
|
||
|
@@ -459,6 +460,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)
|
||
|
@@ -706,6 +757,11 @@
|
||
|
.clk_out_div = 1,
|
||
|
};
|
||
|
|
||
|
+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,*/
|
||
|
@@ -1477,6 +1533,35 @@
|
||
|
&tevii_ts2020_config, &core->i2c_adap);
|
||
|
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:
|
||
|
diff -urN a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
|
||
|
--- a/drivers/media/pci/cx88/cx88.h 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx88/cx88.h 2013-05-03 17:05:57.000000000 +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/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
|
||
|
--- a/drivers/media/pci/cx88/cx88-input.c 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx88/cx88-input.c 2013-01-26 14:52:03.000000000 +0800
|
||
|
@@ -419,6 +419,10 @@
|
||
|
rc_type = RC_BIT_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/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig
|
||
|
--- a/drivers/media/pci/cx88/Kconfig 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/pci/cx88/Kconfig 2013-05-03 17:10:41.000000000 +0800
|
||
|
@@ -57,6 +57,7 @@
|
||
|
select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
+ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
diff -urN a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
|
||
|
--- a/drivers/media/rc/keymaps/Makefile 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/rc/keymaps/Makefile 2013-05-03 17:43:41.000000000 +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 2013-01-26 14:52:49.000000000 +0800
|
||
|
@@ -0,0 +1,78 @@
|
||
|
+/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers
|
||
|
+ *
|
||
|
+ * keymap imported from ir-keymaps.c
|
||
|
+ *
|
||
|
+ *
|
||
|
+ * Copyright (c) 2010-2012 by Nibble Max <nibble.max@gmail.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("Nibble Max <nibble.max@gmail.com>");
|
||
|
diff -urN a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
|
||
|
--- a/drivers/media/usb/dvb-usb-v2/dvbsky.c 1970-01-01 08:00:00.000000000 +0800
|
||
|
+++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c 2013-05-03 17:47:38.000000000 +0800
|
||
|
@@ -0,0 +1,1032 @@
|
||
|
+/*
|
||
|
+ * Driver for DVBSky USB2.0 receiver
|
||
|
+ *
|
||
|
+ * Copyright (C) 2013 Max nibble <nibble.max@gmail.com>
|
||
|
+ *
|
||
|
+ * CIMax code is copied and modified from:
|
||
|
+ * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card
|
||
|
+ * Copyright (C) 2009 NetUP Inc.
|
||
|
+ * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
|
||
|
+ * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
|
||
|
+ *
|
||
|
+ * 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 "dvb_ca_en50221.h"
|
||
|
+#include "dvb_usb.h"
|
||
|
+#include "m88ds3103.h"
|
||
|
+#include "si2168.h"
|
||
|
+#include "si2157.h"
|
||
|
+
|
||
|
+#define DVBSKY_MSG_DELAY 0/*2000*/
|
||
|
+#define DVBSKY_BUF_LEN 64
|
||
|
+
|
||
|
+static int dvbsky_debug;
|
||
|
+module_param(dvbsky_debug, int, 0644);
|
||
|
+MODULE_PARM_DESC(dvbsky_debug, "Activates dvbsky usb debugging (default:0)");
|
||
|
+
|
||
|
+#define DVBSKY_CI_CTL 0x04
|
||
|
+#define DVBSKY_CI_RD 1
|
||
|
+
|
||
|
+#define dprintk(args...) \
|
||
|
+ do { \
|
||
|
+ if (dvbsky_debug) \
|
||
|
+ printk(KERN_INFO "dvbsky_usb: " args); \
|
||
|
+ } while (0)
|
||
|
+
|
||
|
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||
|
+
|
||
|
+struct dvbsky_state {
|
||
|
+ struct mutex stream_mutex;
|
||
|
+ u8 has_ci;
|
||
|
+ u8 ci_attached;
|
||
|
+ struct i2c_client *i2c_client_demod;
|
||
|
+ struct i2c_client *i2c_client_tuner;
|
||
|
+ struct i2c_client *i2c_client_ci;
|
||
|
+ struct dvb_ca_en50221 ci;
|
||
|
+ unsigned long next_status_checked_time;
|
||
|
+ u8 ci_i2c_addr;
|
||
|
+ u8 current_ci_flag;
|
||
|
+ int ci_status;
|
||
|
+};
|
||
|
+
|
||
|
+static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = d_to_priv(d);
|
||
|
+ int ret;
|
||
|
+ u8 obuf_pre[3] = { 0x37, 0, 0 };
|
||
|
+ u8 obuf_post[3] = { 0x36, 3, 0 };
|
||
|
+ dprintk("%s() -off \n", __func__);
|
||
|
+ mutex_lock(&state->stream_mutex);
|
||
|
+ ret = dvb_usbv2_generic_write(d, obuf_pre, 3);
|
||
|
+ if (!ret && onoff) {
|
||
|
+ msleep(10);
|
||
|
+ ret = dvb_usbv2_generic_write(d, obuf_post, 3);
|
||
|
+ dprintk("%s() -on \n", __func__);
|
||
|
+ }
|
||
|
+ mutex_unlock(&state->stream_mutex);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/* CI opertaions */
|
||
|
+static int dvbsky_ci_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
|
||
|
+ u8 *buf, int len)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ struct i2c_msg msg[] = {
|
||
|
+ {
|
||
|
+ .addr = addr,
|
||
|
+ .flags = 0,
|
||
|
+ .buf = ®,
|
||
|
+ .len = 1
|
||
|
+ }, {
|
||
|
+ .addr = addr,
|
||
|
+ .flags = I2C_M_RD,
|
||
|
+ .buf = buf,
|
||
|
+ .len = len
|
||
|
+ }
|
||
|
+ };
|
||
|
+
|
||
|
+ ret = i2c_transfer(i2c_adap, msg, 2);
|
||
|
+
|
||
|
+ if (ret != 2) {
|
||
|
+ dprintk("%s: error, Reg = 0x%02x, Status = %d\n", __func__, reg, ret);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg,
|
||
|
+ u8 *buf, int len)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ u8 buffer[len + 1];
|
||
|
+
|
||
|
+ struct i2c_msg msg = {
|
||
|
+ .addr = addr,
|
||
|
+ .flags = 0,
|
||
|
+ .buf = &buffer[0],
|
||
|
+ .len = len + 1
|
||
|
+ };
|
||
|
+
|
||
|
+ buffer[0] = reg;
|
||
|
+ memcpy(&buffer[1], buf, len);
|
||
|
+
|
||
|
+ ret = i2c_transfer(i2c_adap, &msg, 1);
|
||
|
+
|
||
|
+ if (ret != 1) {
|
||
|
+ dprintk("%s: error, Reg=[0x%02x], Status=%d\n", __func__, reg, ret);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_op_cam(struct dvb_ca_en50221 *ci, int slot,
|
||
|
+ u8 flag, u8 read, int addr, u8 data)
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = ci->data;
|
||
|
+ struct dvbsky_state *state = d_to_priv(d);
|
||
|
+ u8 store;
|
||
|
+ int ret;
|
||
|
+ u8 command[4], respond[2], command_size, respond_size;
|
||
|
+
|
||
|
+ /*dprintk("%s()\n", __func__);*/
|
||
|
+ if (0 != slot)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ if (state->current_ci_flag != flag) {
|
||
|
+ ret = dvbsky_ci_read_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0, &store, 1);
|
||
|
+ if (ret != 0)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ store &= ~0x0c;
|
||
|
+ store |= flag;
|
||
|
+
|
||
|
+ ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0, &store, 1);
|
||
|
+ if (ret != 0)
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+ state->current_ci_flag = flag;
|
||
|
+
|
||
|
+ command[1] = (u8)((addr >> 8) & 0xff); /*high part of address*/
|
||
|
+ command[2] = (u8)(addr & 0xff); /*low part of address*/
|
||
|
+ if (read) {
|
||
|
+ command[0] = 0x71;
|
||
|
+ command_size = 3;
|
||
|
+ respond_size = 2;
|
||
|
+ } else {
|
||
|
+ command[0] = 0x70;
|
||
|
+ command[3] = data;
|
||
|
+ command_size = 4;
|
||
|
+ respond_size = 1;
|
||
|
+ }
|
||
|
+ ret = dvb_usbv2_generic_rw(d, command, command_size, respond, respond_size);
|
||
|
+
|
||
|
+ return (read) ? respond[1] : 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_read_attribute_mem(struct dvb_ca_en50221 *ci,
|
||
|
+ int slot, int addr)
|
||
|
+{
|
||
|
+ return dvbsky_ci_op_cam(ci, slot, 0, DVBSKY_CI_RD, addr, 0);
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_write_attribute_mem(struct dvb_ca_en50221 *ci,
|
||
|
+ int slot, int addr, u8 data)
|
||
|
+{
|
||
|
+ return dvbsky_ci_op_cam(ci, slot, 0, 0, addr, data);
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_read_cam_ctl(struct dvb_ca_en50221 *ci, int slot, u8 addr)
|
||
|
+{
|
||
|
+ return dvbsky_ci_op_cam(ci, slot, DVBSKY_CI_CTL, DVBSKY_CI_RD, addr, 0);
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_write_cam_ctl(struct dvb_ca_en50221 *ci, int slot,
|
||
|
+ u8 addr, u8 data)
|
||
|
+{
|
||
|
+ return dvbsky_ci_op_cam(ci, slot, DVBSKY_CI_CTL, 0, addr, data);
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot)
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = ci->data;
|
||
|
+ struct dvbsky_state *state = d_to_priv(d);
|
||
|
+ u8 buf = 0x80;
|
||
|
+ int ret;
|
||
|
+ dprintk("%s() slot=%d\n", __func__, slot);
|
||
|
+
|
||
|
+ if (0 != slot)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ udelay(500);
|
||
|
+ ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0, &buf, 1);
|
||
|
+
|
||
|
+ if (ret != 0)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ udelay(500);
|
||
|
+
|
||
|
+ buf = 0x00;
|
||
|
+ ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0, &buf, 1);
|
||
|
+ msleep(1000);
|
||
|
+ dprintk("%s() slot=%d complete\n", __func__, slot);
|
||
|
+ return 0;
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot)
|
||
|
+{
|
||
|
+ /* not implemented */
|
||
|
+ dprintk("%s()\n", __func__);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot)
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = ci->data;
|
||
|
+ struct dvbsky_state *state = d_to_priv(d);
|
||
|
+ u8 buf;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ dprintk("%s()\n", __func__);
|
||
|
+ if (0 != slot)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ dvbsky_ci_read_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0, &buf, 1);
|
||
|
+ buf |= 0x60;
|
||
|
+
|
||
|
+ ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0, &buf, 1);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot,
|
||
|
+ int open)
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = ci->data;
|
||
|
+ struct dvbsky_state *state = d_to_priv(d);
|
||
|
+ int ret = 0;
|
||
|
+ u8 buf = 0;
|
||
|
+ /*dprintk("%s()\n", __func__);*/
|
||
|
+
|
||
|
+ /* CAM module INSERT/REMOVE processing. slow operation because of i2c
|
||
|
+ * transfers */
|
||
|
+ if (time_after(jiffies, state->next_status_checked_time)) {
|
||
|
+ ret = dvbsky_ci_read_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0, &buf, 1);
|
||
|
+
|
||
|
+ /*dprintk("%s() status=%x\n", __func__, buf);*/
|
||
|
+
|
||
|
+ state->next_status_checked_time = jiffies
|
||
|
+ + msecs_to_jiffies(1000);
|
||
|
+
|
||
|
+ if (ret != 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (buf & 1) {
|
||
|
+ state->ci_status = DVB_CA_EN50221_POLL_CAM_PRESENT |
|
||
|
+ DVB_CA_EN50221_POLL_CAM_READY;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ state->ci_status = 0;
|
||
|
+ }
|
||
|
+ /*dprintk("%s() ret=%x\n", __func__, state->ci_status);*/
|
||
|
+ return state->ci_status;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_ci_init(struct dvb_usb_device *d)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = d_to_priv(d);
|
||
|
+ int ret;
|
||
|
+ u8 cimax_init[34] = {
|
||
|
+ 0x00, /* module A control*/
|
||
|
+ 0x00, /* auto select mask high A */
|
||
|
+ 0x00, /* auto select mask low A */
|
||
|
+ 0x00, /* auto select pattern high A */
|
||
|
+ 0x00, /* auto select pattern low A */
|
||
|
+ 0x44, /* memory access time A */
|
||
|
+ 0x00, /* invert input A */
|
||
|
+ 0x00, /* RFU */
|
||
|
+ 0x00, /* RFU */
|
||
|
+ 0x00, /* module B control*/
|
||
|
+ 0x00, /* auto select mask high B */
|
||
|
+ 0x00, /* auto select mask low B */
|
||
|
+ 0x00, /* auto select pattern high B */
|
||
|
+ 0x00, /* auto select pattern low B */
|
||
|
+ 0x44, /* memory access time B */
|
||
|
+ 0x00, /* invert input B */
|
||
|
+ 0x00, /* RFU */
|
||
|
+ 0x00, /* RFU */
|
||
|
+ 0x00, /* auto select mask high Ext */
|
||
|
+ 0x00, /* auto select mask low Ext */
|
||
|
+ 0x00, /* auto select pattern high Ext */
|
||
|
+ 0x00, /* auto select pattern low Ext */
|
||
|
+ 0x00, /* RFU */
|
||
|
+ 0x02, /* destination - module A */
|
||
|
+ 0x01, /* power on (use it like store place) */
|
||
|
+ 0x00, /* RFU */
|
||
|
+ 0x00, /* int status read only */
|
||
|
+ 0x00, /* Max: Disable the interrupt in USB solution.*/
|
||
|
+ 0x05, /* EXTINT=active-high, INT=push-pull */
|
||
|
+ 0x00, /* USCG1 */
|
||
|
+ 0x04, /* ack active low */
|
||
|
+ 0x00, /* LOCK = 0 */
|
||
|
+ 0x22, /* serial mode, rising in, rising out, MSB first*/
|
||
|
+ 0x00 /* synchronization */
|
||
|
+ };
|
||
|
+ dprintk("%s()\n", __func__);
|
||
|
+ state->current_ci_flag = 0xff;
|
||
|
+ state->ci_status = 0;
|
||
|
+ state->next_status_checked_time = jiffies + msecs_to_jiffies(1000);
|
||
|
+ state->ci_i2c_addr = 0x40;
|
||
|
+
|
||
|
+ state->ci.owner = THIS_MODULE;
|
||
|
+ state->ci.read_attribute_mem = dvbsky_ci_read_attribute_mem;
|
||
|
+ state->ci.write_attribute_mem = dvbsky_ci_write_attribute_mem;
|
||
|
+ state->ci.read_cam_control = dvbsky_ci_read_cam_ctl;
|
||
|
+ state->ci.write_cam_control = dvbsky_ci_write_cam_ctl;
|
||
|
+ state->ci.slot_reset = dvbsky_ci_slot_reset;
|
||
|
+ state->ci.slot_shutdown = dvbsky_ci_slot_shutdown;
|
||
|
+ state->ci.slot_ts_enable = dvbsky_ci_slot_ts_enable;
|
||
|
+ state->ci.poll_slot_status = dvbsky_ci_poll_slot_status;
|
||
|
+ state->ci.data = d;
|
||
|
+
|
||
|
+ ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0, &cimax_init[0], 34);
|
||
|
+ /* lock registers */
|
||
|
+ ret |= dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0x1f, &cimax_init[0x18], 1);
|
||
|
+ /* power on slots */
|
||
|
+ ret |= dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr,
|
||
|
+ 0x18, &cimax_init[0x18], 1);
|
||
|
+ if (0 != ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+ state->ci_attached = 1;
|
||
|
+ dprintk("%s() complete.\n", __func__);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static void dvbsky_ci_release(struct dvb_usb_device *d)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = d_to_priv(d);
|
||
|
+
|
||
|
+ /* detach CI */
|
||
|
+ if (state->ci_attached)
|
||
|
+ dvb_ca_en50221_release(&state->ci);
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff)
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = fe_to_d(fe);
|
||
|
+ /*dprintk("%s() %d\n", __func__, onoff);*/
|
||
|
+ return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1);
|
||
|
+}
|
||
|
+
|
||
|
+/* GPIO */
|
||
|
+static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
|
||
|
+{
|
||
|
+ u8 obuf[64], ibuf[64];
|
||
|
+ obuf[0] = 0x0e;
|
||
|
+ obuf[1] = gport;
|
||
|
+ obuf[2] = value;
|
||
|
+ return dvb_usbv2_generic_rw(d, obuf, 3, ibuf, 1);
|
||
|
+}
|
||
|
+
|
||
|
+/* I2C */
|
||
|
+static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||
|
+ int num)
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||
|
+ int ret = 0;
|
||
|
+ u8 ibuf[64], obuf[64];
|
||
|
+
|
||
|
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||
|
+ return -EAGAIN;
|
||
|
+
|
||
|
+ if (num > 2) {
|
||
|
+ printk(KERN_ERR "dvbsky_usb: too many i2c messages[%d] than 2.", num);
|
||
|
+ ret = -EOPNOTSUPP;
|
||
|
+ goto i2c_error;
|
||
|
+ }
|
||
|
+
|
||
|
+ if(num == 1) {
|
||
|
+ if (msg[0].len > 60) {
|
||
|
+ printk(KERN_ERR "dvbsky_usb: too many i2c bytes[%d] than 60.", msg[0].len);
|
||
|
+ ret = -EOPNOTSUPP;
|
||
|
+ goto i2c_error;
|
||
|
+ }
|
||
|
+ if (msg[0].flags & I2C_M_RD) {
|
||
|
+ /* single read */
|
||
|
+ obuf[0] = 0x09;
|
||
|
+ obuf[1] = 0;
|
||
|
+ obuf[2] = msg[0].len;
|
||
|
+ obuf[3] = msg[0].addr;
|
||
|
+ ret = dvb_usbv2_generic_rw(d, obuf, 4, ibuf, msg[0].len + 1);
|
||
|
+ /*dprintk("%s(): read status = %d\n", __func__, ibuf[0]);*/
|
||
|
+ if (!ret)
|
||
|
+ memcpy(msg[0].buf, &ibuf[1], msg[0].len);
|
||
|
+ } else {
|
||
|
+ /* write */
|
||
|
+ obuf[0] = 0x08;
|
||
|
+ obuf[1] = msg[0].addr;
|
||
|
+ obuf[2] = msg[0].len;
|
||
|
+ memcpy(&obuf[3], msg[0].buf, msg[0].len);
|
||
|
+ ret = dvb_usbv2_generic_rw(d, obuf, msg[0].len + 3, ibuf, 1);
|
||
|
+ /*dprintk("%s(): write status = %d\n", __func__, ibuf[0]);*/
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ if ((msg[0].len > 60) || (msg[1].len > 60)) {
|
||
|
+ printk(KERN_ERR "dvbsky_usb: too many i2c bytes[w-%d][r-%d] than 60.", msg[0].len, msg[1].len);
|
||
|
+ ret = -EOPNOTSUPP;
|
||
|
+ goto i2c_error;
|
||
|
+ }
|
||
|
+ /* write then read */
|
||
|
+ obuf[0] = 0x09;
|
||
|
+ obuf[1] = msg[0].len;
|
||
|
+ obuf[2] = msg[1].len;
|
||
|
+ obuf[3] = msg[0].addr;
|
||
|
+ memcpy(&obuf[4], msg[0].buf, msg[0].len);
|
||
|
+ ret = dvb_usbv2_generic_rw(d, obuf, msg[0].len + 4, ibuf, msg[1].len + 1);
|
||
|
+ /*dprintk("%s(): write then read status = %d\n", __func__, ibuf[0]);*/
|
||
|
+ if (!ret)
|
||
|
+ memcpy(msg[1].buf, &ibuf[1], msg[1].len);
|
||
|
+ }
|
||
|
+i2c_error:
|
||
|
+ mutex_unlock(&d->i2c_mutex);
|
||
|
+ return (ret) ? ret : num;
|
||
|
+}
|
||
|
+
|
||
|
+static u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
|
||
|
+{
|
||
|
+ return I2C_FUNC_I2C;
|
||
|
+}
|
||
|
+
|
||
|
+static struct i2c_algorithm dvbsky_i2c_algo = {
|
||
|
+ .master_xfer = dvbsky_i2c_xfer,
|
||
|
+ .functionality = dvbsky_i2c_func,
|
||
|
+};
|
||
|
+
|
||
|
+#if IS_ENABLED(CONFIG_RC_CORE)
|
||
|
+static int dvbsky_rc_query(struct dvb_usb_device *d)
|
||
|
+{
|
||
|
+ u32 code = 0xffff;
|
||
|
+ u8 obuf[2], ibuf[2], toggle;
|
||
|
+ int ret;
|
||
|
+ obuf[0] = 0x10;
|
||
|
+ ret = dvb_usbv2_generic_rw(d, obuf, 1, ibuf, 2);
|
||
|
+ if(ret == 0)
|
||
|
+ code = (ibuf[0] << 8) | ibuf[1];
|
||
|
+
|
||
|
+ if (code != 0xffff) {
|
||
|
+ dprintk("rc code: %x", code);
|
||
|
+ toggle = (code & 0x800) ? 1 : 0;
|
||
|
+ code &= 0x3f;
|
||
|
+ rc_keydown(d->rc_dev, code, toggle);
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
|
||
|
+{
|
||
|
+ rc->allowed_protos = RC_BIT_RC5;
|
||
|
+ rc->query = dvbsky_rc_query;
|
||
|
+ rc->interval = 300;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+#else
|
||
|
+ #define dvbsky_get_rc_config NULL
|
||
|
+#endif
|
||
|
+
|
||
|
+static int dvbsky_sync_ctrl(struct dvb_frontend *fe)
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = fe_to_d(fe);
|
||
|
+ return dvbsky_stream_ctrl(d, 1);
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_usb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = fe_to_d(fe);
|
||
|
+ u8 value;
|
||
|
+
|
||
|
+ if (voltage == SEC_VOLTAGE_OFF)
|
||
|
+ value = 0;
|
||
|
+ else
|
||
|
+ value = 1;
|
||
|
+ return dvbsky_gpio_ctrl(d, 0x80, value);
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
|
||
|
+{
|
||
|
+ struct dvb_usb_device *d = adap_to_d(adap);
|
||
|
+ u8 obuf[] = { 0x1e, 0x00 };
|
||
|
+ u8 ibuf[6] = { 0 };
|
||
|
+ struct i2c_msg msg[] = {
|
||
|
+ {
|
||
|
+ .addr = 0x51,
|
||
|
+ .flags = 0,
|
||
|
+ .buf = obuf,
|
||
|
+ .len = 2,
|
||
|
+ }, {
|
||
|
+ .addr = 0x51,
|
||
|
+ .flags = I2C_M_RD,
|
||
|
+ .buf = ibuf,
|
||
|
+ .len = 6,
|
||
|
+
|
||
|
+ }
|
||
|
+ };
|
||
|
+
|
||
|
+ if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
|
||
|
+ memcpy(mac, ibuf, 6);
|
||
|
+
|
||
|
+ printk(KERN_INFO "dvbsky_usb MAC address=%pM\n", mac);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static struct m88ds3103_config dvbsky_usb_ds3103_config = {
|
||
|
+ .demod_address = 0x68,
|
||
|
+ .ci_mode = 1,
|
||
|
+ .pin_ctrl = 0x83,
|
||
|
+ .ts_mode = 0,
|
||
|
+ .start_ctrl = dvbsky_sync_ctrl,
|
||
|
+ .set_voltage = dvbsky_usb_set_voltage,
|
||
|
+};
|
||
|
+
|
||
|
+static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = adap_to_priv(adap);
|
||
|
+ struct dvb_usb_device *d = adap_to_d(adap);
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ dprintk("%s()\n", __func__);
|
||
|
+
|
||
|
+ dvbsky_gpio_ctrl(d, 0x04, 1);
|
||
|
+
|
||
|
+ dvbsky_gpio_ctrl(d, 0x83, 0);
|
||
|
+ msleep(50);
|
||
|
+ dvbsky_gpio_ctrl(d, 0x83, 1);
|
||
|
+ msleep(20);
|
||
|
+
|
||
|
+ adap->fe[0] = dvb_attach(m88ds3103_attach,
|
||
|
+ &dvbsky_usb_ds3103_config,
|
||
|
+ &d->i2c_adap);
|
||
|
+ if (!adap->fe[0]) {
|
||
|
+ printk(KERN_ERR "dvbsky_s960_attach fail.");
|
||
|
+ ret = -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->has_ci = 0;
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_t330_attach(struct dvb_usb_adapter *adap)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = adap_to_priv(adap);
|
||
|
+ struct dvb_usb_device *d = adap_to_d(adap);
|
||
|
+ int ret = 0;
|
||
|
+ struct i2c_adapter *i2c_adapter;
|
||
|
+ struct i2c_client *client_demod, *client_tuner;
|
||
|
+ struct i2c_board_info info;
|
||
|
+ struct si2168_config si2168_config;
|
||
|
+ struct si2157_config si2157_config;
|
||
|
+
|
||
|
+ /* attach demod */
|
||
|
+ memset(&si2168_config, 0, sizeof(si2168_config));
|
||
|
+ si2168_config.i2c_adapter = &i2c_adapter;
|
||
|
+ si2168_config.fe = &adap->fe[0];
|
||
|
+ si2168_config.ts_mode = SI2168_TS_PARALLEL | 0x40;
|
||
|
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||
|
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
|
||
|
+ info.addr = 0x64;
|
||
|
+ info.platform_data = &si2168_config;
|
||
|
+
|
||
|
+ request_module(info.type);
|
||
|
+ client_demod = i2c_new_device(&d->i2c_adap, &info);
|
||
|
+ if (client_demod == NULL ||
|
||
|
+ client_demod->dev.driver == NULL)
|
||
|
+ goto fail_demod_device;
|
||
|
+ if (!try_module_get(client_demod->dev.driver->owner))
|
||
|
+ goto fail_demod_module;
|
||
|
+
|
||
|
+ /* attach tuner */
|
||
|
+ memset(&si2157_config, 0, sizeof(si2157_config));
|
||
|
+ si2157_config.fe = adap->fe[0];
|
||
|
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||
|
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
|
||
|
+ info.addr = 0x60;
|
||
|
+ info.platform_data = &si2157_config;
|
||
|
+
|
||
|
+ request_module(info.type);
|
||
|
+ client_tuner = i2c_new_device(i2c_adapter, &info);
|
||
|
+ if (client_tuner == NULL ||
|
||
|
+ client_tuner->dev.driver == NULL)
|
||
|
+ goto fail_tuner_device;
|
||
|
+ if (!try_module_get(client_tuner->dev.driver->owner))
|
||
|
+ goto fail_tuner_module;
|
||
|
+
|
||
|
+ state->i2c_client_demod = client_demod;
|
||
|
+ state->i2c_client_tuner = client_tuner;
|
||
|
+ return ret;
|
||
|
+fail_tuner_module:
|
||
|
+ i2c_unregister_device(client_tuner);
|
||
|
+fail_tuner_device:
|
||
|
+ module_put(client_demod->dev.driver->owner);
|
||
|
+fail_demod_module:
|
||
|
+ i2c_unregister_device(client_demod);
|
||
|
+fail_demod_device:
|
||
|
+ ret = -ENODEV;
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_t230_attach(struct dvb_usb_adapter *adap)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = adap_to_priv(adap);
|
||
|
+ struct dvb_usb_device *d = adap_to_d(adap);
|
||
|
+ int ret = 0;
|
||
|
+ struct i2c_adapter *i2c_adapter;
|
||
|
+ struct i2c_client *client_demod, *client_tuner;
|
||
|
+ struct i2c_board_info info;
|
||
|
+ struct si2168_config si2168_config;
|
||
|
+ struct si2157_config si2157_config;
|
||
|
+
|
||
|
+ /* attach demod */
|
||
|
+ memset(&si2168_config, 0, sizeof(si2168_config));
|
||
|
+ si2168_config.i2c_adapter = &i2c_adapter;
|
||
|
+ si2168_config.fe = &adap->fe[0];
|
||
|
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
|
||
|
+ si2168_config.ts_clock_inv = true;
|
||
|
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||
|
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
|
||
|
+ info.addr = 0x64;
|
||
|
+ info.platform_data = &si2168_config;
|
||
|
+
|
||
|
+ request_module(info.type);
|
||
|
+ client_demod = i2c_new_device(&d->i2c_adap, &info);
|
||
|
+ if (client_demod == NULL ||
|
||
|
+ client_demod->dev.driver == NULL)
|
||
|
+ goto fail_demod_device;
|
||
|
+ if (!try_module_get(client_demod->dev.driver->owner))
|
||
|
+ goto fail_demod_module;
|
||
|
+
|
||
|
+ /* attach tuner */
|
||
|
+ memset(&si2157_config, 0, sizeof(si2157_config));
|
||
|
+ si2157_config.fe = adap->fe[0];
|
||
|
+ si2157_config.if_port = 1;
|
||
|
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||
|
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
|
||
|
+ info.addr = 0x60;
|
||
|
+ info.platform_data = &si2157_config;
|
||
|
+
|
||
|
+ request_module(info.type);
|
||
|
+ client_tuner = i2c_new_device(i2c_adapter, &info);
|
||
|
+ if (client_tuner == NULL ||
|
||
|
+ client_tuner->dev.driver == NULL)
|
||
|
+ goto fail_tuner_device;
|
||
|
+ if (!try_module_get(client_tuner->dev.driver->owner))
|
||
|
+ goto fail_tuner_module;
|
||
|
+
|
||
|
+ state->i2c_client_demod = client_demod;
|
||
|
+ state->i2c_client_tuner = client_tuner;
|
||
|
+ return ret;
|
||
|
+fail_tuner_module:
|
||
|
+ i2c_unregister_device(client_tuner);
|
||
|
+fail_tuner_device:
|
||
|
+ module_put(client_demod->dev.driver->owner);
|
||
|
+fail_demod_module:
|
||
|
+ i2c_unregister_device(client_demod);
|
||
|
+fail_demod_device:
|
||
|
+ ret = -ENODEV;
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = adap_to_priv(adap);
|
||
|
+ struct dvb_usb_device *d = adap_to_d(adap);
|
||
|
+ int ret = 0;
|
||
|
+ struct i2c_adapter *i2c_adapter;
|
||
|
+ struct i2c_client *client_demod, *client_tuner;
|
||
|
+ struct i2c_board_info info;
|
||
|
+ struct si2168_config si2168_config;
|
||
|
+ struct si2157_config si2157_config;
|
||
|
+
|
||
|
+ /* attach demod */
|
||
|
+ memset(&si2168_config, 0, sizeof(si2168_config));
|
||
|
+ si2168_config.i2c_adapter = &i2c_adapter;
|
||
|
+ si2168_config.fe = &adap->fe[0];
|
||
|
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
|
||
|
+ si2168_config.ts_clock_inv = 1;
|
||
|
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||
|
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
|
||
|
+ info.addr = 0x64;
|
||
|
+ info.platform_data = &si2168_config;
|
||
|
+
|
||
|
+ request_module(info.type);
|
||
|
+ client_demod = i2c_new_device(&d->i2c_adap, &info);
|
||
|
+ if (client_demod == NULL ||
|
||
|
+ client_demod->dev.driver == NULL)
|
||
|
+ goto fail_demod_device;
|
||
|
+ if (!try_module_get(client_demod->dev.driver->owner))
|
||
|
+ goto fail_demod_module;
|
||
|
+
|
||
|
+ /* attach tuner */
|
||
|
+ memset(&si2157_config, 0, sizeof(si2157_config));
|
||
|
+ si2157_config.fe = adap->fe[0];
|
||
|
+ si2157_config.if_port = 0;
|
||
|
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||
|
+ strlcpy(info.type, "si2141", I2C_NAME_SIZE);
|
||
|
+ info.addr = 0x60;
|
||
|
+ info.platform_data = &si2157_config;
|
||
|
+
|
||
|
+ request_module("si2157");
|
||
|
+ client_tuner = i2c_new_device(i2c_adapter, &info);
|
||
|
+ if (client_tuner == NULL ||
|
||
|
+ client_tuner->dev.driver == NULL)
|
||
|
+ goto fail_tuner_device;
|
||
|
+ if (!try_module_get(client_tuner->dev.driver->owner))
|
||
|
+ goto fail_tuner_module;
|
||
|
+
|
||
|
+ state->i2c_client_demod = client_demod;
|
||
|
+ state->i2c_client_tuner = client_tuner;
|
||
|
+ return ret;
|
||
|
+fail_tuner_module:
|
||
|
+ i2c_unregister_device(client_tuner);
|
||
|
+fail_tuner_device:
|
||
|
+ module_put(client_demod->dev.driver->owner);
|
||
|
+fail_demod_module:
|
||
|
+ i2c_unregister_device(client_demod);
|
||
|
+fail_demod_device:
|
||
|
+ ret = -ENODEV;
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_mygica_t230c2_attach(struct dvb_usb_adapter *adap)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = adap_to_priv(adap);
|
||
|
+ struct dvb_usb_device *d = adap_to_d(adap);
|
||
|
+ int ret = 0;
|
||
|
+ struct i2c_adapter *i2c_adapter;
|
||
|
+ struct i2c_client *client_demod, *client_tuner;
|
||
|
+ struct i2c_board_info info;
|
||
|
+ struct si2168_config si2168_config;
|
||
|
+ struct si2157_config si2157_config;
|
||
|
+
|
||
|
+ /* attach demod */
|
||
|
+ memset(&si2168_config, 0, sizeof(si2168_config));
|
||
|
+ si2168_config.i2c_adapter = &i2c_adapter;
|
||
|
+ si2168_config.fe = &adap->fe[0];
|
||
|
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
|
||
|
+ si2168_config.ts_clock_inv = 1;
|
||
|
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||
|
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
|
||
|
+ info.addr = 0x64;
|
||
|
+ info.platform_data = &si2168_config;
|
||
|
+
|
||
|
+ request_module(info.type);
|
||
|
+ client_demod = i2c_new_device(&d->i2c_adap, &info);
|
||
|
+ if (client_demod == NULL ||
|
||
|
+ client_demod->dev.driver == NULL)
|
||
|
+ goto fail_demod_device;
|
||
|
+ if (!try_module_get(client_demod->dev.driver->owner))
|
||
|
+ goto fail_demod_module;
|
||
|
+
|
||
|
+ /* attach tuner */
|
||
|
+ memset(&si2157_config, 0, sizeof(si2157_config));
|
||
|
+ si2157_config.fe = adap->fe[0];
|
||
|
+ si2157_config.if_port = 0;
|
||
|
+ memset(&info, 0, sizeof(struct i2c_board_info));
|
||
|
+ strlcpy(info.type, "si2141", I2C_NAME_SIZE);
|
||
|
+ info.addr = 0x60;
|
||
|
+ info.platform_data = &si2157_config;
|
||
|
+
|
||
|
+ request_module("si2157");
|
||
|
+ client_tuner = i2c_new_device(i2c_adapter, &info);
|
||
|
+ if (client_tuner == NULL ||
|
||
|
+ client_tuner->dev.driver == NULL)
|
||
|
+ goto fail_tuner_device;
|
||
|
+ if (!try_module_get(client_tuner->dev.driver->owner))
|
||
|
+ goto fail_tuner_module;
|
||
|
+
|
||
|
+ state->i2c_client_demod = client_demod;
|
||
|
+ state->i2c_client_tuner = client_tuner;
|
||
|
+ return ret;
|
||
|
+fail_tuner_module:
|
||
|
+ i2c_unregister_device(client_tuner);
|
||
|
+fail_tuner_device:
|
||
|
+ module_put(client_demod->dev.driver->owner);
|
||
|
+fail_demod_module:
|
||
|
+ i2c_unregister_device(client_demod);
|
||
|
+fail_demod_device:
|
||
|
+ ret = -ENODEV;
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
|
||
|
+{
|
||
|
+ return WARM;
|
||
|
+}
|
||
|
+
|
||
|
+static int dvbsky_init(struct dvb_usb_device *d)
|
||
|
+{
|
||
|
+ struct dvbsky_state *state = d_to_priv(d);
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ /* use default interface */
|
||
|
+ ret = usb_set_interface(d->udev, 0, 0);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ mutex_init(&state->stream_mutex);
|
||
|
+
|
||
|
+ /* attach CI */
|
||
|
+ if (state->has_ci) {
|
||
|
+ dvbsky_gpio_ctrl(d, 0xc0, 1);
|
||
|
+ msleep(100);
|
||
|
+ dvbsky_gpio_ctrl(d, 0xc0, 0);
|
||
|
+ msleep(50);
|
||
|
+ state->ci_attached = 0;
|
||
|
+ ret = dvbsky_ci_init(d);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static void dvbsky_exit(struct dvb_usb_device *d)
|
||
|
+{
|
||
|
+ return dvbsky_ci_release(d);
|
||
|
+}
|
||
|
+
|
||
|
+/* DVB USB Driver stuff */
|
||
|
+static struct dvb_usb_device_properties dvbsky_s960_props = {
|
||
|
+ .driver_name = KBUILD_MODNAME,
|
||
|
+ .owner = THIS_MODULE,
|
||
|
+ .adapter_nr = adapter_nr,
|
||
|
+ .size_of_priv = sizeof(struct dvbsky_state),
|
||
|
+
|
||
|
+ .generic_bulk_ctrl_endpoint = 0x01,
|
||
|
+ .generic_bulk_ctrl_endpoint_response = 0x81,
|
||
|
+
|
||
|
+ .i2c_algo = &dvbsky_i2c_algo,
|
||
|
+ .frontend_attach = dvbsky_s960_attach,
|
||
|
+ .init = dvbsky_init,
|
||
|
+ .get_rc_config = dvbsky_get_rc_config,
|
||
|
+ .streaming_ctrl = dvbsky_streaming_ctrl,
|
||
|
+ .identify_state = dvbsky_identify_state,
|
||
|
+ .exit = dvbsky_exit,
|
||
|
+ .read_mac_address = dvbsky_read_mac_addr,
|
||
|
+
|
||
|
+ .num_adapters = 1,
|
||
|
+ .adapter = {
|
||
|
+ {
|
||
|
+ .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
|
||
|
+ }
|
||
|
+ }
|
||
|
+};
|
||
|
+
|
||
|
+static struct dvb_usb_device_properties dvbsky_t330_props = {
|
||
|
+ .driver_name = KBUILD_MODNAME,
|
||
|
+ .owner = THIS_MODULE,
|
||
|
+ .adapter_nr = adapter_nr,
|
||
|
+ .size_of_priv = sizeof(struct dvbsky_state),
|
||
|
+
|
||
|
+ .generic_bulk_ctrl_endpoint = 0x01,
|
||
|
+ .generic_bulk_ctrl_endpoint_response = 0x81,
|
||
|
+ .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
|
||
|
+
|
||
|
+ .i2c_algo = &dvbsky_i2c_algo,
|
||
|
+ .frontend_attach = dvbsky_t330_attach,
|
||
|
+ .init = dvbsky_init,
|
||
|
+ .get_rc_config = dvbsky_get_rc_config,
|
||
|
+ .streaming_ctrl = dvbsky_streaming_ctrl,
|
||
|
+ .identify_state = dvbsky_identify_state,
|
||
|
+ .exit = dvbsky_exit,
|
||
|
+ .read_mac_address = dvbsky_read_mac_addr,
|
||
|
+
|
||
|
+ .num_adapters = 1,
|
||
|
+ .adapter = {
|
||
|
+ {
|
||
|
+ .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
|
||
|
+ }
|
||
|
+ }
|
||
|
+};
|
||
|
+
|
||
|
+static struct dvb_usb_device_properties mygica_t230_props = {
|
||
|
+ .driver_name = KBUILD_MODNAME,
|
||
|
+ .owner = THIS_MODULE,
|
||
|
+ .adapter_nr = adapter_nr,
|
||
|
+ .size_of_priv = sizeof(struct dvbsky_state),
|
||
|
+
|
||
|
+ .generic_bulk_ctrl_endpoint = 0x01,
|
||
|
+ .generic_bulk_ctrl_endpoint_response = 0x81,
|
||
|
+ .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
|
||
|
+
|
||
|
+ .i2c_algo = &dvbsky_i2c_algo,
|
||
|
+ .frontend_attach = dvbsky_t230_attach,
|
||
|
+ .init = dvbsky_init,
|
||
|
+ .get_rc_config = dvbsky_get_rc_config,
|
||
|
+ .streaming_ctrl = dvbsky_streaming_ctrl,
|
||
|
+ .identify_state = dvbsky_identify_state,
|
||
|
+ .exit = dvbsky_exit,
|
||
|
+ .read_mac_address = dvbsky_read_mac_addr,
|
||
|
+
|
||
|
+ .num_adapters = 1,
|
||
|
+ .adapter = {
|
||
|
+ {
|
||
|
+ .stream = DVB_USB_STREAM_BULK(0x02, 5, 8192),
|
||
|
+ }
|
||
|
+ }
|
||
|
+};
|
||
|
+
|
||
|
+static struct dvb_usb_device_properties mygica_t230c_props = {
|
||
|
+ .driver_name = KBUILD_MODNAME,
|
||
|
+ .owner = THIS_MODULE,
|
||
|
+ .adapter_nr = adapter_nr,
|
||
|
+ .size_of_priv = sizeof(struct dvbsky_state),
|
||
|
+
|
||
|
+ .generic_bulk_ctrl_endpoint = 0x01,
|
||
|
+ .generic_bulk_ctrl_endpoint_response = 0x81,
|
||
|
+ .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
|
||
|
+
|
||
|
+ .i2c_algo = &dvbsky_i2c_algo,
|
||
|
+ .frontend_attach = dvbsky_mygica_t230c_attach,
|
||
|
+ .init = dvbsky_init,
|
||
|
+ .get_rc_config = dvbsky_get_rc_config,
|
||
|
+ .streaming_ctrl = dvbsky_streaming_ctrl,
|
||
|
+ .identify_state = dvbsky_identify_state,
|
||
|
+ .exit = dvbsky_exit,
|
||
|
+
|
||
|
+ .num_adapters = 1,
|
||
|
+ .adapter = {
|
||
|
+ {
|
||
|
+ .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
|
||
|
+ }
|
||
|
+ }
|
||
|
+};
|
||
|
+
|
||
|
+static struct dvb_usb_device_properties mygica_t230c2_props = {
|
||
|
+ .driver_name = KBUILD_MODNAME,
|
||
|
+ .owner = THIS_MODULE,
|
||
|
+ .adapter_nr = adapter_nr,
|
||
|
+ .size_of_priv = sizeof(struct dvbsky_state),
|
||
|
+
|
||
|
+ .generic_bulk_ctrl_endpoint = 0x01,
|
||
|
+ .generic_bulk_ctrl_endpoint_response = 0x81,
|
||
|
+ .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
|
||
|
+
|
||
|
+ .i2c_algo = &dvbsky_i2c_algo,
|
||
|
+ .frontend_attach = dvbsky_mygica_t230c2_attach,
|
||
|
+ .init = dvbsky_init,
|
||
|
+ .get_rc_config = dvbsky_get_rc_config,
|
||
|
+ .streaming_ctrl = dvbsky_streaming_ctrl,
|
||
|
+ .identify_state = dvbsky_identify_state,
|
||
|
+ .exit = dvbsky_exit,
|
||
|
+
|
||
|
+ .num_adapters = 1,
|
||
|
+ .adapter = {
|
||
|
+ {
|
||
|
+ .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
|
||
|
+ }
|
||
|
+ }
|
||
|
+};
|
||
|
+
|
||
|
+static const struct usb_device_id dvbsky_id_table[] = {
|
||
|
+ { DVB_USB_DEVICE(0x0572, 0x6831,
|
||
|
+ &dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
|
||
|
+ { DVB_USB_DEVICE(0x0572, 0x0320,
|
||
|
+ &dvbsky_t330_props, "DVBSky T330", RC_MAP_DVBSKY) },
|
||
|
+ { DVB_USB_DEVICE(0x0572, 0xc68a,
|
||
|
+ &mygica_t230c2_props, "MyGica Mini DVB-T2 USB Stick T230C2",
|
||
|
+ RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
|
||
|
+ { DVB_USB_DEVICE(0x0572, 0xc689,
|
||
|
+ &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C",
|
||
|
+ RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
|
||
|
+ { DVB_USB_DEVICE(0x0572, 0xc688,
|
||
|
+ &mygica_t230_props, "MyGica Mini DVB-T2 USB Stick T230",
|
||
|
+ RC_MAP_EMPTY) },
|
||
|
+ { }
|
||
|
+};
|
||
|
+MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
|
||
|
+
|
||
|
+static struct usb_driver dvbsky_usb_driver = {
|
||
|
+ .name = KBUILD_MODNAME,
|
||
|
+ .id_table = dvbsky_id_table,
|
||
|
+ .probe = dvb_usbv2_probe,
|
||
|
+ .disconnect = dvb_usbv2_disconnect,
|
||
|
+ .suspend = dvb_usbv2_suspend,
|
||
|
+ .resume = dvb_usbv2_resume,
|
||
|
+ .reset_resume = dvb_usbv2_reset_resume,
|
||
|
+ .no_dynamic_id = 1,
|
||
|
+ .soft_unbind = 1,
|
||
|
+};
|
||
|
+
|
||
|
+module_usb_driver(dvbsky_usb_driver);
|
||
|
+
|
||
|
+MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
|
||
|
+MODULE_DESCRIPTION("Driver for DVBSky USB2.0");
|
||
|
+MODULE_LICENSE("GPL");
|
||
|
diff -urN a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
|
||
|
--- a/drivers/media/usb/dvb-usb-v2/Kconfig 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig 2013-05-03 17:45:35.000000000 +0800
|
||
|
@@ -149,3 +149,10 @@
|
||
|
help
|
||
|
Say Y here to support the Realtek RTL28xxU DVB USB receiver.
|
||
|
|
||
|
+config DVB_USB_DVBSKY
|
||
|
+ tristate "DVBSky USB2.0 support"
|
||
|
+ depends on DVB_USB_V2
|
||
|
+ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
|
||
|
+ help
|
||
|
+ Say Y here to support the USB receivers from DVBSky.
|
||
|
+
|
||
|
diff -urN a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
|
||
|
--- a/drivers/media/usb/dvb-usb-v2/Makefile 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/drivers/media/usb/dvb-usb-v2/Makefile 2013-02-17 12:03:00.000000000 +0800
|
||
|
@@ -43,6 +43,9 @@
|
||
|
dvb-usb-rtl28xxu-objs := rtl28xxu.o
|
||
|
obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
|
||
|
|
||
|
+dvb-usb-dvbsky-objs := dvbsky.o
|
||
|
+obj-$(CONFIG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o
|
||
|
+
|
||
|
ccflags-y += -I$(srctree)/drivers/media/dvb-core
|
||
|
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
|
||
|
ccflags-y += -I$(srctree)/drivers/media/tuners
|
||
|
diff -urN a/include/media/rc-map.h b/include/media/rc-map.h
|
||
|
--- a/include/media/rc-map.h 2013-04-29 08:36:01.000000000 +0800
|
||
|
+++ b/include/media/rc-map.h 2013-05-03 17:02:46.000000000 +0800
|
||
|
@@ -118,6 +118,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"
|