mirror of
https://github.com/LibreELEC/LibreELEC.tv
synced 2025-09-24 19:46:01 +07:00
4216 lines
116 KiB
Diff
4216 lines
116 KiB
Diff
diff -uprN linux-3.2.10.orig/drivers/media/dvb/dvb-usb/dw2102.c linux-3.2.10/drivers/media/dvb/dvb-usb/dw2102.c
|
|
--- linux-3.2.10.orig/drivers/media/dvb/dvb-usb/dw2102.c 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/dvb/dvb-usb/dw2102.c 2012-03-16 10:55:52.000000000 +0100
|
|
@@ -3,6 +3,7 @@
|
|
* TeVii S600, S630, S650, S660, S480,
|
|
* Prof 1100, 7500,
|
|
* Geniatech SU3000 Cards
|
|
+ * DVBSKY S860
|
|
* Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
@@ -19,6 +20,7 @@
|
|
#include "stb6000.h"
|
|
#include "eds1547.h"
|
|
#include "cx24116.h"
|
|
+#include "m88ds3103.h"
|
|
#include "tda1002x.h"
|
|
#include "mt312.h"
|
|
#include "zl10039.h"
|
|
@@ -80,6 +82,9 @@
|
|
#define DW2102_RC_QUERY (0x1a00)
|
|
#define DW2102_LED_CTRL (0x1b00)
|
|
|
|
+/*Bst device index in table*/
|
|
+#define BST_6830_Index 15
|
|
+
|
|
#define err_str "did not find the firmware file. (%s) " \
|
|
"Please see linux/Documentation/dvb/ for more details " \
|
|
"on firmware-problems."
|
|
@@ -881,6 +886,44 @@ static int s660_set_voltage(struct dvb_f
|
|
|
|
return 0;
|
|
}
|
|
+
|
|
+static int bstusb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
|
+{
|
|
+
|
|
+ struct dvb_usb_adapter *udev_adap =
|
|
+ (struct dvb_usb_adapter *)(fe->dvb->priv);
|
|
+
|
|
+ u8 obuf[3] = { 0xe, 0x80, 0 };
|
|
+ u8 ibuf[] = { 0 };
|
|
+
|
|
+ info("US6830: %s!\n", __func__);
|
|
+
|
|
+ if (voltage == SEC_VOLTAGE_OFF)
|
|
+ obuf[2] = 0;
|
|
+ else
|
|
+ obuf[2] = 1;
|
|
+
|
|
+ if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
|
|
+ err("command 0x0e transfer failed.");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bstusb_restart(struct dvb_frontend *fe)
|
|
+{
|
|
+
|
|
+ struct dvb_usb_adapter *udev_adap =
|
|
+ (struct dvb_usb_adapter *)(fe->dvb->priv);
|
|
+
|
|
+ u8 obuf[3] = { 0x36, 3, 0 };
|
|
+ u8 ibuf[] = { 0 };
|
|
+
|
|
+
|
|
+ if (dvb_usb_generic_rw(udev_adap->dev, obuf, 3, ibuf, 1, 0) < 0)
|
|
+ err("command 0x36 transfer failed.");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
|
|
static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
|
|
{
|
|
@@ -987,6 +1030,24 @@ static struct ds3000_config su3000_ds300
|
|
.ci_mode = 1,
|
|
};
|
|
|
|
+static struct m88ds3103_config US6830_ds3103_config = {
|
|
+ .demod_address = 0x68,
|
|
+ .ci_mode = 1,
|
|
+ .pin_ctrl = 0x83,
|
|
+ .ts_mode = 0,
|
|
+ .start_ctrl = bstusb_restart,
|
|
+ .set_voltage = bstusb_set_voltage,
|
|
+};
|
|
+
|
|
+static struct m88ds3103_config US6832_ds3103_config = {
|
|
+ .demod_address = 0x68,
|
|
+ .ci_mode = 1,
|
|
+ .pin_ctrl = 0x80,
|
|
+ .ts_mode = 0,
|
|
+ .start_ctrl = bstusb_restart,
|
|
+ .set_voltage = bstusb_set_voltage,
|
|
+};
|
|
+
|
|
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
|
|
{
|
|
struct dvb_tuner_ops *tuner_ops = NULL;
|
|
@@ -1214,6 +1275,72 @@ static int su3000_frontend_attach(struct
|
|
return 0;
|
|
}
|
|
|
|
+static int US6830_frontend_attach(struct dvb_usb_adapter *d)
|
|
+{
|
|
+ u8 obuf[3] = { 0xe, 0x83, 0 };
|
|
+ u8 ibuf[] = { 0 };
|
|
+
|
|
+
|
|
+ info("US6830: %s!\n", __func__);
|
|
+
|
|
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
|
|
+ err("command 0x0e transfer failed.");
|
|
+
|
|
+ obuf[0] = 0xe;
|
|
+ obuf[1] = 0x83;
|
|
+ obuf[2] = 1;
|
|
+
|
|
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
|
|
+ err("command 0x0e transfer failed.");
|
|
+
|
|
+ obuf[0] = 0x51;
|
|
+
|
|
+ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
|
|
+ err("command 0x51 transfer failed.");
|
|
+
|
|
+ d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6830_ds3103_config,
|
|
+ &d->dev->i2c_adap);
|
|
+ if (d->fe_adap[0].fe == NULL)
|
|
+ return -EIO;
|
|
+
|
|
+ info("Attached DS3000!\n");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int US6832_frontend_attach(struct dvb_usb_adapter *d)
|
|
+{
|
|
+ u8 obuf[3] = { 0xe, 0x83, 0 };
|
|
+ u8 ibuf[] = { 0 };
|
|
+
|
|
+
|
|
+ info("US6832: %s!\n", __func__);
|
|
+
|
|
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
|
|
+ err("command 0x0e transfer failed.");
|
|
+
|
|
+ obuf[0] = 0xe;
|
|
+ obuf[1] = 0x83;
|
|
+ obuf[2] = 1;
|
|
+
|
|
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
|
|
+ err("command 0x0e transfer failed.");
|
|
+
|
|
+ obuf[0] = 0x51;
|
|
+
|
|
+ if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
|
|
+ err("command 0x51 transfer failed.");
|
|
+
|
|
+ d->fe_adap[0].fe = dvb_attach(m88ds3103_attach, &US6832_ds3103_config,
|
|
+ &d->dev->i2c_adap);
|
|
+ if (d->fe_adap[0].fe == NULL)
|
|
+ return -EIO;
|
|
+
|
|
+ info("Attached DS3000!\n");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
|
|
{
|
|
dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
|
|
@@ -1451,6 +1578,9 @@ static struct usb_device_id dw2102_table
|
|
{USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
|
|
{USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
|
|
{USB_DEVICE(0x1f4d, 0x3100)},
|
|
+ {USB_DEVICE(0x0572, 0x6830)},
|
|
+ {USB_DEVICE(0x0572, 0x6831)},
|
|
+ {USB_DEVICE(0x0572, 0x6832)},
|
|
{ }
|
|
};
|
|
|
|
@@ -1856,6 +1986,107 @@ static struct dvb_usb_device_properties
|
|
}
|
|
};
|
|
|
|
+static struct dvb_usb_device_properties US6830_properties = {
|
|
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
|
+ .usb_ctrl = DEVICE_SPECIFIC,
|
|
+ .size_of_priv = sizeof(struct su3000_state),
|
|
+ .power_ctrl = su3000_power_ctrl,
|
|
+ .num_adapters = 1,
|
|
+ .identify_state = su3000_identify_state,
|
|
+ .i2c_algo = &su3000_i2c_algo,
|
|
+
|
|
+ .rc.legacy = {
|
|
+ .rc_map_table = rc_map_su3000_table,
|
|
+ .rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
|
|
+ .rc_interval = 150,
|
|
+ .rc_query = dw2102_rc_query,
|
|
+ },
|
|
+
|
|
+ .read_mac_address = su3000_read_mac_address,
|
|
+
|
|
+ .generic_bulk_ctrl_endpoint = 0x01,
|
|
+
|
|
+ .adapter = {
|
|
+ {
|
|
+ .num_frontends = 1,
|
|
+ .fe = {{
|
|
+ .streaming_ctrl = su3000_streaming_ctrl,
|
|
+ .frontend_attach = US6830_frontend_attach,
|
|
+ .stream = {
|
|
+ .type = USB_BULK,
|
|
+ .count = 8,
|
|
+ .endpoint = 0x82,
|
|
+ .u = {
|
|
+ .bulk = {
|
|
+ .buffersize = 4096,
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }},
|
|
+ }
|
|
+ },
|
|
+ .num_device_descs = 2,
|
|
+ .devices = {
|
|
+ { "Bestunar US6830 HD",
|
|
+ { &dw2102_table[BST_6830_Index], NULL },
|
|
+ { NULL },
|
|
+ },
|
|
+ { "Bestunar US6831 HD",
|
|
+ { &dw2102_table[BST_6830_Index+1], NULL },
|
|
+ { NULL },
|
|
+ },
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct dvb_usb_device_properties US6832_properties = {
|
|
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
|
+ .usb_ctrl = DEVICE_SPECIFIC,
|
|
+ .size_of_priv = sizeof(struct su3000_state),
|
|
+ .power_ctrl = su3000_power_ctrl,
|
|
+ .num_adapters = 1,
|
|
+ .identify_state = su3000_identify_state,
|
|
+ .i2c_algo = &su3000_i2c_algo,
|
|
+
|
|
+ .rc.legacy = {
|
|
+ .rc_map_table = rc_map_su3000_table,
|
|
+ .rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
|
|
+ .rc_interval = 150,
|
|
+ .rc_query = dw2102_rc_query,
|
|
+ },
|
|
+
|
|
+ .read_mac_address = su3000_read_mac_address,
|
|
+
|
|
+ .generic_bulk_ctrl_endpoint = 0x01,
|
|
+
|
|
+ .adapter = {
|
|
+ {
|
|
+ .num_frontends = 1,
|
|
+ .fe = {{
|
|
+ .streaming_ctrl = su3000_streaming_ctrl,
|
|
+ .frontend_attach = US6832_frontend_attach,
|
|
+ .stream = {
|
|
+ .type = USB_BULK,
|
|
+ .count = 8,
|
|
+ .endpoint = 0x82,
|
|
+ .u = {
|
|
+ .bulk = {
|
|
+ .buffersize = 4096,
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }},
|
|
+ }
|
|
+ },
|
|
+ .num_device_descs = 1,
|
|
+ .devices = {
|
|
+ { "Bestunar US6832 HD",
|
|
+ { &dw2102_table[BST_6830_Index+2], NULL },
|
|
+ { NULL },
|
|
+ },
|
|
+
|
|
+ }
|
|
+};
|
|
+
|
|
static int dw2102_probe(struct usb_interface *intf,
|
|
const struct usb_device_id *id)
|
|
{
|
|
@@ -1915,6 +2146,10 @@ static int dw2102_probe(struct usb_inter
|
|
0 == dvb_usb_device_init(intf, p7500,
|
|
THIS_MODULE, NULL, adapter_nr) ||
|
|
0 == dvb_usb_device_init(intf, &su3000_properties,
|
|
+ THIS_MODULE, NULL, adapter_nr) ||
|
|
+ 0 == dvb_usb_device_init(intf, &US6830_properties,
|
|
+ THIS_MODULE, NULL, adapter_nr) ||
|
|
+ 0 == dvb_usb_device_init(intf, &US6832_properties,
|
|
THIS_MODULE, NULL, adapter_nr))
|
|
return 0;
|
|
|
|
diff -uprN linux-3.2.10.orig/drivers/media/dvb/dvb-usb/Kconfig linux-3.2.10/drivers/media/dvb/dvb-usb/Kconfig
|
|
--- linux-3.2.10.orig/drivers/media/dvb/dvb-usb/Kconfig 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/dvb/dvb-usb/Kconfig 2012-03-16 10:55:52.000000000 +0100
|
|
@@ -279,6 +279,7 @@ config DVB_USB_DW2102
|
|
select DVB_STV0288 if !DVB_FE_CUSTOMISE
|
|
select DVB_STB6000 if !DVB_FE_CUSTOMISE
|
|
select DVB_CX24116 if !DVB_FE_CUSTOMISE
|
|
+ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
|
|
select DVB_SI21XX if !DVB_FE_CUSTOMISE
|
|
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
|
|
select DVB_MT312 if !DVB_FE_CUSTOMISE
|
|
diff -uprN linux-3.2.10.orig/drivers/media/dvb/frontends/Kconfig linux-3.2.10/drivers/media/dvb/frontends/Kconfig
|
|
--- linux-3.2.10.orig/drivers/media/dvb/frontends/Kconfig 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/dvb/frontends/Kconfig 2012-03-16 10:55:57.000000000 +0100
|
|
@@ -214,6 +214,13 @@ config DVB_CX24116
|
|
help
|
|
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
|
|
|
+config DVB_M88DS3103
|
|
+ tristate "Montage DS3103 based"
|
|
+ depends on DVB_CORE && I2C
|
|
+ default m if DVB_FE_CUSTOMISE
|
|
+ help
|
|
+ A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
|
+
|
|
config DVB_SI21XX
|
|
tristate "Silicon Labs SI21XX based"
|
|
depends on DVB_CORE && I2C
|
|
diff -uprN linux-3.2.10.orig/drivers/media/dvb/frontends/m88ds3103.c linux-3.2.10/drivers/media/dvb/frontends/m88ds3103.c
|
|
--- linux-3.2.10.orig/drivers/media/dvb/frontends/m88ds3103.c 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/dvb/frontends/m88ds3103.c 2012-03-16 10:55:57.000000000 +0100
|
|
@@ -0,0 +1,1811 @@
|
|
+/*
|
|
+ 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>
|
|
+
|
|
+ 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"
|
|
+
|
|
+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)
|
|
+
|
|
+#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
|
|
+
|
|
+/* 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,
|
|
+};
|
|
+
|
|
+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 */
|
|
+};
|
|
+
|
|
+/*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;
|
|
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
|
+ *status = 0;
|
|
+ dprintk("%s()\n", __func__);
|
|
+
|
|
+ switch (c->delivery_system){
|
|
+ case SYS_DVBS:
|
|
+ if ((m88ds3103_readreg(state, 0xd1) & 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:
|
|
+ if ((m88ds3103_readreg(state, 0x0d) & 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;
|
|
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
|
+ u8 tmp1, tmp2, tmp3;
|
|
+ u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0;
|
|
+
|
|
+ dprintk("%s()\n", __func__);
|
|
+
|
|
+ switch (c->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;
|
|
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
|
+ 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__);
|
|
+
|
|
+ switch (c->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;
|
|
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
|
+ u8 tmp1, tmp2, tmp3, data;
|
|
+
|
|
+ dprintk("%s()\n", __func__);
|
|
+
|
|
+ switch (c->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;
|
|
+
|
|
+ /* 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_property(struct dvb_frontend *fe,
|
|
+ struct dtv_property *tvp)
|
|
+{
|
|
+ dprintk("%s(..)\n", __func__);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int m88ds3103_get_property(struct dvb_frontend *fe,
|
|
+ struct dtv_property *tvp)
|
|
+{
|
|
+ dprintk("%s(..)\n", __func__);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+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_set_frontend(struct dvb_frontend *fe,
|
|
+ struct dvb_frontend_parameters *p)
|
|
+{
|
|
+ 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;
|
|
+ u16 value, ndiv, lpf_coeff;
|
|
+ u32 f3db, gdiv28;
|
|
+ u8 val1,val2,data, RFgain;
|
|
+
|
|
+ dprintk("%s() ", __func__);
|
|
+
|
|
+ if (state->config->set_ts_params)
|
|
+ state->config->set_ts_params(fe, 0);
|
|
+
|
|
+ div4 = 0;
|
|
+ if(state->tuner_id == TS2022_ID){
|
|
+ m88ds3103_tuner_writereg(state, 0x10, 0x0a);
|
|
+ m88ds3103_tuner_writereg(state, 0x11, 0x40);
|
|
+ if (p->frequency < 1103000) {
|
|
+ m88ds3103_tuner_writereg(state, 0x10, 0x1b);
|
|
+ div4 = 1;
|
|
+ ndiv = (p->frequency * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;
|
|
+ }else {
|
|
+ ndiv = (p->frequency * (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 (p->frequency < 1146000){
|
|
+ m88ds3103_tuner_writereg(state, 0x10, 0x11);
|
|
+ div4 = 1;
|
|
+ ndiv = (p->frequency * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ;
|
|
+ }else{
|
|
+ m88ds3103_tuner_writereg(state, 0x10, 0x01);
|
|
+ ndiv = (p->frequency * (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(( p->frequency >= 1650000 ) && (p->frequency <= 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 = (p->frequency * (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 += FREQ_OFFSET_AT_SMALL_SYM_RATE_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 - p->frequency;
|
|
+
|
|
+ /* 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 (c->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->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->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->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, offset_khz);
|
|
+
|
|
+ /* ds3000 out of software reset */
|
|
+ m88ds3103_writereg(state, 0x00, 0x00);
|
|
+ /* start ds3000 build-in uC */
|
|
+ m88ds3103_writereg(state, 0xb2, 0x00);
|
|
+
|
|
+ for (i = 0; i < 30 ; i++) {
|
|
+ m88ds3103_read_status(fe, &status);
|
|
+ if (status && FE_HAS_LOCK){
|
|
+ if(state->config->start_ctrl){
|
|
+ if(state->first_lock == 0){
|
|
+ state->config->start_ctrl(fe);
|
|
+ state->first_lock = 1;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ msleep(10);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int m88ds3103_tune(struct dvb_frontend *fe,
|
|
+ struct dvb_frontend_parameters *params,
|
|
+ unsigned int mode_flags,
|
|
+ unsigned int *delay,
|
|
+ fe_status_t *status)
|
|
+{
|
|
+ *delay = HZ / 5;
|
|
+ if (params) {
|
|
+ int ret = m88ds3103_set_frontend(fe, params);
|
|
+ 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 = {
|
|
+
|
|
+ .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_property = m88ds3103_set_property,
|
|
+ .get_property = m88ds3103_get_property,
|
|
+ .set_frontend = m88ds3103_set_frontend,
|
|
+};
|
|
+
|
|
+MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware");
|
|
+MODULE_AUTHOR("Max nibble");
|
|
+MODULE_LICENSE("GPL");
|
|
diff -uprN linux-3.2.10.orig/drivers/media/dvb/frontends/m88ds3103.h linux-3.2.10/drivers/media/dvb/frontends/m88ds3103.h
|
|
--- linux-3.2.10.orig/drivers/media/dvb/frontends/m88ds3103.h 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/dvb/frontends/m88ds3103.h 2012-03-16 10:55:57.000000000 +0100
|
|
@@ -0,0 +1,54 @@
|
|
+/*
|
|
+ Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver
|
|
+ Copyright (C) 2011 Max nibble<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.
|
|
+
|
|
+ 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 -uprN linux-3.2.10.orig/drivers/media/dvb/frontends/Makefile linux-3.2.10/drivers/media/dvb/frontends/Makefile
|
|
--- linux-3.2.10.orig/drivers/media/dvb/frontends/Makefile 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/dvb/frontends/Makefile 2012-03-16 10:55:57.000000000 +0100
|
|
@@ -95,4 +95,5 @@ obj-$(CONFIG_DVB_TDA18271C2DD) += tda182
|
|
obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
|
|
obj-$(CONFIG_DVB_A8293) += a8293.o
|
|
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
|
|
+obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
|
|
|
|
diff -uprN linux-3.2.10.orig/drivers/media/rc/keymaps/Makefile linux-3.2.10/drivers/media/rc/keymaps/Makefile
|
|
--- linux-3.2.10.orig/drivers/media/rc/keymaps/Makefile 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/rc/keymaps/Makefile 2012-03-16 10:56:16.000000000 +0100
|
|
@@ -26,6 +26,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t
|
|
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 -uprN linux-3.2.10.orig/drivers/media/rc/keymaps/rc-dvbsky.c linux-3.2.10/drivers/media/rc/keymaps/rc-dvbsky.c
|
|
--- linux-3.2.10.orig/drivers/media/rc/keymaps/rc-dvbsky.c 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/rc/keymaps/rc-dvbsky.c 2012-03-16 11:57:45.000000000 +0100
|
|
@@ -0,0 +1,80 @@
|
|
+/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers
|
|
+ *
|
|
+ * keymap imported from ir-keymaps.c
|
|
+ *
|
|
+ *
|
|
+ * Copyright (c) 2010-2011 by Mauro Carvalho Chehab <mchehab@redhat.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <media/rc-map.h>
|
|
+
|
|
+/*
|
|
+ * 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)
|
|
+
|
|
+/* outcommented cause build error
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
|
|
+*/
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-cards.c linux-3.2.10/drivers/media/video/cx23885/cx23885-cards.c
|
|
--- linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-cards.c 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx23885/cx23885-cards.c 2012-03-16 10:55:17.000000000 +0100
|
|
@@ -437,7 +437,21 @@ struct cx23885_board cx23885_boards[] =
|
|
.amux = CX25840_AUDIO7,
|
|
.gpio0 = 0,
|
|
} },
|
|
+ },
|
|
+ [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,
|
|
+ },
|
|
+
|
|
};
|
|
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
|
|
|
|
@@ -637,6 +651,18 @@ struct cx23885_subid cx23885_subids[] =
|
|
.subvendor = 0x1b55,
|
|
.subdevice = 0xe2e4,
|
|
.card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF,
|
|
+ }, {
|
|
+ .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,
|
|
},
|
|
};
|
|
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
|
|
@@ -1147,9 +1173,57 @@ void cx23885_gpio_setup(struct cx23885_d
|
|
/* enable irq */
|
|
cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
|
|
break;
|
|
+ case CX23885_BOARD_DVBSKY_S950:
|
|
+ case CX23885_BOARD_BST_PS8512:
|
|
+ cx23885_gpio_enable(dev, GPIO_2, 1);
|
|
+ cx23885_gpio_clear(dev, GPIO_2);
|
|
+ msleep(100);
|
|
+ cx23885_gpio_set(dev, GPIO_2);
|
|
+ break;
|
|
+ case CX23885_BOARD_DVBSKY_S952:
|
|
+ cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */
|
|
+
|
|
+ cx23885_gpio_enable(dev, GPIO_2, 1);
|
|
+ cx23885_gpio_enable(dev, GPIO_11, 1);
|
|
+
|
|
+ cx23885_gpio_clear(dev, GPIO_2);
|
|
+ cx23885_gpio_clear(dev, GPIO_11);
|
|
+ msleep(100);
|
|
+ cx23885_gpio_set(dev, GPIO_2);
|
|
+ cx23885_gpio_set(dev, GPIO_11);
|
|
+
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
+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[] = {
|
|
@@ -1181,7 +1255,7 @@ int cx23885_ir_init(struct cx23885_dev *
|
|
const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg);
|
|
|
|
struct v4l2_subdev_ir_parameters params;
|
|
- int ret = 0;
|
|
+ int ret = 0;
|
|
switch (dev->board) {
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1500:
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
|
|
@@ -1232,6 +1306,20 @@ int cx23885_ir_init(struct cx23885_dev *
|
|
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:
|
|
+ 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;
|
|
@@ -1263,6 +1351,9 @@ void cx23885_ir_fini(struct cx23885_dev
|
|
break;
|
|
case CX23885_BOARD_TEVII_S470:
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
|
+ case CX23885_BOARD_BST_PS8512:
|
|
+ case CX23885_BOARD_DVBSKY_S950:
|
|
+ case CX23885_BOARD_DVBSKY_S952:
|
|
cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
|
|
/* sd_ir is a duplicate pointer to the AV Core, just clear it */
|
|
dev->sd_ir = NULL;
|
|
@@ -1306,6 +1397,9 @@ void cx23885_ir_pci_int_enable(struct cx
|
|
break;
|
|
case CX23885_BOARD_TEVII_S470:
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
|
+ case CX23885_BOARD_BST_PS8512:
|
|
+ case CX23885_BOARD_DVBSKY_S950:
|
|
+ case CX23885_BOARD_DVBSKY_S952:
|
|
if (dev->sd_ir)
|
|
cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
|
|
break;
|
|
@@ -1388,6 +1482,8 @@ void cx23885_card_setup(struct cx23885_d
|
|
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_TEVII_S470:
|
|
case CX23885_BOARD_DVBWORLD_2005:
|
|
ts1->gen_ctrl_val = 0x5; /* Parallel */
|
|
@@ -1417,6 +1513,14 @@ void cx23885_card_setup(struct cx23885_d
|
|
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
|
|
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
|
|
break;
|
|
+ case CX23885_BOARD_DVBSKY_S952:
|
|
+ ts1->gen_ctrl_val = 0x5; /* Parallel */
|
|
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
|
|
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
|
|
+ ts2->gen_ctrl_val = 0xe; /* Serial bus + punctured clock */
|
|
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
|
|
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
|
|
+ break;
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1500:
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
|
|
@@ -1468,6 +1572,9 @@ void cx23885_card_setup(struct cx23885_d
|
|
case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1500:
|
|
case CX23885_BOARD_MPX885:
|
|
+ case CX23885_BOARD_BST_PS8512:
|
|
+ case CX23885_BOARD_DVBSKY_S950:
|
|
+ case CX23885_BOARD_DVBSKY_S952:
|
|
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
|
|
&dev->i2c_bus[2].i2c_adap,
|
|
"cx25840", 0x88 >> 1, NULL);
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-dvb.c linux-3.2.10/drivers/media/video/cx23885/cx23885-dvb.c
|
|
--- linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-dvb.c 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx23885/cx23885-dvb.c 2012-03-16 10:55:17.000000000 +0100
|
|
@@ -51,6 +51,7 @@
|
|
#include "stv6110.h"
|
|
#include "lnbh24.h"
|
|
#include "cx24116.h"
|
|
+#include "m88ds3103.h"
|
|
#include "cimax2.h"
|
|
#include "lgs8gxx.h"
|
|
#include "netup-eeprom.h"
|
|
@@ -479,6 +480,30 @@ static struct xc5000_config mygica_x8506
|
|
.if_khz = 5380,
|
|
};
|
|
|
|
+/* bestunar single dvb-s2 */
|
|
+static struct m88ds3103_config bst_ds3103_config = {
|
|
+ .demod_address = 0x68,
|
|
+ .ci_mode = 0,
|
|
+ .pin_ctrl = 0x82,
|
|
+ .ts_mode = 0,
|
|
+ .set_voltage = bst_set_voltage,
|
|
+};
|
|
+/* DVBSKY dual dvb-s2 */
|
|
+static struct m88ds3103_config dvbsky_ds3103_config_pri = {
|
|
+ .demod_address = 0x68,
|
|
+ .ci_mode = 0,
|
|
+ .pin_ctrl = 0x82,
|
|
+ .ts_mode = 0,
|
|
+ .set_voltage = bst_set_voltage,
|
|
+};
|
|
+static struct m88ds3103_config dvbsky_ds3103_config_sec = {
|
|
+ .demod_address = 0x68,
|
|
+ .ci_mode = 0,
|
|
+ .pin_ctrl = 0x82,
|
|
+ .ts_mode = 1,
|
|
+ .set_voltage = dvbsky_set_voltage_sec,
|
|
+};
|
|
+
|
|
static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
|
|
struct dvb_frontend_parameters *param)
|
|
{
|
|
@@ -1123,6 +1148,32 @@ static int dvb_register(struct cx23885_t
|
|
goto frontend_detach;
|
|
}
|
|
break;
|
|
+ case CX23885_BOARD_BST_PS8512:
|
|
+ case CX23885_BOARD_DVBSKY_S950:
|
|
+ i2c_bus = &dev->i2c_bus[1];
|
|
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
|
|
+ &bst_ds3103_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ break;
|
|
+
|
|
+ case CX23885_BOARD_DVBSKY_S952:
|
|
+ switch (port->nr) {
|
|
+ /* port B */
|
|
+ case 1:
|
|
+ i2c_bus = &dev->i2c_bus[1];
|
|
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
|
|
+ &dvbsky_ds3103_config_pri,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ break;
|
|
+ /* port C */
|
|
+ case 2:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
|
|
+ &dvbsky_ds3103_config_sec,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
default:
|
|
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
|
|
" isn't supported yet\n",
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-dvb.c.orig linux-3.2.10/drivers/media/video/cx23885/cx23885-dvb.c.orig
|
|
--- linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-dvb.c.orig 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx23885/cx23885-dvb.c.orig 2012-03-16 10:14:15.000000000 +0100
|
|
@@ -0,0 +1,1294 @@
|
|
+/*
|
|
+ * Driver for the Conexant CX23885 PCIe bridge
|
|
+ *
|
|
+ * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org>
|
|
+ *
|
|
+ * 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/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/kthread.h>
|
|
+#include <linux/file.h>
|
|
+#include <linux/suspend.h>
|
|
+
|
|
+#include "cx23885.h"
|
|
+#include <media/v4l2-common.h>
|
|
+
|
|
+#include "dvb_ca_en50221.h"
|
|
+#include "s5h1409.h"
|
|
+#include "s5h1411.h"
|
|
+#include "mt2131.h"
|
|
+#include "tda8290.h"
|
|
+#include "tda18271.h"
|
|
+#include "lgdt330x.h"
|
|
+#include "xc4000.h"
|
|
+#include "xc5000.h"
|
|
+#include "max2165.h"
|
|
+#include "tda10048.h"
|
|
+#include "tuner-xc2028.h"
|
|
+#include "tuner-simple.h"
|
|
+#include "dib7000p.h"
|
|
+#include "dibx000_common.h"
|
|
+#include "zl10353.h"
|
|
+#include "stv0900.h"
|
|
+#include "stv0900_reg.h"
|
|
+#include "stv6110.h"
|
|
+#include "lnbh24.h"
|
|
+#include "cx24116.h"
|
|
+#include "cimax2.h"
|
|
+#include "lgs8gxx.h"
|
|
+#include "netup-eeprom.h"
|
|
+#include "netup-init.h"
|
|
+#include "lgdt3305.h"
|
|
+#include "atbm8830.h"
|
|
+#include "ds3000.h"
|
|
+#include "cx23885-f300.h"
|
|
+#include "altera-ci.h"
|
|
+#include "stv0367.h"
|
|
+
|
|
+static unsigned int debug;
|
|
+
|
|
+#define dprintk(level, fmt, arg...)\
|
|
+ do { if (debug >= level)\
|
|
+ printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
|
|
+ } while (0)
|
|
+
|
|
+/* ------------------------------------------------------------------ */
|
|
+
|
|
+static unsigned int alt_tuner;
|
|
+module_param(alt_tuner, int, 0644);
|
|
+MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
|
|
+
|
|
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
|
+
|
|
+/* ------------------------------------------------------------------ */
|
|
+
|
|
+static int dvb_buf_setup(struct videobuf_queue *q,
|
|
+ unsigned int *count, unsigned int *size)
|
|
+{
|
|
+ struct cx23885_tsport *port = q->priv_data;
|
|
+
|
|
+ port->ts_packet_size = 188 * 4;
|
|
+ port->ts_packet_count = 32;
|
|
+
|
|
+ *size = port->ts_packet_size * port->ts_packet_count;
|
|
+ *count = 32;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int dvb_buf_prepare(struct videobuf_queue *q,
|
|
+ struct videobuf_buffer *vb, enum v4l2_field field)
|
|
+{
|
|
+ struct cx23885_tsport *port = q->priv_data;
|
|
+ return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
|
|
+}
|
|
+
|
|
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
|
+{
|
|
+ struct cx23885_tsport *port = q->priv_data;
|
|
+ cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
|
|
+}
|
|
+
|
|
+static void dvb_buf_release(struct videobuf_queue *q,
|
|
+ struct videobuf_buffer *vb)
|
|
+{
|
|
+ cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
|
|
+}
|
|
+
|
|
+static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open)
|
|
+{
|
|
+ struct videobuf_dvb_frontends *f;
|
|
+ struct videobuf_dvb_frontend *fe;
|
|
+
|
|
+ f = &port->frontends;
|
|
+
|
|
+ if (f->gate <= 1) /* undefined or fe0 */
|
|
+ fe = videobuf_dvb_get_frontend(f, 1);
|
|
+ else
|
|
+ fe = videobuf_dvb_get_frontend(f, f->gate);
|
|
+
|
|
+ if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
|
|
+ fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
|
|
+}
|
|
+
|
|
+static struct videobuf_queue_ops dvb_qops = {
|
|
+ .buf_setup = dvb_buf_setup,
|
|
+ .buf_prepare = dvb_buf_prepare,
|
|
+ .buf_queue = dvb_buf_queue,
|
|
+ .buf_release = dvb_buf_release,
|
|
+};
|
|
+
|
|
+static struct s5h1409_config hauppauge_generic_config = {
|
|
+ .demod_address = 0x32 >> 1,
|
|
+ .output_mode = S5H1409_SERIAL_OUTPUT,
|
|
+ .gpio = S5H1409_GPIO_ON,
|
|
+ .qam_if = 44000,
|
|
+ .inversion = S5H1409_INVERSION_OFF,
|
|
+ .status_mode = S5H1409_DEMODLOCKING,
|
|
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
|
|
+};
|
|
+
|
|
+static struct tda10048_config hauppauge_hvr1200_config = {
|
|
+ .demod_address = 0x10 >> 1,
|
|
+ .output_mode = TDA10048_SERIAL_OUTPUT,
|
|
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
|
|
+ .inversion = TDA10048_INVERSION_ON,
|
|
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
|
|
+ .dtv7_if_freq_khz = TDA10048_IF_3800,
|
|
+ .dtv8_if_freq_khz = TDA10048_IF_4300,
|
|
+ .clk_freq_khz = TDA10048_CLK_16000,
|
|
+};
|
|
+
|
|
+static struct tda10048_config hauppauge_hvr1210_config = {
|
|
+ .demod_address = 0x10 >> 1,
|
|
+ .output_mode = TDA10048_SERIAL_OUTPUT,
|
|
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
|
|
+ .inversion = TDA10048_INVERSION_ON,
|
|
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
|
|
+ .dtv7_if_freq_khz = TDA10048_IF_3500,
|
|
+ .dtv8_if_freq_khz = TDA10048_IF_4000,
|
|
+ .clk_freq_khz = TDA10048_CLK_16000,
|
|
+};
|
|
+
|
|
+static struct s5h1409_config hauppauge_ezqam_config = {
|
|
+ .demod_address = 0x32 >> 1,
|
|
+ .output_mode = S5H1409_SERIAL_OUTPUT,
|
|
+ .gpio = S5H1409_GPIO_OFF,
|
|
+ .qam_if = 4000,
|
|
+ .inversion = S5H1409_INVERSION_ON,
|
|
+ .status_mode = S5H1409_DEMODLOCKING,
|
|
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
|
|
+};
|
|
+
|
|
+static struct s5h1409_config hauppauge_hvr1800lp_config = {
|
|
+ .demod_address = 0x32 >> 1,
|
|
+ .output_mode = S5H1409_SERIAL_OUTPUT,
|
|
+ .gpio = S5H1409_GPIO_OFF,
|
|
+ .qam_if = 44000,
|
|
+ .inversion = S5H1409_INVERSION_OFF,
|
|
+ .status_mode = S5H1409_DEMODLOCKING,
|
|
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
|
|
+};
|
|
+
|
|
+static struct s5h1409_config hauppauge_hvr1500_config = {
|
|
+ .demod_address = 0x32 >> 1,
|
|
+ .output_mode = S5H1409_SERIAL_OUTPUT,
|
|
+ .gpio = S5H1409_GPIO_OFF,
|
|
+ .inversion = S5H1409_INVERSION_OFF,
|
|
+ .status_mode = S5H1409_DEMODLOCKING,
|
|
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
|
|
+};
|
|
+
|
|
+static struct mt2131_config hauppauge_generic_tunerconfig = {
|
|
+ 0x61
|
|
+};
|
|
+
|
|
+static struct lgdt330x_config fusionhdtv_5_express = {
|
|
+ .demod_address = 0x0e,
|
|
+ .demod_chip = LGDT3303,
|
|
+ .serial_mpeg = 0x40,
|
|
+};
|
|
+
|
|
+static struct s5h1409_config hauppauge_hvr1500q_config = {
|
|
+ .demod_address = 0x32 >> 1,
|
|
+ .output_mode = S5H1409_SERIAL_OUTPUT,
|
|
+ .gpio = S5H1409_GPIO_ON,
|
|
+ .qam_if = 44000,
|
|
+ .inversion = S5H1409_INVERSION_OFF,
|
|
+ .status_mode = S5H1409_DEMODLOCKING,
|
|
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
|
|
+};
|
|
+
|
|
+static struct s5h1409_config dvico_s5h1409_config = {
|
|
+ .demod_address = 0x32 >> 1,
|
|
+ .output_mode = S5H1409_SERIAL_OUTPUT,
|
|
+ .gpio = S5H1409_GPIO_ON,
|
|
+ .qam_if = 44000,
|
|
+ .inversion = S5H1409_INVERSION_OFF,
|
|
+ .status_mode = S5H1409_DEMODLOCKING,
|
|
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
|
|
+};
|
|
+
|
|
+static struct s5h1411_config dvico_s5h1411_config = {
|
|
+ .output_mode = S5H1411_SERIAL_OUTPUT,
|
|
+ .gpio = S5H1411_GPIO_ON,
|
|
+ .qam_if = S5H1411_IF_44000,
|
|
+ .vsb_if = S5H1411_IF_44000,
|
|
+ .inversion = S5H1411_INVERSION_OFF,
|
|
+ .status_mode = S5H1411_DEMODLOCKING,
|
|
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
|
|
+};
|
|
+
|
|
+static struct s5h1411_config hcw_s5h1411_config = {
|
|
+ .output_mode = S5H1411_SERIAL_OUTPUT,
|
|
+ .gpio = S5H1411_GPIO_OFF,
|
|
+ .vsb_if = S5H1411_IF_44000,
|
|
+ .qam_if = S5H1411_IF_4000,
|
|
+ .inversion = S5H1411_INVERSION_ON,
|
|
+ .status_mode = S5H1411_DEMODLOCKING,
|
|
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
|
|
+};
|
|
+
|
|
+static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
|
|
+ .i2c_address = 0x61,
|
|
+ .if_khz = 5380,
|
|
+};
|
|
+
|
|
+static struct xc5000_config dvico_xc5000_tunerconfig = {
|
|
+ .i2c_address = 0x64,
|
|
+ .if_khz = 5380,
|
|
+};
|
|
+
|
|
+static struct tda829x_config tda829x_no_probe = {
|
|
+ .probe_tuner = TDA829X_DONT_PROBE,
|
|
+};
|
|
+
|
|
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
|
|
+ .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3,
|
|
+ .if_lvl = 6, .rfagc_top = 0x37 },
|
|
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0,
|
|
+ .if_lvl = 6, .rfagc_top = 0x37 },
|
|
+};
|
|
+
|
|
+static struct tda18271_std_map hauppauge_hvr1200_tda18271_std_map = {
|
|
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
|
|
+ .if_lvl = 1, .rfagc_top = 0x37, },
|
|
+ .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5,
|
|
+ .if_lvl = 1, .rfagc_top = 0x37, },
|
|
+ .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6,
|
|
+ .if_lvl = 1, .rfagc_top = 0x37, },
|
|
+};
|
|
+
|
|
+static struct tda18271_config hauppauge_tda18271_config = {
|
|
+ .std_map = &hauppauge_tda18271_std_map,
|
|
+ .gate = TDA18271_GATE_ANALOG,
|
|
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
|
|
+};
|
|
+
|
|
+static struct tda18271_config hauppauge_hvr1200_tuner_config = {
|
|
+ .std_map = &hauppauge_hvr1200_tda18271_std_map,
|
|
+ .gate = TDA18271_GATE_ANALOG,
|
|
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
|
|
+};
|
|
+
|
|
+static struct tda18271_config hauppauge_hvr1210_tuner_config = {
|
|
+ .gate = TDA18271_GATE_DIGITAL,
|
|
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
|
|
+};
|
|
+
|
|
+static struct tda18271_std_map hauppauge_hvr127x_std_map = {
|
|
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
|
|
+ .if_lvl = 1, .rfagc_top = 0x58 },
|
|
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
|
|
+ .if_lvl = 1, .rfagc_top = 0x58 },
|
|
+};
|
|
+
|
|
+static struct tda18271_config hauppauge_hvr127x_config = {
|
|
+ .std_map = &hauppauge_hvr127x_std_map,
|
|
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
|
|
+};
|
|
+
|
|
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
|
|
+ .i2c_addr = 0x0e,
|
|
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
|
|
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
|
|
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
|
|
+ .deny_i2c_rptr = 1,
|
|
+ .spectral_inversion = 1,
|
|
+ .qam_if_khz = 4000,
|
|
+ .vsb_if_khz = 3250,
|
|
+};
|
|
+
|
|
+static struct dibx000_agc_config xc3028_agc_config = {
|
|
+ BAND_VHF | BAND_UHF, /* band_caps */
|
|
+
|
|
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
|
|
+ * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
|
|
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0,
|
|
+ * P_agc_nb_est=2, P_agc_write=0
|
|
+ */
|
|
+ (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
|
|
+ (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
|
|
+
|
|
+ 712, /* inv_gain */
|
|
+ 21, /* time_stabiliz */
|
|
+
|
|
+ 0, /* alpha_level */
|
|
+ 118, /* thlock */
|
|
+
|
|
+ 0, /* wbd_inv */
|
|
+ 2867, /* wbd_ref */
|
|
+ 0, /* wbd_sel */
|
|
+ 2, /* wbd_alpha */
|
|
+
|
|
+ 0, /* agc1_max */
|
|
+ 0, /* agc1_min */
|
|
+ 39718, /* agc2_max */
|
|
+ 9930, /* agc2_min */
|
|
+ 0, /* agc1_pt1 */
|
|
+ 0, /* agc1_pt2 */
|
|
+ 0, /* agc1_pt3 */
|
|
+ 0, /* agc1_slope1 */
|
|
+ 0, /* agc1_slope2 */
|
|
+ 0, /* agc2_pt1 */
|
|
+ 128, /* agc2_pt2 */
|
|
+ 29, /* agc2_slope1 */
|
|
+ 29, /* agc2_slope2 */
|
|
+
|
|
+ 17, /* alpha_mant */
|
|
+ 27, /* alpha_exp */
|
|
+ 23, /* beta_mant */
|
|
+ 51, /* beta_exp */
|
|
+
|
|
+ 1, /* perform_agc_softsplit */
|
|
+};
|
|
+
|
|
+/* PLL Configuration for COFDM BW_MHz = 8.000000
|
|
+ * With external clock = 30.000000 */
|
|
+static struct dibx000_bandwidth_config xc3028_bw_config = {
|
|
+ 60000, /* internal */
|
|
+ 30000, /* sampling */
|
|
+ 1, /* pll_cfg: prediv */
|
|
+ 8, /* pll_cfg: ratio */
|
|
+ 3, /* pll_cfg: range */
|
|
+ 1, /* pll_cfg: reset */
|
|
+ 0, /* pll_cfg: bypass */
|
|
+ 0, /* misc: refdiv */
|
|
+ 0, /* misc: bypclk_div */
|
|
+ 1, /* misc: IO_CLK_en_core */
|
|
+ 1, /* misc: ADClkSrc */
|
|
+ 0, /* misc: modulo */
|
|
+ (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
|
|
+ (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
|
|
+ 20452225, /* timf */
|
|
+ 30000000 /* xtal_hz */
|
|
+};
|
|
+
|
|
+static struct dib7000p_config hauppauge_hvr1400_dib7000_config = {
|
|
+ .output_mpeg2_in_188_bytes = 1,
|
|
+ .hostbus_diversity = 1,
|
|
+ .tuner_is_baseband = 0,
|
|
+ .update_lna = NULL,
|
|
+
|
|
+ .agc_config_count = 1,
|
|
+ .agc = &xc3028_agc_config,
|
|
+ .bw = &xc3028_bw_config,
|
|
+
|
|
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
|
|
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
|
|
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
|
|
+
|
|
+ .pwm_freq_div = 0,
|
|
+ .agc_control = NULL,
|
|
+ .spur_protect = 0,
|
|
+
|
|
+ .output_mode = OUTMODE_MPEG2_SERIAL,
|
|
+};
|
|
+
|
|
+static struct zl10353_config dvico_fusionhdtv_xc3028 = {
|
|
+ .demod_address = 0x0f,
|
|
+ .if2 = 45600,
|
|
+ .no_tuner = 1,
|
|
+ .disable_i2c_gate_ctrl = 1,
|
|
+};
|
|
+
|
|
+static struct stv0900_reg stv0900_ts_regs[] = {
|
|
+ { R0900_TSGENERAL, 0x00 },
|
|
+ { R0900_P1_TSSPEED, 0x40 },
|
|
+ { R0900_P2_TSSPEED, 0x40 },
|
|
+ { R0900_P1_TSCFGM, 0xc0 },
|
|
+ { R0900_P2_TSCFGM, 0xc0 },
|
|
+ { R0900_P1_TSCFGH, 0xe0 },
|
|
+ { R0900_P2_TSCFGH, 0xe0 },
|
|
+ { R0900_P1_TSCFGL, 0x20 },
|
|
+ { R0900_P2_TSCFGL, 0x20 },
|
|
+ { 0xffff, 0xff }, /* terminate */
|
|
+};
|
|
+
|
|
+static struct stv0900_config netup_stv0900_config = {
|
|
+ .demod_address = 0x68,
|
|
+ .demod_mode = 1, /* dual */
|
|
+ .xtal = 8000000,
|
|
+ .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
|
|
+ .diseqc_mode = 2,/* 2/3 PWM */
|
|
+ .ts_config_regs = stv0900_ts_regs,
|
|
+ .tun1_maddress = 0,/* 0x60 */
|
|
+ .tun2_maddress = 3,/* 0x63 */
|
|
+ .tun1_adc = 1,/* 1 Vpp */
|
|
+ .tun2_adc = 1,/* 1 Vpp */
|
|
+};
|
|
+
|
|
+static struct stv6110_config netup_stv6110_tunerconfig_a = {
|
|
+ .i2c_address = 0x60,
|
|
+ .mclk = 16000000,
|
|
+ .clk_div = 1,
|
|
+ .gain = 8, /* +16 dB - maximum gain */
|
|
+};
|
|
+
|
|
+static struct stv6110_config netup_stv6110_tunerconfig_b = {
|
|
+ .i2c_address = 0x63,
|
|
+ .mclk = 16000000,
|
|
+ .clk_div = 1,
|
|
+ .gain = 8, /* +16 dB - maximum gain */
|
|
+};
|
|
+
|
|
+static struct cx24116_config tbs_cx24116_config = {
|
|
+ .demod_address = 0x55,
|
|
+};
|
|
+
|
|
+static struct ds3000_config tevii_ds3000_config = {
|
|
+ .demod_address = 0x68,
|
|
+};
|
|
+
|
|
+static struct cx24116_config dvbworld_cx24116_config = {
|
|
+ .demod_address = 0x05,
|
|
+};
|
|
+
|
|
+static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = {
|
|
+ .prod = LGS8GXX_PROD_LGS8GL5,
|
|
+ .demod_address = 0x19,
|
|
+ .serial_ts = 0,
|
|
+ .ts_clk_pol = 1,
|
|
+ .ts_clk_gated = 1,
|
|
+ .if_clk_freq = 30400, /* 30.4 MHz */
|
|
+ .if_freq = 5380, /* 5.38 MHz */
|
|
+ .if_neg_center = 1,
|
|
+ .ext_adc = 0,
|
|
+ .adc_signed = 0,
|
|
+ .if_neg_edge = 0,
|
|
+};
|
|
+
|
|
+static struct xc5000_config mygica_x8506_xc5000_config = {
|
|
+ .i2c_address = 0x61,
|
|
+ .if_khz = 5380,
|
|
+};
|
|
+
|
|
+static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
|
|
+ struct dvb_frontend_parameters *param)
|
|
+{
|
|
+ struct cx23885_tsport *port = fe->dvb->priv;
|
|
+ struct cx23885_dev *dev = port->dev;
|
|
+
|
|
+ switch (dev->board) {
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1275:
|
|
+ switch (param->u.vsb.modulation) {
|
|
+ case VSB_8:
|
|
+ cx23885_gpio_clear(dev, GPIO_5);
|
|
+ break;
|
|
+ case QAM_64:
|
|
+ case QAM_256:
|
|
+ default:
|
|
+ cx23885_gpio_set(dev, GPIO_5);
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_MYGICA_X8506:
|
|
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
|
|
+ /* Select Digital TV */
|
|
+ cx23885_gpio_set(dev, GPIO_0);
|
|
+ break;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe,
|
|
+ unsigned int cmd, void *parg,
|
|
+ unsigned int stage)
|
|
+{
|
|
+ int err = 0;
|
|
+
|
|
+ switch (stage) {
|
|
+ case DVB_FE_IOCTL_PRE:
|
|
+
|
|
+ switch (cmd) {
|
|
+ case FE_SET_FRONTEND:
|
|
+ err = cx23885_dvb_set_frontend(fe,
|
|
+ (struct dvb_frontend_parameters *) parg);
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DVB_FE_IOCTL_POST:
|
|
+ /* no post-ioctl handling required */
|
|
+ break;
|
|
+ }
|
|
+ return err;
|
|
+};
|
|
+
|
|
+
|
|
+static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
|
|
+ .prod = LGS8GXX_PROD_LGS8G75,
|
|
+ .demod_address = 0x19,
|
|
+ .serial_ts = 0,
|
|
+ .ts_clk_pol = 1,
|
|
+ .ts_clk_gated = 1,
|
|
+ .if_clk_freq = 30400, /* 30.4 MHz */
|
|
+ .if_freq = 6500, /* 6.50 MHz */
|
|
+ .if_neg_center = 1,
|
|
+ .ext_adc = 0,
|
|
+ .adc_signed = 1,
|
|
+ .adc_vpp = 2, /* 1.6 Vpp */
|
|
+ .if_neg_edge = 1,
|
|
+};
|
|
+
|
|
+static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
|
|
+ .i2c_address = 0x61,
|
|
+ .if_khz = 6500,
|
|
+};
|
|
+
|
|
+static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = {
|
|
+ .prod = ATBM8830_PROD_8830,
|
|
+ .demod_address = 0x44,
|
|
+ .serial_ts = 0,
|
|
+ .ts_sampling_edge = 1,
|
|
+ .ts_clk_gated = 0,
|
|
+ .osc_clk_freq = 30400, /* in kHz */
|
|
+ .if_freq = 0, /* zero IF */
|
|
+ .zif_swap_iq = 1,
|
|
+ .agc_min = 0x2E,
|
|
+ .agc_max = 0xFF,
|
|
+ .agc_hold_loop = 0,
|
|
+};
|
|
+
|
|
+static struct max2165_config mygic_x8558pro_max2165_cfg1 = {
|
|
+ .i2c_address = 0x60,
|
|
+ .osc_clk = 20
|
|
+};
|
|
+
|
|
+static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = {
|
|
+ .prod = ATBM8830_PROD_8830,
|
|
+ .demod_address = 0x44,
|
|
+ .serial_ts = 1,
|
|
+ .ts_sampling_edge = 1,
|
|
+ .ts_clk_gated = 0,
|
|
+ .osc_clk_freq = 30400, /* in kHz */
|
|
+ .if_freq = 0, /* zero IF */
|
|
+ .zif_swap_iq = 1,
|
|
+ .agc_min = 0x2E,
|
|
+ .agc_max = 0xFF,
|
|
+ .agc_hold_loop = 0,
|
|
+};
|
|
+
|
|
+static struct max2165_config mygic_x8558pro_max2165_cfg2 = {
|
|
+ .i2c_address = 0x60,
|
|
+ .osc_clk = 20
|
|
+};
|
|
+static struct stv0367_config netup_stv0367_config[] = {
|
|
+ {
|
|
+ .demod_address = 0x1c,
|
|
+ .xtal = 27000000,
|
|
+ .if_khz = 4500,
|
|
+ .if_iq_mode = 0,
|
|
+ .ts_mode = 1,
|
|
+ .clk_pol = 0,
|
|
+ }, {
|
|
+ .demod_address = 0x1d,
|
|
+ .xtal = 27000000,
|
|
+ .if_khz = 4500,
|
|
+ .if_iq_mode = 0,
|
|
+ .ts_mode = 1,
|
|
+ .clk_pol = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct xc5000_config netup_xc5000_config[] = {
|
|
+ {
|
|
+ .i2c_address = 0x61,
|
|
+ .if_khz = 4500,
|
|
+ }, {
|
|
+ .i2c_address = 0x64,
|
|
+ .if_khz = 4500,
|
|
+ },
|
|
+};
|
|
+
|
|
+int netup_altera_fpga_rw(void *device, int flag, int data, int read)
|
|
+{
|
|
+ struct cx23885_dev *dev = (struct cx23885_dev *)device;
|
|
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
|
|
+ uint32_t mem = 0;
|
|
+
|
|
+ mem = cx_read(MC417_RWD);
|
|
+ if (read)
|
|
+ cx_set(MC417_OEN, ALT_DATA);
|
|
+ else {
|
|
+ cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */
|
|
+ mem &= ~ALT_DATA;
|
|
+ mem |= (data & ALT_DATA);
|
|
+ }
|
|
+
|
|
+ if (flag)
|
|
+ mem |= ALT_AD_RG;
|
|
+ else
|
|
+ mem &= ~ALT_AD_RG;
|
|
+
|
|
+ mem &= ~ALT_CS;
|
|
+ if (read)
|
|
+ mem = (mem & ~ALT_RD) | ALT_WR;
|
|
+ else
|
|
+ mem = (mem & ~ALT_WR) | ALT_RD;
|
|
+
|
|
+ cx_write(MC417_RWD, mem); /* start RW cycle */
|
|
+
|
|
+ for (;;) {
|
|
+ mem = cx_read(MC417_RWD);
|
|
+ if ((mem & ALT_RDY) == 0)
|
|
+ break;
|
|
+ if (time_after(jiffies, timeout))
|
|
+ break;
|
|
+ udelay(1);
|
|
+ }
|
|
+
|
|
+ cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS);
|
|
+ if (read)
|
|
+ return mem & ALT_DATA;
|
|
+
|
|
+ return 0;
|
|
+};
|
|
+
|
|
+static int dvb_register(struct cx23885_tsport *port)
|
|
+{
|
|
+ struct cx23885_dev *dev = port->dev;
|
|
+ struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
|
|
+ struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
|
|
+ int mfe_shared = 0; /* bus not shared by default */
|
|
+ int ret;
|
|
+
|
|
+ /* Get the first frontend */
|
|
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
|
|
+ if (!fe0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* init struct videobuf_dvb */
|
|
+ fe0->dvb.name = dev->name;
|
|
+
|
|
+ /* multi-frontend gate control is undefined or defaults to fe0 */
|
|
+ port->frontends.gate = 0;
|
|
+
|
|
+ /* Sets the gate control callback to be used by i2c command calls */
|
|
+ port->gate_ctrl = cx23885_dvb_gate_ctrl;
|
|
+
|
|
+ /* init frontend */
|
|
+ switch (dev->board) {
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
|
+ &hauppauge_generic_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &hauppauge_generic_tunerconfig, 0);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1275:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
|
|
+ &hauppauge_lgdt3305_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
|
|
+ 0x60, &dev->i2c_bus[1].i2c_adap,
|
|
+ &hauppauge_hvr127x_config);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
|
|
+ &hcw_s5h1411_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
|
|
+ 0x60, &dev->i2c_bus[1].i2c_adap,
|
|
+ &hauppauge_tda18271_config);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ switch (alt_tuner) {
|
|
+ case 1:
|
|
+ fe0->dvb.frontend =
|
|
+ dvb_attach(s5h1409_attach,
|
|
+ &hauppauge_ezqam_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
|
|
+ &dev->i2c_bus[1].i2c_adap, 0x42,
|
|
+ &tda829x_no_probe);
|
|
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
|
|
+ 0x60, &dev->i2c_bus[1].i2c_adap,
|
|
+ &hauppauge_tda18271_config);
|
|
+ }
|
|
+ break;
|
|
+ case 0:
|
|
+ default:
|
|
+ fe0->dvb.frontend =
|
|
+ dvb_attach(s5h1409_attach,
|
|
+ &hauppauge_generic_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL)
|
|
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &hauppauge_generic_tunerconfig, 0);
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
|
+ &hauppauge_hvr1800lp_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &hauppauge_generic_tunerconfig, 0);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
|
|
+ &fusionhdtv_5_express,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap, 0x61,
|
|
+ TUNER_LG_TDVS_H06XF);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
|
|
+ i2c_bus = &dev->i2c_bus[1];
|
|
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
|
+ &hauppauge_hvr1500q_config,
|
|
+ &dev->i2c_bus[0].i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL)
|
|
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &hauppauge_hvr1500q_tunerconfig);
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
|
|
+ i2c_bus = &dev->i2c_bus[1];
|
|
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
|
+ &hauppauge_hvr1500_config,
|
|
+ &dev->i2c_bus[0].i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ struct dvb_frontend *fe;
|
|
+ struct xc2028_config cfg = {
|
|
+ .i2c_adap = &i2c_bus->i2c_adap,
|
|
+ .i2c_addr = 0x61,
|
|
+ };
|
|
+ static struct xc2028_ctrl ctl = {
|
|
+ .fname = XC2028_DEFAULT_FIRMWARE,
|
|
+ .max_len = 64,
|
|
+ .demod = XC3028_FE_OREN538,
|
|
+ };
|
|
+
|
|
+ fe = dvb_attach(xc2028_attach,
|
|
+ fe0->dvb.frontend, &cfg);
|
|
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
|
+ fe->ops.tuner_ops.set_config(fe, &ctl);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
|
|
+ &hauppauge_hvr1200_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
|
|
+ &dev->i2c_bus[1].i2c_adap, 0x42,
|
|
+ &tda829x_no_probe);
|
|
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
|
|
+ 0x60, &dev->i2c_bus[1].i2c_adap,
|
|
+ &hauppauge_hvr1200_tuner_config);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1210:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
|
|
+ &hauppauge_hvr1210_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
|
|
+ 0x60, &dev->i2c_bus[1].i2c_adap,
|
|
+ &hauppauge_hvr1210_tuner_config);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(dib7000p_attach,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ 0x12, &hauppauge_hvr1400_dib7000_config);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ struct dvb_frontend *fe;
|
|
+ struct xc2028_config cfg = {
|
|
+ .i2c_adap = &dev->i2c_bus[1].i2c_adap,
|
|
+ .i2c_addr = 0x64,
|
|
+ };
|
|
+ static struct xc2028_ctrl ctl = {
|
|
+ .fname = XC3028L_DEFAULT_FIRMWARE,
|
|
+ .max_len = 64,
|
|
+ .demod = XC3028_FE_DIBCOM52,
|
|
+ /* This is true for all demods with
|
|
+ v36 firmware? */
|
|
+ .type = XC2028_D2633,
|
|
+ };
|
|
+
|
|
+ fe = dvb_attach(xc2028_attach,
|
|
+ fe0->dvb.frontend, &cfg);
|
|
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
|
+ fe->ops.tuner_ops.set_config(fe, &ctl);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
|
|
+ i2c_bus = &dev->i2c_bus[port->nr - 1];
|
|
+
|
|
+ fe0->dvb.frontend = dvb_attach(s5h1409_attach,
|
|
+ &dvico_s5h1409_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend == NULL)
|
|
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
|
|
+ &dvico_s5h1411_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL)
|
|
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &dvico_xc5000_tunerconfig);
|
|
+ break;
|
|
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: {
|
|
+ i2c_bus = &dev->i2c_bus[port->nr - 1];
|
|
+
|
|
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
|
+ &dvico_fusionhdtv_xc3028,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ struct dvb_frontend *fe;
|
|
+ struct xc2028_config cfg = {
|
|
+ .i2c_adap = &i2c_bus->i2c_adap,
|
|
+ .i2c_addr = 0x61,
|
|
+ };
|
|
+ static struct xc2028_ctrl ctl = {
|
|
+ .fname = XC2028_DEFAULT_FIRMWARE,
|
|
+ .max_len = 64,
|
|
+ .demod = XC3028_FE_ZARLINK456,
|
|
+ };
|
|
+
|
|
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
|
|
+ &cfg);
|
|
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
|
+ fe->ops.tuner_ops.set_config(fe, &ctl);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
|
|
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
|
|
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+
|
|
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
|
+ &dvico_fusionhdtv_xc3028,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ struct dvb_frontend *fe;
|
|
+ struct xc2028_config cfg = {
|
|
+ .i2c_adap = &dev->i2c_bus[1].i2c_adap,
|
|
+ .i2c_addr = 0x61,
|
|
+ };
|
|
+ static struct xc2028_ctrl ctl = {
|
|
+ .fname = XC2028_DEFAULT_FIRMWARE,
|
|
+ .max_len = 64,
|
|
+ .demod = XC3028_FE_ZARLINK456,
|
|
+ };
|
|
+
|
|
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend,
|
|
+ &cfg);
|
|
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
|
|
+ fe->ops.tuner_ops.set_config(fe, &ctl);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+
|
|
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
|
|
+ &dvico_fusionhdtv_xc3028,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ struct dvb_frontend *fe;
|
|
+ struct xc4000_config cfg = {
|
|
+ .i2c_address = 0x61,
|
|
+ .default_pm = 0,
|
|
+ .dvb_amplitude = 134,
|
|
+ .set_smoothedcvbs = 1,
|
|
+ .if_khz = 4560
|
|
+ };
|
|
+
|
|
+ fe = dvb_attach(xc4000_attach, fe0->dvb.frontend,
|
|
+ &dev->i2c_bus[1].i2c_adap, &cfg);
|
|
+ if (!fe) {
|
|
+ printk(KERN_ERR "%s/2: xc4000 attach failed\n",
|
|
+ dev->name);
|
|
+ goto frontend_detach;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_TBS_6920:
|
|
+ i2c_bus = &dev->i2c_bus[1];
|
|
+
|
|
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
|
|
+ &tbs_cx24116_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL)
|
|
+ fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
|
|
+
|
|
+ break;
|
|
+ case CX23885_BOARD_TEVII_S470:
|
|
+ i2c_bus = &dev->i2c_bus[1];
|
|
+
|
|
+ fe0->dvb.frontend = dvb_attach(ds3000_attach,
|
|
+ &tevii_ds3000_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL)
|
|
+ fe0->dvb.frontend->ops.set_voltage = f300_set_voltage;
|
|
+
|
|
+ break;
|
|
+ case CX23885_BOARD_DVBWORLD_2005:
|
|
+ i2c_bus = &dev->i2c_bus[1];
|
|
+
|
|
+ fe0->dvb.frontend = dvb_attach(cx24116_attach,
|
|
+ &dvbworld_cx24116_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ break;
|
|
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ switch (port->nr) {
|
|
+ /* port B */
|
|
+ case 1:
|
|
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
|
|
+ &netup_stv0900_config,
|
|
+ &i2c_bus->i2c_adap, 0);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ if (dvb_attach(stv6110_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &netup_stv6110_tunerconfig_a,
|
|
+ &i2c_bus->i2c_adap)) {
|
|
+ if (!dvb_attach(lnbh24_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ LNBH24_PCL | LNBH24_TTX,
|
|
+ LNBH24_TEN, 0x09))
|
|
+ printk(KERN_ERR
|
|
+ "No LNBH24 found!\n");
|
|
+
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ /* port C */
|
|
+ case 2:
|
|
+ fe0->dvb.frontend = dvb_attach(stv0900_attach,
|
|
+ &netup_stv0900_config,
|
|
+ &i2c_bus->i2c_adap, 1);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ if (dvb_attach(stv6110_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &netup_stv6110_tunerconfig_b,
|
|
+ &i2c_bus->i2c_adap)) {
|
|
+ if (!dvb_attach(lnbh24_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ LNBH24_PCL | LNBH24_TTX,
|
|
+ LNBH24_TEN, 0x0a))
|
|
+ printk(KERN_ERR
|
|
+ "No LNBH24 found!\n");
|
|
+
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_MYGICA_X8506:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ i2c_bus2 = &dev->i2c_bus[1];
|
|
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
|
|
+ &mygica_x8506_lgs8gl5_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(xc5000_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &i2c_bus2->i2c_adap,
|
|
+ &mygica_x8506_xc5000_config);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_MAGICPRO_PROHDTVE2:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ i2c_bus2 = &dev->i2c_bus[1];
|
|
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
|
|
+ &magicpro_prohdtve2_lgs8g75_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(xc5000_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &i2c_bus2->i2c_adap,
|
|
+ &magicpro_prohdtve2_xc5000_config);
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
|
|
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
|
|
+ &hcw_s5h1411_config,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL)
|
|
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
|
|
+ 0x60, &dev->i2c_bus[0].i2c_adap,
|
|
+ &hauppauge_tda18271_config);
|
|
+ break;
|
|
+ case CX23885_BOARD_MYGICA_X8558PRO:
|
|
+ switch (port->nr) {
|
|
+ /* port B */
|
|
+ case 1:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ fe0->dvb.frontend = dvb_attach(atbm8830_attach,
|
|
+ &mygica_x8558pro_atbm8830_cfg1,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(max2165_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &mygic_x8558pro_max2165_cfg1);
|
|
+ }
|
|
+ break;
|
|
+ /* port C */
|
|
+ case 2:
|
|
+ i2c_bus = &dev->i2c_bus[1];
|
|
+ fe0->dvb.frontend = dvb_attach(atbm8830_attach,
|
|
+ &mygica_x8558pro_atbm8830_cfg2,
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ dvb_attach(max2165_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &mygic_x8558pro_max2165_cfg2);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
|
|
+ i2c_bus = &dev->i2c_bus[0];
|
|
+ mfe_shared = 1;/* MFE */
|
|
+ port->frontends.gate = 0;/* not clear for me yet */
|
|
+ /* ports B, C */
|
|
+ /* MFE frontend 1 DVB-T */
|
|
+ fe0->dvb.frontend = dvb_attach(stv0367ter_attach,
|
|
+ &netup_stv0367_config[port->nr - 1],
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL) {
|
|
+ if (NULL == dvb_attach(xc5000_attach,
|
|
+ fe0->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &netup_xc5000_config[port->nr - 1]))
|
|
+ goto frontend_detach;
|
|
+ /* load xc5000 firmware */
|
|
+ fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
|
|
+ }
|
|
+ /* MFE frontend 2 */
|
|
+ fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
|
|
+ if (fe1 == NULL)
|
|
+ goto frontend_detach;
|
|
+ /* DVB-C init */
|
|
+ fe1->dvb.frontend = dvb_attach(stv0367cab_attach,
|
|
+ &netup_stv0367_config[port->nr - 1],
|
|
+ &i2c_bus->i2c_adap);
|
|
+ if (fe1->dvb.frontend != NULL) {
|
|
+ fe1->dvb.frontend->id = 1;
|
|
+ if (NULL == dvb_attach(xc5000_attach,
|
|
+ fe1->dvb.frontend,
|
|
+ &i2c_bus->i2c_adap,
|
|
+ &netup_xc5000_config[port->nr - 1]))
|
|
+ goto frontend_detach;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
|
|
+ " isn't supported yet\n",
|
|
+ dev->name);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) {
|
|
+ printk(KERN_ERR "%s: frontend initialization failed\n",
|
|
+ dev->name);
|
|
+ goto frontend_detach;
|
|
+ }
|
|
+
|
|
+ /* define general-purpose callback pointer */
|
|
+ fe0->dvb.frontend->callback = cx23885_tuner_callback;
|
|
+ if (fe1)
|
|
+ fe1->dvb.frontend->callback = cx23885_tuner_callback;
|
|
+#if 0
|
|
+ /* Ensure all frontends negotiate bus access */
|
|
+ fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
|
|
+ if (fe1)
|
|
+ fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
|
|
+#endif
|
|
+
|
|
+ /* Put the analog decoder in standby to keep it quiet */
|
|
+ call_all(dev, core, s_power, 0);
|
|
+
|
|
+ if (fe0->dvb.frontend->ops.analog_ops.standby)
|
|
+ fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
|
|
+
|
|
+ /* register everything */
|
|
+ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
|
|
+ &dev->pci->dev, adapter_nr, mfe_shared,
|
|
+ cx23885_dvb_fe_ioctl_override);
|
|
+ if (ret)
|
|
+ goto frontend_detach;
|
|
+
|
|
+ /* init CI & MAC */
|
|
+ switch (dev->board) {
|
|
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
|
|
+ static struct netup_card_info cinfo;
|
|
+
|
|
+ netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
|
|
+ memcpy(port->frontends.adapter.proposed_mac,
|
|
+ cinfo.port[port->nr - 1].mac, 6);
|
|
+ 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);
|
|
+ break;
|
|
+ }
|
|
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
|
|
+ struct altera_ci_config netup_ci_cfg = {
|
|
+ .dev = dev,/* magic number to identify*/
|
|
+ .adapter = &port->frontends.adapter,/* for CI */
|
|
+ .demux = &fe0->dvb.demux,/* for hw pid filter */
|
|
+ .fpga_rw = netup_altera_fpga_rw,
|
|
+ };
|
|
+
|
|
+ altera_ci_init(&netup_ci_cfg, port->nr);
|
|
+ break;
|
|
+ }
|
|
+ case CX23885_BOARD_TEVII_S470: {
|
|
+ u8 eeprom[256]; /* 24C02 i2c eeprom */
|
|
+
|
|
+ if (port->nr != 1)
|
|
+ break;
|
|
+
|
|
+ /* Read entire EEPROM */
|
|
+ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
|
|
+ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
|
|
+ printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
|
|
+ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+
|
|
+frontend_detach:
|
|
+ port->gate_ctrl = NULL;
|
|
+ videobuf_dvb_dealloc_frontends(&port->frontends);
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+int cx23885_dvb_register(struct cx23885_tsport *port)
|
|
+{
|
|
+
|
|
+ struct videobuf_dvb_frontend *fe0;
|
|
+ struct cx23885_dev *dev = port->dev;
|
|
+ int err, i;
|
|
+
|
|
+ /* Here we need to allocate the correct number of frontends,
|
|
+ * as reflected in the cards struct. The reality is that currently
|
|
+ * no cx23885 boards support this - yet. But, if we don't modify this
|
|
+ * code then the second frontend would never be allocated (later)
|
|
+ * and fail with error before the attach in dvb_register().
|
|
+ * Without these changes we risk an OOPS later. The changes here
|
|
+ * are for safety, and should provide a good foundation for the
|
|
+ * future addition of any multi-frontend cx23885 based boards.
|
|
+ */
|
|
+ printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
|
|
+ port->num_frontends);
|
|
+
|
|
+ for (i = 1; i <= port->num_frontends; i++) {
|
|
+ if (videobuf_dvb_alloc_frontend(
|
|
+ &port->frontends, i) == NULL) {
|
|
+ printk(KERN_ERR "%s() failed to alloc\n", __func__);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
|
|
+ if (!fe0)
|
|
+ err = -EINVAL;
|
|
+
|
|
+ dprintk(1, "%s\n", __func__);
|
|
+ dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n",
|
|
+ dev->board,
|
|
+ dev->name,
|
|
+ dev->pci_bus,
|
|
+ dev->pci_slot);
|
|
+
|
|
+ err = -ENODEV;
|
|
+
|
|
+ /* dvb stuff */
|
|
+ /* We have to init the queue for each frontend on a port. */
|
|
+ printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
|
|
+ videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
|
|
+ &dev->pci->dev, &port->slock,
|
|
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
|
|
+ sizeof(struct cx23885_buffer), port, NULL);
|
|
+ }
|
|
+ err = dvb_register(port);
|
|
+ if (err != 0)
|
|
+ printk(KERN_ERR "%s() dvb_register failed err = %d\n",
|
|
+ __func__, err);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+int cx23885_dvb_unregister(struct cx23885_tsport *port)
|
|
+{
|
|
+ struct videobuf_dvb_frontend *fe0;
|
|
+
|
|
+ /* FIXME: in an error condition where the we have
|
|
+ * an expected number of frontends (attach problem)
|
|
+ * then this might not clean up correctly, if 1
|
|
+ * is invalid.
|
|
+ * This comment only applies to future boards IF they
|
|
+ * implement MFE support.
|
|
+ */
|
|
+ fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
|
|
+ if (fe0 && fe0->dvb.frontend)
|
|
+ videobuf_dvb_unregister_bus(&port->frontends);
|
|
+
|
|
+ switch (port->dev->board) {
|
|
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
|
|
+ netup_ci_exit(port);
|
|
+ break;
|
|
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
|
|
+ altera_ci_release(port->dev, port->nr);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ port->gate_ctrl = NULL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-f300.c linux-3.2.10/drivers/media/video/cx23885/cx23885-f300.c
|
|
--- linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-f300.c 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx23885/cx23885-f300.c 2012-03-16 10:55:17.000000000 +0100
|
|
@@ -175,3 +175,59 @@ int f300_set_voltage(struct dvb_frontend
|
|
|
|
return f300_xfer(fe, buf);
|
|
}
|
|
+
|
|
+/* bst control */
|
|
+int bst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
|
+{
|
|
+ struct cx23885_tsport *port = fe->dvb->priv;
|
|
+ struct cx23885_dev *dev = port->dev;
|
|
+
|
|
+ cx23885_gpio_enable(dev, GPIO_1, 1);
|
|
+ cx23885_gpio_enable(dev, GPIO_0, 1);
|
|
+
|
|
+ switch (voltage) {
|
|
+ case SEC_VOLTAGE_13:
|
|
+ cx23885_gpio_set(dev, GPIO_1);
|
|
+ cx23885_gpio_clear(dev, GPIO_0);
|
|
+ break;
|
|
+ case SEC_VOLTAGE_18:
|
|
+ cx23885_gpio_set(dev, GPIO_1);
|
|
+ cx23885_gpio_set(dev, GPIO_0);
|
|
+ break;
|
|
+ case SEC_VOLTAGE_OFF:
|
|
+ cx23885_gpio_clear(dev, GPIO_1);
|
|
+ cx23885_gpio_clear(dev, GPIO_0);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int dvbsky_set_voltage_sec(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
|
+{
|
|
+ struct cx23885_tsport *port = fe->dvb->priv;
|
|
+ struct cx23885_dev *dev = port->dev;
|
|
+
|
|
+ cx23885_gpio_enable(dev, GPIO_12, 1);
|
|
+ cx23885_gpio_enable(dev, GPIO_13, 1);
|
|
+
|
|
+ switch (voltage) {
|
|
+ case SEC_VOLTAGE_13:
|
|
+ cx23885_gpio_set(dev, GPIO_13);
|
|
+ cx23885_gpio_clear(dev, GPIO_12);
|
|
+ break;
|
|
+ case SEC_VOLTAGE_18:
|
|
+ cx23885_gpio_set(dev, GPIO_13);
|
|
+ cx23885_gpio_set(dev, GPIO_12);
|
|
+ break;
|
|
+ case SEC_VOLTAGE_OFF:
|
|
+ cx23885_gpio_clear(dev, GPIO_13);
|
|
+ cx23885_gpio_clear(dev, GPIO_12);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-f300.h linux-3.2.10/drivers/media/video/cx23885/cx23885-f300.h
|
|
--- linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-f300.h 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx23885/cx23885-f300.h 2012-03-16 10:55:17.000000000 +0100
|
|
@@ -1,2 +1,8 @@
|
|
+extern int dvbsky_set_voltage_sec(struct dvb_frontend *fe,
|
|
+ fe_sec_voltage_t voltage);
|
|
+
|
|
+extern int bst_set_voltage(struct dvb_frontend *fe,
|
|
+ fe_sec_voltage_t voltage);
|
|
+
|
|
extern int f300_set_voltage(struct dvb_frontend *fe,
|
|
fe_sec_voltage_t voltage);
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx23885/cx23885.h linux-3.2.10/drivers/media/video/cx23885/cx23885.h
|
|
--- linux-3.2.10.orig/drivers/media/video/cx23885/cx23885.h 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx23885/cx23885.h 2012-03-16 10:55:17.000000000 +0100
|
|
@@ -87,6 +87,9 @@
|
|
#define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30
|
|
#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31
|
|
#define CX23885_BOARD_MPX885 32
|
|
+#define CX23885_BOARD_BST_PS8512 (CX23885_BOARD_MPX885+1)
|
|
+#define CX23885_BOARD_DVBSKY_S952 (CX23885_BOARD_BST_PS8512+1)
|
|
+#define CX23885_BOARD_DVBSKY_S950 (CX23885_BOARD_DVBSKY_S952+1)
|
|
|
|
#define GPIO_0 0x00000001
|
|
#define GPIO_1 0x00000002
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-input.c linux-3.2.10/drivers/media/video/cx23885/cx23885-input.c
|
|
--- linux-3.2.10.orig/drivers/media/video/cx23885/cx23885-input.c 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx23885/cx23885-input.c 2012-03-16 10:55:17.000000000 +0100
|
|
@@ -87,6 +87,9 @@ void cx23885_input_rx_work_handler(struc
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1290:
|
|
case CX23885_BOARD_TEVII_S470:
|
|
case CX23885_BOARD_HAUPPAUGE_HVR1250:
|
|
+ case CX23885_BOARD_BST_PS8512:
|
|
+ case CX23885_BOARD_DVBSKY_S950:
|
|
+ case CX23885_BOARD_DVBSKY_S952:
|
|
/*
|
|
* The only boards we handle right now. However other boards
|
|
* using the CX2388x integrated IR controller should be similar
|
|
@@ -138,6 +141,9 @@ static int cx23885_input_ir_start(struct
|
|
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:
|
|
/*
|
|
* The IR controller on this board only returns pulse widths.
|
|
* Any other mode setting will fail to set up the device.
|
|
@@ -279,6 +285,15 @@ int cx23885_input_init(struct cx23885_de
|
|
/* 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:
|
|
+ /* Integrated CX2388[58] IR controller */
|
|
+ driver_type = RC_DRIVER_IR_RAW;
|
|
+ allowed_protos = RC_TYPE_ALL;
|
|
+ /* A guess at the remote */
|
|
+ rc_map = RC_MAP_DVBSKY;
|
|
+ break;
|
|
default:
|
|
return -ENODEV;
|
|
}
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx23885/Kconfig linux-3.2.10/drivers/media/video/cx23885/Kconfig
|
|
--- linux-3.2.10.orig/drivers/media/video/cx23885/Kconfig 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx23885/Kconfig 2012-03-16 10:55:17.000000000 +0100
|
|
@@ -20,6 +20,7 @@ config VIDEO_CX23885
|
|
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
|
|
select DVB_STV6110 if !DVB_FE_CUSTOMISE
|
|
select DVB_CX24116 if !DVB_FE_CUSTOMISE
|
|
+ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
|
|
select DVB_STV0900 if !DVB_FE_CUSTOMISE
|
|
select DVB_DS3000 if !DVB_FE_CUSTOMISE
|
|
select DVB_STV0367 if !DVB_FE_CUSTOMISE
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx88/cx88-cards.c linux-3.2.10/drivers/media/video/cx88/cx88-cards.c
|
|
--- linux-3.2.10.orig/drivers/media/video/cx88/cx88-cards.c 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx88/cx88-cards.c 2012-03-16 10:55:35.000000000 +0100
|
|
@@ -2237,6 +2237,18 @@ static const struct cx88_board cx88_boar
|
|
} },
|
|
.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,
|
|
+ },
|
|
};
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
@@ -2726,6 +2738,10 @@ static const struct cx88_subid cx88_subi
|
|
.subvendor = 0x1822,
|
|
.subdevice = 0x0023,
|
|
.card = CX88_BOARD_TWINHAN_VP1027_DVBS,
|
|
+ }, {
|
|
+ .subvendor = 0x14f1,
|
|
+ .subdevice = 0x8312,
|
|
+ .card = CX88_BOARD_BST_PS8312,
|
|
},
|
|
};
|
|
|
|
@@ -3454,7 +3470,13 @@ static void cx88_card_setup(struct cx88_
|
|
msleep(100);
|
|
cx_write(MO_SRST_IO, 1);
|
|
msleep(100);
|
|
- break;
|
|
+ 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 -uprN linux-3.2.10.orig/drivers/media/video/cx88/cx88-dvb.c linux-3.2.10/drivers/media/video/cx88/cx88-dvb.c
|
|
--- linux-3.2.10.orig/drivers/media/video/cx88/cx88-dvb.c 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx88/cx88-dvb.c 2012-03-16 10:55:35.000000000 +0100
|
|
@@ -54,6 +54,7 @@
|
|
#include "stv0288.h"
|
|
#include "stb6000.h"
|
|
#include "cx24116.h"
|
|
+#include "m88ds3103.h"
|
|
#include "stv0900.h"
|
|
#include "stb6100.h"
|
|
#include "stb6100_proc.h"
|
|
@@ -458,6 +459,56 @@ static int tevii_dvbs_set_voltage(struct
|
|
return core->prev_set_voltage(fe, voltage);
|
|
return 0;
|
|
}
|
|
+/*CX88_BOARD_BST_PS8312*/
|
|
+static int bst_dvbs_set_voltage(struct dvb_frontend *fe,
|
|
+ fe_sec_voltage_t voltage)
|
|
+{
|
|
+ struct cx8802_dev *dev= fe->dvb->priv;
|
|
+ struct cx88_core *core = dev->core;
|
|
+
|
|
+ cx_write(MO_GP1_IO, 0x111111);
|
|
+ switch (voltage) {
|
|
+ case SEC_VOLTAGE_13:
|
|
+ cx_write(MO_GP1_IO, 0x020200);
|
|
+ break;
|
|
+ case SEC_VOLTAGE_18:
|
|
+ cx_write(MO_GP1_IO, 0x020202);
|
|
+ break;
|
|
+ case SEC_VOLTAGE_OFF:
|
|
+ cx_write(MO_GP1_IO, 0x111100);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (core->prev_set_voltage)
|
|
+ return core->prev_set_voltage(fe, voltage);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bst_dvbs_set_voltage_v2(struct dvb_frontend *fe,
|
|
+ fe_sec_voltage_t voltage)
|
|
+{
|
|
+ struct cx8802_dev *dev= fe->dvb->priv;
|
|
+ struct cx88_core *core = dev->core;
|
|
+
|
|
+ cx_write(MO_GP1_IO, 0x111101);
|
|
+ switch (voltage) {
|
|
+ case SEC_VOLTAGE_13:
|
|
+ cx_write(MO_GP1_IO, 0x020200);
|
|
+ break;
|
|
+ case SEC_VOLTAGE_18:
|
|
+
|
|
+ cx_write(MO_GP1_IO, 0x020202);
|
|
+ break;
|
|
+ case SEC_VOLTAGE_OFF:
|
|
+
|
|
+ cx_write(MO_GP1_IO, 0x111110);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (core->prev_set_voltage)
|
|
+ return core->prev_set_voltage(fe, voltage);
|
|
+ return 0;
|
|
+}
|
|
|
|
static int vp1027_set_voltage(struct dvb_frontend *fe,
|
|
fe_sec_voltage_t voltage)
|
|
@@ -700,6 +751,11 @@ static struct ds3000_config tevii_ds3000
|
|
.set_ts_params = ds3000_set_ts_param,
|
|
};
|
|
|
|
+static struct m88ds3103_config dvbsky_ds3103_config = {
|
|
+ .demod_address = 0x68,
|
|
+ .set_ts_params = ds3000_set_ts_param,
|
|
+};
|
|
+
|
|
static const struct stv0900_config prof_7301_stv0900_config = {
|
|
.demod_address = 0x6a,
|
|
/* demod_mode = 0,*/
|
|
@@ -1458,6 +1514,36 @@ static int dvb_register(struct cx8802_de
|
|
if (fe0->dvb.frontend != NULL)
|
|
fe0->dvb.frontend->ops.set_voltage =
|
|
tevii_dvbs_set_voltage;
|
|
+ break;
|
|
+ case CX88_BOARD_BST_PS8312:
|
|
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
|
|
+ &dvbsky_ds3103_config,
|
|
+ &core->i2c_adap);
|
|
+ if (fe0->dvb.frontend != NULL)
|
|
+ {
|
|
+ int ret;
|
|
+ u8 b0[] = { 0x60 };
|
|
+ u8 b1[2] = { 0 };
|
|
+ struct i2c_msg msg[] = {
|
|
+ {
|
|
+ .addr = 0x50,
|
|
+ .flags = 0,
|
|
+ .buf = b0,
|
|
+ .len = 1
|
|
+ }, {
|
|
+ .addr = 0x50,
|
|
+ .flags = I2C_M_RD,
|
|
+ .buf = b1,
|
|
+ .len = 2
|
|
+ }
|
|
+ };
|
|
+ ret = i2c_transfer(&core->i2c_adap, msg, 2);
|
|
+ printk("PS8312: config = %02x, %02x", b1[0],b1[1]);
|
|
+ if(b1[0] == 0xaa)
|
|
+ fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage_v2;
|
|
+ else
|
|
+ fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage;
|
|
+ }
|
|
break;
|
|
case CX88_BOARD_OMICOM_SS4_PCI:
|
|
case CX88_BOARD_TBS_8920:
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx88/cx88.h linux-3.2.10/drivers/media/video/cx88/cx88.h
|
|
--- linux-3.2.10.orig/drivers/media/video/cx88/cx88.h 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx88/cx88.h 2012-03-16 10:55:35.000000000 +0100
|
|
@@ -244,6 +244,7 @@ extern const struct sram_channel const c
|
|
#define CX88_BOARD_TEVII_S464 86
|
|
#define CX88_BOARD_WINFAST_DTV2000H_PLUS 87
|
|
#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
|
|
+#define CX88_BOARD_BST_PS8312 (CX88_BOARD_WINFAST_DTV1800H_XC4000+1)
|
|
|
|
enum cx88_itype {
|
|
CX88_VMUX_COMPOSITE1 = 1,
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx88/cx88-input.c linux-3.2.10/drivers/media/video/cx88/cx88-input.c
|
|
--- linux-3.2.10.orig/drivers/media/video/cx88/cx88-input.c 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx88/cx88-input.c 2012-03-16 10:55:35.000000000 +0100
|
|
@@ -415,6 +415,10 @@ int cx88_ir_init(struct cx88_core *core,
|
|
rc_type = RC_TYPE_NEC;
|
|
ir->sampling = 0xff00; /* address */
|
|
break;
|
|
+ case CX88_BOARD_BST_PS8312:
|
|
+ ir_codes = RC_MAP_DVBSKY;
|
|
+ ir->sampling = 0xff00; /* address */
|
|
+ break;
|
|
}
|
|
|
|
if (!ir_codes) {
|
|
diff -uprN linux-3.2.10.orig/drivers/media/video/cx88/Kconfig linux-3.2.10/drivers/media/video/cx88/Kconfig
|
|
--- linux-3.2.10.orig/drivers/media/video/cx88/Kconfig 2012-03-16 10:41:16.000000000 +0100
|
|
+++ linux-3.2.10/drivers/media/video/cx88/Kconfig 2012-03-16 10:55:35.000000000 +0100
|
|
@@ -57,6 +57,7 @@ config VIDEO_CX88_DVB
|
|
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
|
|
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
|
|
select DVB_CX24116 if !DVB_FE_CUSTOMISE
|
|
+ select DVB_M88DS3103 if !DVB_FE_CUSTOMISE
|
|
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
|
select DVB_STV0288 if !DVB_FE_CUSTOMISE
|
|
select DVB_STB6000 if !DVB_FE_CUSTOMISE
|
|
diff -uprN linux-3.2.10.orig/include/media/rc-map.h linux-3.2.10/include/media/rc-map.h
|
|
--- linux-3.2.10.orig/include/media/rc-map.h 2012-03-16 10:41:11.000000000 +0100
|
|
+++ linux-3.2.10/include/media/rc-map.h 2012-03-16 10:56:20.000000000 +0100
|
|
@@ -83,6 +83,7 @@ void rc_map_init(void);
|
|
#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"
|