summaryrefslogtreecommitdiff
path: root/linux/drivers/media/common
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/common')
-rw-r--r--linux/drivers/media/common/ir-keymaps.c55
-rw-r--r--linux/drivers/media/common/saa7146_core.c2
-rw-r--r--linux/drivers/media/common/saa7146_fops.c4
-rw-r--r--linux/drivers/media/common/saa7146_video.c23
-rw-r--r--linux/drivers/media/common/tuners/Kconfig16
-rw-r--r--linux/drivers/media/common/tuners/Makefile1
-rw-r--r--linux/drivers/media/common/tuners/mt2060.c38
-rw-r--r--linux/drivers/media/common/tuners/mt20xx.c3
-rw-r--r--linux/drivers/media/common/tuners/mt2131.c2
-rw-r--r--linux/drivers/media/common/tuners/mt2131.h2
-rw-r--r--linux/drivers/media/common/tuners/mt2131_priv.h2
-rw-r--r--linux/drivers/media/common/tuners/mxl5005s.c4
-rw-r--r--linux/drivers/media/common/tuners/mxl5005s.h2
-rw-r--r--linux/drivers/media/common/tuners/mxl5007t.c1051
-rw-r--r--linux/drivers/media/common/tuners/mxl5007t.h104
-rw-r--r--linux/drivers/media/common/tuners/tda18271-fe.c1
-rw-r--r--linux/drivers/media/common/tuners/tda9887.c5
-rw-r--r--linux/drivers/media/common/tuners/tuner-simple.c38
-rw-r--r--linux/drivers/media/common/tuners/tuner-types.c22
-rw-r--r--linux/drivers/media/common/tuners/tuner-xc2028.h1
-rw-r--r--linux/drivers/media/common/tuners/xc5000.c113
-rw-r--r--linux/drivers/media/common/tuners/xc5000.h8
-rw-r--r--linux/drivers/media/common/tuners/xc5000_priv.h37
23 files changed, 1401 insertions, 133 deletions
diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c
index a464ad34e..f1d172a3f 100644
--- a/linux/drivers/media/common/ir-keymaps.c
+++ b/linux/drivers/media/common/ir-keymaps.c
@@ -1842,12 +1842,61 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
[ 0x41 ] = KEY_GREEN, /* AP2 */
[ 0x47 ] = KEY_YELLOW, /* AP3 */
[ 0x57 ] = KEY_BLUE, /* AP4 */
-
-
};
-
EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
+/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton
+ Mauro Carvalho Chehab <mchehab@infradead.org> */
+IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE] = {
+ [0x4c] = KEY_POWER2,
+ [0x4a] = KEY_TUNER,
+ [0x40] = KEY_1,
+ [0x60] = KEY_2,
+ [0x50] = KEY_3,
+ [0x70] = KEY_4,
+ [0x48] = KEY_5,
+ [0x68] = KEY_6,
+ [0x58] = KEY_7,
+ [0x78] = KEY_8,
+ [0x44] = KEY_9,
+ [0x54] = KEY_0,
+
+ [0x64] = KEY_LAST, /* +100 */
+ [0x4e] = KEY_AGAIN, /* Recall */
+
+ [0x6c] = KEY_SWITCHVIDEOMODE, /* Video Source */
+ [0x5e] = KEY_MENU,
+ [0x56] = KEY_SCREEN,
+ [0x7a] = KEY_SETUP,
+
+ [0x46] = KEY_MUTE,
+ [0x5c] = KEY_MODE, /* Stereo */
+ [0x74] = KEY_INFO,
+ [0x7c] = KEY_CLEAR,
+
+ [0x55] = KEY_UP,
+ [0x49] = KEY_DOWN,
+ [0x7e] = KEY_LEFT,
+ [0x59] = KEY_RIGHT,
+ [0x6a] = KEY_ENTER,
+
+ [0x42] = KEY_VOLUMEUP,
+ [0x62] = KEY_VOLUMEDOWN,
+ [0x52] = KEY_CHANNELUP,
+ [0x72] = KEY_CHANNELDOWN,
+
+ [0x41] = KEY_RECORD,
+ [0x51] = KEY_SHUFFLE, /* Snapshot */
+ [0x75] = KEY_TIME, /* Timeshift */
+ [0x71] = KEY_TV2, /* PIP */
+
+ [0x45] = KEY_REWIND,
+ [0x6f] = KEY_PAUSE,
+ [0x7d] = KEY_FORWARD,
+ [0x79] = KEY_STOP,
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2);
+
/* for the Technotrend 1500 bundled remotes (grey and black): */
IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
[ 0x01 ] = KEY_POWER,
diff --git a/linux/drivers/media/common/saa7146_core.c b/linux/drivers/media/common/saa7146_core.c
index 7bcf1eb14..9bce837f3 100644
--- a/linux/drivers/media/common/saa7146_core.c
+++ b/linux/drivers/media/common/saa7146_core.c
@@ -234,7 +234,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt)
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt)
{
__le32 *cpu;
- dma_addr_t dma_addr;
+ dma_addr_t dma_addr = 0;
cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);
if (NULL == cpu) {
diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c
index ac035cbcf..37a227d01 100644
--- a/linux/drivers/media/common/saa7146_fops.c
+++ b/linux/drivers/media/common/saa7146_fops.c
@@ -534,7 +534,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
memcpy(vfd, &device_template, sizeof(struct video_device));
strlcpy(vfd->name, name, sizeof(vfd->name));
vfd->release = video_device_release;
- vfd->priv = dev;
+ video_set_drvdata(vfd, dev);
// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
if (video_register_device(vfd, type, -1) < 0) {
@@ -564,7 +564,7 @@ int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev
DEB_EE(("dev:%p\n",dev));
- if( VFL_TYPE_GRABBER == (*vid)->type ) {
+ if ((*vid)->vfl_type == VFL_TYPE_GRABBER) {
vv->video_minor = -1;
} else {
vv->vbi_minor = -1;
diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c
index d3185e610..8804d4e78 100644
--- a/linux/drivers/media/common/saa7146_video.c
+++ b/linux/drivers/media/common/saa7146_video.c
@@ -657,7 +657,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
/* if we have a user buffer, the first page may not be
aligned to a page boundary. */
- pt1->offset = list->offset;
+ pt1->offset = dma->sglist->offset;
pt2->offset = pt1->offset+o1;
pt3->offset = pt1->offset+o2;
@@ -959,21 +959,18 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc *f = arg;
- int index;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- case V4L2_BUF_TYPE_VIDEO_OVERLAY: {
- index = f->index;
- if (index < 0 || index >= NUM_FORMATS) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (f->index >= NUM_FORMATS)
return -EINVAL;
- }
- memset(f,0,sizeof(*f));
- f->index = index;
- strlcpy((char *)f->description,formats[index].name,sizeof(f->description));
- f->pixelformat = formats[index].pixelformat;
+ strlcpy((char *)f->description, formats[f->index].name,
+ sizeof(f->description));
+ f->pixelformat = formats[f->index].pixelformat;
+ f->flags = 0;
+ memset(f->reserved, 0, sizeof(f->reserved));
break;
- }
default:
return -EINVAL;
}
@@ -1072,7 +1069,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
{
v4l2_std_id *id = arg;
int found = 0;
- int i, err;
+ int i;
DEB_EE(("VIDIOC_S_STD\n"));
@@ -1120,7 +1117,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
case VIDIOC_OVERLAY:
{
int on = *(int *)arg;
- int err = 0;
DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
if (on != 0) {
@@ -1196,7 +1192,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q;
int i;
/* fixme: number of capture buffers and sizes for v4l apps */
diff --git a/linux/drivers/media/common/tuners/Kconfig b/linux/drivers/media/common/tuners/Kconfig
index 850d5689b..6f92beaa5 100644
--- a/linux/drivers/media/common/tuners/Kconfig
+++ b/linux/drivers/media/common/tuners/Kconfig
@@ -21,9 +21,8 @@ config MEDIA_TUNER
tristate
default VIDEO_MEDIA && I2C
depends on VIDEO_MEDIA && I2C
- select FW_LOADER if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
- select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
- select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
+ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE
select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE
@@ -138,8 +137,6 @@ config MEDIA_TUNER_QT1010
config MEDIA_TUNER_XC2028
tristate "XCeive xc2028/xc3028 tuners"
depends on VIDEO_MEDIA && I2C
- depends on HOTPLUG
- select FW_LOADER
default m if MEDIA_TUNER_CUSTOMIZE
help
Say Y here to include support for the xc2028/xc3028 tuners.
@@ -147,8 +144,6 @@ config MEDIA_TUNER_XC2028
config MEDIA_TUNER_XC5000
tristate "Xceive XC5000 silicon tuner"
depends on VIDEO_MEDIA && I2C
- depends on HOTPLUG
- select FW_LOADER
default m if DVB_FE_CUSTOMISE
help
A driver for the silicon tuner XC5000 from Xceive.
@@ -162,4 +157,11 @@ config MEDIA_TUNER_MXL5005S
help
A driver for the silicon tuner MXL5005S from MaxLinear.
+config MEDIA_TUNER_MXL5007T
+ tristate "MaxLinear MxL5007T silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon tuner MxL5007T from MaxLinear.
+
endif # MEDIA_TUNER_CUSTOMIZE
diff --git a/linux/drivers/media/common/tuners/Makefile b/linux/drivers/media/common/tuners/Makefile
index 55f7e6706..4dfbe5b82 100644
--- a/linux/drivers/media/common/tuners/Makefile
+++ b/linux/drivers/media/common/tuners/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
+obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/common/tuners/mt2060.c b/linux/drivers/media/common/tuners/mt2060.c
index 355817754..d1962bb24 100644
--- a/linux/drivers/media/common/tuners/mt2060.c
+++ b/linux/drivers/media/common/tuners/mt2060.c
@@ -177,6 +177,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
b[0] = REG_LO1B1;
b[1] = 0xFF;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
mt2060_writeregs(priv,b,2);
freq = params->frequency / 1000; // Hz -> kHz
@@ -240,6 +243,9 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
i++;
} while (i<10);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
return ret;
}
@@ -303,13 +309,35 @@ static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static int mt2060_init(struct dvb_frontend *fe)
{
struct mt2060_priv *priv = fe->tuner_priv;
- return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ ret = mt2060_writereg(priv, REG_VGAG,
+ (priv->cfg->clock_out << 6) | 0x33);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ return ret;
}
static int mt2060_sleep(struct dvb_frontend *fe)
{
struct mt2060_priv *priv = fe->tuner_priv;
- return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ ret = mt2060_writereg(priv, REG_VGAG,
+ (priv->cfg->clock_out << 6) | 0x30);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ return ret;
}
static int mt2060_release(struct dvb_frontend *fe)
@@ -351,6 +379,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
priv->i2c = i2c;
priv->if1_freq = if1;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
kfree(priv);
return NULL;
@@ -367,6 +398,9 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
mt2060_calibrate(priv);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
return fe;
}
EXPORT_SYMBOL(mt2060_attach);
diff --git a/linux/drivers/media/common/tuners/mt20xx.c b/linux/drivers/media/common/tuners/mt20xx.c
index 9d9f1cf11..2669cd0bf 100644
--- a/linux/drivers/media/common/tuners/mt20xx.c
+++ b/linux/drivers/media/common/tuners/mt20xx.c
@@ -149,7 +149,8 @@ static int mt2032_compute_freq(struct dvb_frontend *fe,
tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
- if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+ if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 ||
+ lo2n > 30) {
tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
lo1a, lo1n, lo2a,lo2n);
return(-1);
diff --git a/linux/drivers/media/common/tuners/mt2131.c b/linux/drivers/media/common/tuners/mt2131.c
index becc409d9..c528db6bb 100644
--- a/linux/drivers/media/common/tuners/mt2131.c
+++ b/linux/drivers/media/common/tuners/mt2131.c
@@ -1,7 +1,7 @@
/*
* Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * 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
diff --git a/linux/drivers/media/common/tuners/mt2131.h b/linux/drivers/media/common/tuners/mt2131.h
index cd8376f6f..6632de640 100644
--- a/linux/drivers/media/common/tuners/mt2131.h
+++ b/linux/drivers/media/common/tuners/mt2131.h
@@ -1,7 +1,7 @@
/*
* Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * 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
diff --git a/linux/drivers/media/common/tuners/mt2131_priv.h b/linux/drivers/media/common/tuners/mt2131_priv.h
index e930759c2..4e05a67e8 100644
--- a/linux/drivers/media/common/tuners/mt2131_priv.h
+++ b/linux/drivers/media/common/tuners/mt2131_priv.h
@@ -1,7 +1,7 @@
/*
* Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * 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
diff --git a/linux/drivers/media/common/tuners/mxl5005s.c b/linux/drivers/media/common/tuners/mxl5005s.c
index e356db855..20405506a 100644
--- a/linux/drivers/media/common/tuners/mxl5005s.c
+++ b/linux/drivers/media/common/tuners/mxl5005s.c
@@ -2,7 +2,7 @@
MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
Copyright (C) 2008 MaxLinear
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
Functions:
mxl5005s_reset()
mxl5005s_writereg()
@@ -3839,7 +3839,7 @@ static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
/* ----------------------------------------------------------------
* Begin: Everything after here is new code to adapt the
* proprietary Realtek driver into a Linux API tuner.
- * Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
*/
static int mxl5005s_reset(struct dvb_frontend *fe)
{
diff --git a/linux/drivers/media/common/tuners/mxl5005s.h b/linux/drivers/media/common/tuners/mxl5005s.h
index 396db150b..7ac6815b3 100644
--- a/linux/drivers/media/common/tuners/mxl5005s.h
+++ b/linux/drivers/media/common/tuners/mxl5005s.h
@@ -2,7 +2,7 @@
MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
Copyright (C) 2008 MaxLinear
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 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
diff --git a/linux/drivers/media/common/tuners/mxl5007t.c b/linux/drivers/media/common/tuners/mxl5007t.c
new file mode 100644
index 000000000..19abe35b9
--- /dev/null
+++ b/linux/drivers/media/common/tuners/mxl5007t.c
@@ -0,0 +1,1051 @@
+/*
+ * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner
+ *
+ * Copyright (C) 2008 Michael Krufky <mkrufky@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/i2c.h>
+#include <linux/types.h>
+#include "compat.h"
+#include <linux/videodev2.h>
+#include "tuner-i2c.h"
+#include "mxl5007t.h"
+
+static DEFINE_MUTEX(mxl5007t_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+static int mxl5007t_debug;
+module_param_named(debug, mxl5007t_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level");
+
+/* ------------------------------------------------------------------------- */
+
+#define mxl_printk(kern, fmt, arg...) \
+ printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define mxl_err(fmt, arg...) \
+ mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg)
+
+#define mxl_warn(fmt, arg...) \
+ mxl_printk(KERN_WARNING, fmt, ##arg)
+
+#define mxl_info(fmt, arg...) \
+ mxl_printk(KERN_INFO, fmt, ##arg)
+
+#define mxl_debug(fmt, arg...) \
+({ \
+ if (mxl5007t_debug) \
+ mxl_printk(KERN_DEBUG, fmt, ##arg); \
+})
+
+#define mxl_fail(ret) \
+({ \
+ int __ret; \
+ __ret = (ret < 0); \
+ if (__ret) \
+ mxl_printk(KERN_ERR, "error %d on line %d", \
+ ret, __LINE__); \
+ __ret; \
+})
+
+/* ------------------------------------------------------------------------- */
+
+#define MHz 1000000
+
+enum mxl5007t_mode {
+ MxL_MODE_OTA_DVBT_ATSC = 0,
+ MxL_MODE_OTA_NTSC_PAL_GH = 1,
+ MxL_MODE_OTA_PAL_IB = 2,
+ MxL_MODE_OTA_PAL_D_SECAM_KL = 3,
+ MxL_MODE_OTA_ISDBT = 4,
+ MxL_MODE_CABLE_DIGITAL = 0x10,
+ MxL_MODE_CABLE_NTSC_PAL_GH = 0x11,
+ MxL_MODE_CABLE_PAL_IB = 0x12,
+ MxL_MODE_CABLE_PAL_D_SECAM_KL = 0x13,
+ MxL_MODE_CABLE_SCTE40 = 0x14,
+};
+
+enum mxl5007t_chip_version {
+ MxL_UNKNOWN_ID = 0x00,
+ MxL_5007_V1_F1 = 0x11,
+ MxL_5007_V1_F2 = 0x12,
+ MxL_5007_V2_100_F1 = 0x21,
+ MxL_5007_V2_100_F2 = 0x22,
+ MxL_5007_V2_200_F1 = 0x23,
+ MxL_5007_V2_200_F2 = 0x24,
+};
+
+struct reg_pair_t {
+ u8 reg;
+ u8 val;
+};
+
+/* ------------------------------------------------------------------------- */
+
+static struct reg_pair_t init_tab[] = {
+ { 0x0b, 0x44 }, /* XTAL */
+ { 0x0c, 0x60 }, /* IF */
+ { 0x10, 0x00 }, /* MISC */
+ { 0x12, 0xca }, /* IDAC */
+ { 0x16, 0x90 }, /* MODE */
+ { 0x32, 0x38 }, /* MODE Analog/Digital */
+ { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */
+ { 0x2c, 0x34 }, /* OVERRIDE */
+ { 0x4d, 0x40 }, /* OVERRIDE */
+ { 0x7f, 0x02 }, /* OVERRIDE */
+ { 0x9a, 0x52 }, /* OVERRIDE */
+ { 0x48, 0x5a }, /* OVERRIDE */
+ { 0x76, 0x1a }, /* OVERRIDE */
+ { 0x6a, 0x48 }, /* OVERRIDE */
+ { 0x64, 0x28 }, /* OVERRIDE */
+ { 0x66, 0xe6 }, /* OVERRIDE */
+ { 0x35, 0x0e }, /* OVERRIDE */
+ { 0x7e, 0x01 }, /* OVERRIDE */
+ { 0x83, 0x00 }, /* OVERRIDE */
+ { 0x04, 0x0b }, /* OVERRIDE */
+ { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */
+ { 0, 0 }
+};
+
+static struct reg_pair_t init_tab_cable[] = {
+ { 0x0b, 0x44 }, /* XTAL */
+ { 0x0c, 0x60 }, /* IF */
+ { 0x10, 0x00 }, /* MISC */
+ { 0x12, 0xca }, /* IDAC */
+ { 0x16, 0x90 }, /* MODE */
+ { 0x32, 0x38 }, /* MODE A/D */
+ { 0x71, 0x3f }, /* TOP1 */
+ { 0x72, 0x3f }, /* TOP2 */
+ { 0x74, 0x3f }, /* TOP3 */
+ { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */
+ { 0x2c, 0x34 }, /* OVERRIDE */
+ { 0x4d, 0x40 }, /* OVERRIDE */
+ { 0x7f, 0x02 }, /* OVERRIDE */
+ { 0x9a, 0x52 }, /* OVERRIDE */
+ { 0x48, 0x5a }, /* OVERRIDE */
+ { 0x76, 0x1a }, /* OVERRIDE */
+ { 0x6a, 0x48 }, /* OVERRIDE */
+ { 0x64, 0x28 }, /* OVERRIDE */
+ { 0x66, 0xe6 }, /* OVERRIDE */
+ { 0x35, 0x0e }, /* OVERRIDE */
+ { 0x7e, 0x01 }, /* OVERRIDE */
+ { 0x04, 0x0b }, /* OVERRIDE */
+ { 0x68, 0xb4 }, /* OVERRIDE */
+ { 0x36, 0x00 }, /* OVERRIDE */
+ { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */
+ { 0, 0 }
+};
+
+/* ------------------------------------------------------------------------- */
+
+static struct reg_pair_t reg_pair_rftune[] = {
+ { 0x11, 0x00 }, /* abort tune */
+ { 0x13, 0x15 },
+ { 0x14, 0x40 },
+ { 0x15, 0x0e },
+ { 0x11, 0x02 }, /* start tune */
+ { 0, 0 }
+};
+
+/* ------------------------------------------------------------------------- */
+
+struct mxl5007t_state {
+ struct list_head hybrid_tuner_instance_list;
+ struct tuner_i2c_props i2c_props;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+ struct mutex lock;
+#else
+ struct semaphore lock;
+#endif
+
+ struct mxl5007t_config *config;
+
+ enum mxl5007t_chip_version chip_id;
+
+ struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)];
+ struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)];
+ struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)];
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* called by _init and _rftun to manipulate the register arrays */
+
+static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val)
+{
+ unsigned int i = 0;
+
+ while (reg_pair[i].reg || reg_pair[i].val) {
+ if (reg_pair[i].reg == reg) {
+ reg_pair[i].val &= ~mask;
+ reg_pair[i].val |= val;
+ }
+ i++;
+
+ }
+ return;
+}
+
+static void copy_reg_bits(struct reg_pair_t *reg_pair1,
+ struct reg_pair_t *reg_pair2)
+{
+ unsigned int i, j;
+
+ i = j = 0;
+
+ while (reg_pair1[i].reg || reg_pair1[i].val) {
+ while (reg_pair2[j].reg || reg_pair2[j].reg) {
+ if (reg_pair1[i].reg != reg_pair2[j].reg) {
+ j++;
+ continue;
+ }
+ reg_pair2[j].val = reg_pair1[i].val;
+ break;
+ }
+ i++;
+ }
+ return;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void mxl5007t_set_mode_bits(struct mxl5007t_state *state,
+ enum mxl5007t_mode mode,
+ s32 if_diff_out_level)
+{
+ switch (mode) {
+ case MxL_MODE_OTA_DVBT_ATSC:
+ set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06);
+ set_reg_bits(state->tab_init, 0x35, 0xff, 0x0e);
+ break;
+ case MxL_MODE_OTA_ISDBT:
+ set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06);
+ set_reg_bits(state->tab_init, 0x35, 0xff, 0x12);
+ break;
+ case MxL_MODE_OTA_NTSC_PAL_GH:
+ set_reg_bits(state->tab_init, 0x16, 0x70, 0x00);
+ set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+ break;
+ case MxL_MODE_OTA_PAL_IB:
+ set_reg_bits(state->tab_init, 0x16, 0x70, 0x10);
+ set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+ break;
+ case MxL_MODE_OTA_PAL_D_SECAM_KL:
+ set_reg_bits(state->tab_init, 0x16, 0x70, 0x20);
+ set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+ break;
+ case MxL_MODE_CABLE_DIGITAL:
+ set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+ set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+ 8 - if_diff_out_level);
+ set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+ break;
+ case MxL_MODE_CABLE_NTSC_PAL_GH:
+ set_reg_bits(state->tab_init, 0x16, 0x70, 0x00);
+ set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+ set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+ set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+ 8 - if_diff_out_level);
+ set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+ break;
+ case MxL_MODE_CABLE_PAL_IB:
+ set_reg_bits(state->tab_init, 0x16, 0x70, 0x10);
+ set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+ set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+ set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+ 8 - if_diff_out_level);
+ set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+ break;
+ case MxL_MODE_CABLE_PAL_D_SECAM_KL:
+ set_reg_bits(state->tab_init, 0x16, 0x70, 0x20);
+ set_reg_bits(state->tab_init, 0x32, 0xff, 0x85);
+ set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+ set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+ 8 - if_diff_out_level);
+ set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+ break;
+ case MxL_MODE_CABLE_SCTE40:
+ set_reg_bits(state->tab_init_cable, 0x36, 0xff, 0x08);
+ set_reg_bits(state->tab_init_cable, 0x68, 0xff, 0xbc);
+ set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01);
+ set_reg_bits(state->tab_init_cable, 0x72, 0xff,
+ 8 - if_diff_out_level);
+ set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17);
+ break;
+ default:
+ mxl_fail(-EINVAL);
+ }
+ return;
+}
+
+static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
+ enum mxl5007t_if_freq if_freq,
+ int invert_if)
+{
+ u8 val;
+
+ switch (if_freq) {
+ case MxL_IF_4_MHZ:
+ val = 0x00;
+ break;
+ case MxL_IF_4_5_MHZ:
+ val = 0x20;
+ break;
+ case MxL_IF_4_57_MHZ:
+ val = 0x30;
+ break;
+ case MxL_IF_5_MHZ:
+ val = 0x40;
+ break;
+ case MxL_IF_5_38_MHZ:
+ val = 0x50;
+ break;
+ case MxL_IF_6_MHZ:
+ val = 0x60;
+ break;
+ case MxL_IF_6_28_MHZ:
+ val = 0x70;
+ break;
+ case MxL_IF_9_1915_MHZ:
+ val = 0x80;
+ break;
+ case MxL_IF_35_25_MHZ:
+ val = 0x90;
+ break;
+ case MxL_IF_36_15_MHZ:
+ val = 0xa0;
+ break;
+ case MxL_IF_44_MHZ:
+ val = 0xb0;
+ break;
+ default:
+ mxl_fail(-EINVAL);
+ return;
+ }
+ set_reg_bits(state->tab_init, 0x0c, 0xf0, val);
+
+ /* set inverted IF or normal IF */
+ set_reg_bits(state->tab_init, 0x0c, 0x08, invert_if ? 0x08 : 0x00);
+
+ return;
+}
+
+static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state,
+ enum mxl5007t_xtal_freq xtal_freq)
+{
+ u8 val;
+
+ switch (xtal_freq) {
+ case MxL_XTAL_16_MHZ:
+ val = 0x00; /* select xtal freq & Ref Freq */
+ break;
+ case MxL_XTAL_20_MHZ:
+ val = 0x11;
+ break;
+ case MxL_XTAL_20_25_MHZ:
+ val = 0x22;
+ break;
+ case MxL_XTAL_20_48_MHZ:
+ val = 0x33;
+ break;
+ case MxL_XTAL_24_MHZ:
+ val = 0x44;
+ break;
+ case MxL_XTAL_25_MHZ:
+ val = 0x55;
+ break;
+ case MxL_XTAL_25_14_MHZ:
+ val = 0x66;
+ break;
+ case MxL_XTAL_27_MHZ:
+ val = 0x77;
+ break;
+ case MxL_XTAL_28_8_MHZ:
+ val = 0x88;
+ break;
+ case MxL_XTAL_32_MHZ:
+ val = 0x99;
+ break;
+ case MxL_XTAL_40_MHZ:
+ val = 0xaa;
+ break;
+ case MxL_XTAL_44_MHZ:
+ val = 0xbb;
+ break;
+ case MxL_XTAL_48_MHZ:
+ val = 0xcc;
+ break;
+ case MxL_XTAL_49_3811_MHZ:
+ val = 0xdd;
+ break;
+ default:
+ mxl_fail(-EINVAL);
+ return;
+ }
+ set_reg_bits(state->tab_init, 0x0b, 0xff, val);
+
+ return;
+}
+
+static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state,
+ enum mxl5007t_mode mode)
+{
+ struct mxl5007t_config *cfg = state->config;
+
+ memcpy(&state->tab_init, &init_tab, sizeof(init_tab));
+ memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable));
+
+ mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level);
+ mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if);
+ mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz);
+
+ set_reg_bits(state->tab_init, 0x10, 0x40, cfg->loop_thru_enable << 6);
+
+ set_reg_bits(state->tab_init, 0xd8, 0x08, cfg->clk_out_enable << 3);
+
+ set_reg_bits(state->tab_init, 0x10, 0x07, cfg->clk_out_amp);
+
+ /* set IDAC to automatic mode control by AGC */
+ set_reg_bits(state->tab_init, 0x12, 0x80, 0x00);
+
+ if (mode >= MxL_MODE_CABLE_DIGITAL) {
+ copy_reg_bits(state->tab_init, state->tab_init_cable);
+ return state->tab_init_cable;
+ } else
+ return state->tab_init;
+}
+
+/* ------------------------------------------------------------------------- */
+
+enum mxl5007t_bw_mhz {
+ MxL_BW_6MHz = 6,
+ MxL_BW_7MHz = 7,
+ MxL_BW_8MHz = 8,
+};
+
+static void mxl5007t_set_bw_bits(struct mxl5007t_state *state,
+ enum mxl5007t_bw_mhz bw)
+{
+ u8 val;
+
+ switch (bw) {
+ case MxL_BW_6MHz:
+ val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A,
+ * and DIG_MODEINDEX_CSF */
+ break;
+ case MxL_BW_7MHz:
+ val = 0x21;
+ break;
+ case MxL_BW_8MHz:
+ val = 0x3f;
+ break;
+ default:
+ mxl_fail(-EINVAL);
+ return;
+ }
+ set_reg_bits(state->tab_rftune, 0x13, 0x3f, val);
+
+ return;
+}
+
+static struct
+reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state,
+ u32 rf_freq, enum mxl5007t_bw_mhz bw)
+{
+ u32 dig_rf_freq = 0;
+ u32 temp;
+ u32 frac_divider = 1000000;
+ unsigned int i;
+
+ memcpy(&state->tab_rftune, &reg_pair_rftune, sizeof(reg_pair_rftune));
+
+ mxl5007t_set_bw_bits(state, bw);
+
+ /* Convert RF frequency into 16 bits =>
+ * 10 bit integer (MHz) + 6 bit fraction */
+ dig_rf_freq = rf_freq / MHz;
+
+ temp = rf_freq % MHz;
+
+ for (i = 0; i < 6; i++) {
+ dig_rf_freq <<= 1;
+ frac_divider /= 2;
+ if (temp > frac_divider) {
+ temp -= frac_divider;
+ dig_rf_freq++;
+ }
+ }
+
+ /* add to have shift center point by 7.8124 kHz */
+ if (temp > 7812)
+ dig_rf_freq++;
+
+ set_reg_bits(state->tab_rftune, 0x14, 0xff, (u8)dig_rf_freq);
+ set_reg_bits(state->tab_rftune, 0x15, 0xff, (u8)(dig_rf_freq >> 8));
+
+ return state->tab_rftune;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val)
+{
+ u8 buf[] = { reg, val };
+ struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0,
+ .buf = buf, .len = 2 };
+ int ret;
+
+ ret = i2c_transfer(state->i2c_props.adap, &msg, 1);
+ if (ret != 1) {
+ mxl_err("failed!");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mxl5007t_write_regs(struct mxl5007t_state *state,
+ struct reg_pair_t *reg_pair)
+{
+ unsigned int i = 0;
+ int ret = 0;
+
+ while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) {
+ ret = mxl5007t_write_reg(state,
+ reg_pair[i].reg, reg_pair[i].val);
+ i++;
+ }
+ return ret;
+}
+
+static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[] = {
+ { .addr = state->i2c_props.addr, .flags = 0,
+ .buf = &reg, .len = 1 },
+ { .addr = state->i2c_props.addr, .flags = I2C_M_RD,
+ .buf = val, .len = 1 },
+ };
+ int ret;
+
+ ret = i2c_transfer(state->i2c_props.adap, msg, 2);
+ if (ret != 2) {
+ mxl_err("failed!");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mxl5007t_soft_reset(struct mxl5007t_state *state)
+{
+ u8 d = 0xff;
+ struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0,
+ .buf = &d, .len = 1 };
+
+ int ret = i2c_transfer(state->i2c_props.adap, &msg, 1);
+
+ if (ret != 1) {
+ mxl_err("failed!");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mxl5007t_tuner_init(struct mxl5007t_state *state,
+ enum mxl5007t_mode mode)
+{
+ struct reg_pair_t *init_regs;
+ int ret;
+
+ ret = mxl5007t_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ /* calculate initialization reg array */
+ init_regs = mxl5007t_calc_init_regs(state, mode);
+
+ ret = mxl5007t_write_regs(state, init_regs);
+ if (mxl_fail(ret))
+ goto fail;
+ mdelay(1);
+
+ ret = mxl5007t_write_reg(state, 0x2c, 0x35);
+ mxl_fail(ret);
+fail:
+ return ret;
+}
+
+static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz,
+ enum mxl5007t_bw_mhz bw)
+{
+ struct reg_pair_t *rf_tune_regs;
+ int ret;
+
+ /* calculate channel change reg array */
+ rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw);
+
+ ret = mxl5007t_write_regs(state, rf_tune_regs);
+ if (mxl_fail(ret))
+ goto fail;
+ msleep(3);
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_synth_lock_status(struct mxl5007t_state *state,
+ int *rf_locked, int *ref_locked)
+{
+ u8 d;
+ int ret;
+
+ *rf_locked = 0;
+ *ref_locked = 0;
+
+ ret = mxl5007t_read_reg(state, 0xcf, &d);
+ if (mxl_fail(ret))
+ goto fail;
+
+ if ((d & 0x0c) == 0x0c)
+ *rf_locked = 1;
+
+ if ((d & 0x03) == 0x03)
+ *ref_locked = 1;
+fail:
+ return ret;
+}
+
+static int mxl5007t_check_rf_input_power(struct mxl5007t_state *state,
+ s32 *rf_input_level)
+{
+ u8 d1, d2;
+ int ret;
+
+ ret = mxl5007t_read_reg(state, 0xb7, &d1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl5007t_read_reg(state, 0xbf, &d2);
+ if (mxl_fail(ret))
+ goto fail;
+
+ d2 = d2 >> 4;
+ if (d2 > 7)
+ d2 += 0xf0;
+
+ *rf_input_level = (s32)(d1 + d2 - 113);
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+ int rf_locked, ref_locked;
+ s32 rf_input_level;
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked);
+ if (mxl_fail(ret))
+ goto fail;
+ mxl_debug("%s%s", rf_locked ? "rf locked " : "",
+ ref_locked ? "ref locked" : "");
+
+ ret = mxl5007t_check_rf_input_power(state, &rf_input_level);
+ if (mxl_fail(ret))
+ goto fail;
+ mxl_debug("rf input power: %d", rf_input_level);
+fail:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+ enum mxl5007t_bw_mhz bw;
+ enum mxl5007t_mode mode;
+ int ret;
+ u32 freq = params->frequency;
+
+ if (fe->ops.info.type == FE_ATSC) {
+ switch (params->u.vsb.modulation) {
+ case VSB_8:
+ case VSB_16:
+ mode = MxL_MODE_OTA_DVBT_ATSC;
+ break;
+ case QAM_64:
+ case QAM_256:
+ mode = MxL_MODE_CABLE_DIGITAL;
+ break;
+ default:
+ mxl_err("modulation not set!");
+ return -EINVAL;
+ }
+ bw = MxL_BW_6MHz;
+ } else if (fe->ops.info.type == FE_OFDM) {
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ bw = MxL_BW_6MHz;
+ break;
+ case BANDWIDTH_7_MHZ:
+ bw = MxL_BW_7MHz;
+ break;
+ case BANDWIDTH_8_MHZ:
+ bw = MxL_BW_8MHz;
+ break;
+ default:
+ mxl_err("bandwidth not set!");
+ return -EINVAL;
+ }
+ mode = MxL_MODE_OTA_DVBT_ATSC;
+ } else {
+ mxl_err("modulation type not supported!");
+ return -EINVAL;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ mutex_lock(&state->lock);
+
+ ret = mxl5007t_tuner_init(state, mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl5007t_tuner_rf_tune(state, freq, bw);
+ if (mxl_fail(ret))
+ goto fail;
+
+ state->frequency = freq;
+ state->bandwidth = (fe->ops.info.type == FE_OFDM) ?
+ params->u.ofdm.bandwidth : 0;
+fail:
+ mutex_unlock(&state->lock);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return ret;
+}
+
+static int mxl5007t_set_analog_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+ enum mxl5007t_bw_mhz bw = 0; /* FIXME */
+ enum mxl5007t_mode cbl_mode;
+ enum mxl5007t_mode ota_mode;
+ char *mode_name;
+ int ret;
+ u32 freq = params->frequency * 62500;
+
+#if 0
+ if (params->mode == V4L2_TUNER_RADIO) {
+ freq = freq / 1000;
+ mode_name = "fm";
+ } else
+#else
+#define cable 1
+#endif
+ if (params->std & V4L2_STD_MN) {
+ cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
+ ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
+ mode_name = "MN";
+ } else if (params->std & V4L2_STD_B) {
+ cbl_mode = MxL_MODE_CABLE_PAL_IB;
+ ota_mode = MxL_MODE_OTA_PAL_IB;
+ mode_name = "B";
+ } else if (params->std & V4L2_STD_GH) {
+ cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
+ ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
+ mode_name = "GH";
+ } else if (params->std & V4L2_STD_PAL_I) {
+ cbl_mode = MxL_MODE_CABLE_PAL_IB;
+ ota_mode = MxL_MODE_OTA_PAL_IB;
+ mode_name = "I";
+ } else if (params->std & V4L2_STD_DK) {
+ cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
+ ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
+ mode_name = "DK";
+ } else if (params->std & V4L2_STD_SECAM_L) {
+ cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
+ ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
+ mode_name = "L";
+ } else if (params->std & V4L2_STD_SECAM_LC) {
+ cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL;
+ ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL;
+ mode_name = "L'";
+ } else {
+ mode_name = "xx";
+ /* FIXME */
+ cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH;
+ ota_mode = MxL_MODE_OTA_NTSC_PAL_GH;
+ }
+ mxl_debug("setting mxl5007 to system %s", mode_name);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ mutex_lock(&state->lock);
+
+ ret = mxl5007t_tuner_init(state, cable ? cbl_mode : ota_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl5007t_tuner_rf_tune(state, freq, bw);
+ if (mxl_fail(ret))
+ goto fail;
+
+ state->frequency = freq;
+ state->bandwidth = 0;
+fail:
+ mutex_unlock(&state->lock);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_init(struct dvb_frontend *fe)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+ int ret;
+ u8 d;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = mxl5007t_read_reg(state, 0x05, &d);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl5007t_write_reg(state, 0x05, d | 0x01);
+ mxl_fail(ret);
+fail:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return ret;
+}
+
+static int mxl5007t_sleep(struct dvb_frontend *fe)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+ int ret;
+ u8 d;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = mxl5007t_read_reg(state, 0x05, &d);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl5007t_write_reg(state, 0x05, d & ~0x01);
+ mxl_fail(ret);
+fail:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+ *frequency = state->frequency;
+ return 0;
+}
+
+static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+ *bandwidth = state->bandwidth;
+ return 0;
+}
+
+static int mxl5007t_release(struct dvb_frontend *fe)
+{
+ struct mxl5007t_state *state = fe->tuner_priv;
+
+ mutex_lock(&mxl5007t_list_mutex);
+
+ if (state)
+ hybrid_tuner_release_state(state);
+
+ mutex_unlock(&mxl5007t_list_mutex);
+
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static struct dvb_tuner_ops mxl5007t_tuner_ops = {
+ .info = {
+ .name = "MaxLinear MxL5007T",
+#if 0
+ .frequency_min = ,
+ .frequency_max = ,
+ .frequency_step = ,
+#endif
+ },
+ .init = mxl5007t_init,
+ .sleep = mxl5007t_sleep,
+ .set_params = mxl5007t_set_params,
+ .set_analog_params = mxl5007t_set_analog_params,
+ .get_status = mxl5007t_get_status,
+ .get_frequency = mxl5007t_get_frequency,
+ .get_bandwidth = mxl5007t_get_bandwidth,
+ .release = mxl5007t_release,
+};
+
+static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
+{
+ char *name;
+ int ret;
+ u8 id;
+
+ ret = mxl5007t_read_reg(state, 0xd3, &id);
+ if (mxl_fail(ret))
+ goto fail;
+
+ switch (id) {
+ case MxL_5007_V1_F1:
+ name = "MxL5007.v1.f1";
+ break;
+ case MxL_5007_V1_F2:
+ name = "MxL5007.v1.f2";
+ break;
+ case MxL_5007_V2_100_F1:
+ name = "MxL5007.v2.100.f1";
+ break;
+ case MxL_5007_V2_100_F2:
+ name = "MxL5007.v2.100.f2";
+ break;
+ case MxL_5007_V2_200_F1:
+ name = "MxL5007.v2.200.f1";
+ break;
+ case MxL_5007_V2_200_F2:
+ name = "MxL5007.v2.200.f2";
+ break;
+ default:
+#if 0
+ ret = -EINVAL;
+ goto fail;
+#else
+ name = "MxL5007T";
+ id = MxL_UNKNOWN_ID;
+#endif
+ }
+ state->chip_id = id;
+ mxl_info("%s detected @ %d-%04x", name,
+ i2c_adapter_id(state->i2c_props.adap),
+ state->i2c_props.addr);
+ return 0;
+fail:
+ mxl_warn("unable to identify device @ %d-%04x",
+ i2c_adapter_id(state->i2c_props.adap),
+ state->i2c_props.addr);
+
+ state->chip_id = MxL_UNKNOWN_ID;
+ return ret;
+}
+
+struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, u8 addr,
+ struct mxl5007t_config *cfg)
+{
+ struct mxl5007t_state *state = NULL;
+ int instance, ret;
+
+ mutex_lock(&mxl5007t_list_mutex);
+ instance = hybrid_tuner_request_state(struct mxl5007t_state, state,
+ hybrid_tuner_instance_list,
+ i2c, addr, "mxl5007");
+ switch (instance) {
+ case 0:
+ goto fail;
+ case 1:
+ /* new tuner instance */
+ state->config = cfg;
+
+ mutex_init(&state->lock);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = mxl5007t_get_chip_id(state);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* check return value of mxl5007t_get_chip_id */
+ if (mxl_fail(ret))
+ goto fail;
+ break;
+ default:
+ /* existing tuner instance */
+ break;
+ }
+ fe->tuner_priv = state;
+ mutex_unlock(&mxl5007t_list_mutex);
+
+ memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+fail:
+ mutex_unlock(&mxl5007t_list_mutex);
+
+ mxl5007t_release(fe);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(mxl5007t_attach);
+MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/linux/drivers/media/common/tuners/mxl5007t.h b/linux/drivers/media/common/tuners/mxl5007t.h
new file mode 100644
index 000000000..aa3eea0b5
--- /dev/null
+++ b/linux/drivers/media/common/tuners/mxl5007t.h
@@ -0,0 +1,104 @@
+/*
+ * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner
+ *
+ * Copyright (C) 2008 Michael Krufky <mkrufky@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.
+ */
+
+#ifndef __MXL5007T_H__
+#define __MXL5007T_H__
+
+#include "dvb_frontend.h"
+
+/* ------------------------------------------------------------------------- */
+
+enum mxl5007t_if_freq {
+ MxL_IF_4_MHZ, /* 4000000 */
+ MxL_IF_4_5_MHZ, /* 4500000 */
+ MxL_IF_4_57_MHZ, /* 4570000 */
+ MxL_IF_5_MHZ, /* 5000000 */
+ MxL_IF_5_38_MHZ, /* 5380000 */
+ MxL_IF_6_MHZ, /* 6000000 */
+ MxL_IF_6_28_MHZ, /* 6280000 */
+ MxL_IF_9_1915_MHZ, /* 9191500 */
+ MxL_IF_35_25_MHZ, /* 35250000 */
+ MxL_IF_36_15_MHZ, /* 36150000 */
+ MxL_IF_44_MHZ, /* 44000000 */
+};
+
+enum mxl5007t_xtal_freq {
+ MxL_XTAL_16_MHZ, /* 16000000 */
+ MxL_XTAL_20_MHZ, /* 20000000 */
+ MxL_XTAL_20_25_MHZ, /* 20250000 */
+ MxL_XTAL_20_48_MHZ, /* 20480000 */
+ MxL_XTAL_24_MHZ, /* 24000000 */
+ MxL_XTAL_25_MHZ, /* 25000000 */
+ MxL_XTAL_25_14_MHZ, /* 25140000 */
+ MxL_XTAL_27_MHZ, /* 27000000 */
+ MxL_XTAL_28_8_MHZ, /* 28800000 */
+ MxL_XTAL_32_MHZ, /* 32000000 */
+ MxL_XTAL_40_MHZ, /* 40000000 */
+ MxL_XTAL_44_MHZ, /* 44000000 */
+ MxL_XTAL_48_MHZ, /* 48000000 */
+ MxL_XTAL_49_3811_MHZ, /* 49381100 */
+};
+
+enum mxl5007t_clkout_amp {
+ MxL_CLKOUT_AMP_0_94V = 0,
+ MxL_CLKOUT_AMP_0_53V = 1,
+ MxL_CLKOUT_AMP_0_37V = 2,
+ MxL_CLKOUT_AMP_0_28V = 3,
+ MxL_CLKOUT_AMP_0_23V = 4,
+ MxL_CLKOUT_AMP_0_20V = 5,
+ MxL_CLKOUT_AMP_0_17V = 6,
+ MxL_CLKOUT_AMP_0_15V = 7,
+};
+
+struct mxl5007t_config {
+ s32 if_diff_out_level;
+ enum mxl5007t_clkout_amp clk_out_amp;
+ enum mxl5007t_xtal_freq xtal_freq_hz;
+ enum mxl5007t_if_freq if_freq_hz;
+ unsigned int invert_if:1;
+ unsigned int loop_thru_enable:1;
+ unsigned int clk_out_enable:1;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE))
+extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, u8 addr,
+ struct mxl5007t_config *cfg);
+#else
+static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ u8 addr,
+ struct mxl5007t_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* __MXL5007T_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/linux/drivers/media/common/tuners/tda18271-fe.c b/linux/drivers/media/common/tuners/tda18271-fe.c
index 68167b5ad..33bc96ea6 100644
--- a/linux/drivers/media/common/tuners/tda18271-fe.c
+++ b/linux/drivers/media/common/tuners/tda18271-fe.c
@@ -1156,7 +1156,6 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
switch (instance) {
case 0:
goto fail;
- break;
case 1:
/* new tuner instance */
priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
diff --git a/linux/drivers/media/common/tuners/tda9887.c b/linux/drivers/media/common/tuners/tda9887.c
index 61a56026d..effbf31da 100644
--- a/linux/drivers/media/common/tuners/tda9887.c
+++ b/linux/drivers/media/common/tuners/tda9887.c
@@ -6,12 +6,12 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include "compat.h"
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
#include "tuner-i2c.h"
#include "tda9887.h"
+#include "compat.h"
/* Chips:
@@ -687,7 +687,6 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
case 0:
mutex_unlock(&tda9887_list_mutex);
return NULL;
- break;
case 1:
fe->analog_demod_priv = priv;
priv->mode = T_STANDBY;
diff --git a/linux/drivers/media/common/tuners/tuner-simple.c b/linux/drivers/media/common/tuners/tuner-simple.c
index a029cf8f5..036504510 100644
--- a/linux/drivers/media/common/tuners/tuner-simple.c
+++ b/linux/drivers/media/common/tuners/tuner-simple.c
@@ -7,7 +7,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include "compat.h"
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
#include <media/tuner-types.h>
@@ -143,6 +143,7 @@ static inline int tuner_stereo(const int type, const int status)
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
case TUNER_LG_NTSC_TAPE:
+ case TUNER_TCL_MF02GIP_5N:
return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
default:
return status & TUNER_STEREO;
@@ -260,7 +261,7 @@ static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
static int simple_config_lookup(struct dvb_frontend *fe,
struct tuner_params *t_params,
- int *frequency, u8 *config, u8 *cb)
+ unsigned *frequency, u8 *config, u8 *cb)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
int i;
@@ -514,6 +515,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
case TUNER_PHILIPS_FMD1216ME_MK3:
case TUNER_LG_NTSC_TAPE:
case TUNER_PHILIPS_FM1256_IH3:
+ case TUNER_TCL_MF02GIP_5N:
buffer[3] = 0x19;
break;
case TUNER_TNF_5335MF:
@@ -607,45 +609,45 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
priv->last_div = div;
if (t_params->has_tda9887) {
struct v4l2_priv_tun_config tda9887_cfg;
- int config = 0;
+ int tda_config = 0;
int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
V4L2_STD_SECAM_LC)) &&
!(params->std & ~(V4L2_STD_SECAM_L |
V4L2_STD_SECAM_LC));
tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &config;
+ tda9887_cfg.priv = &tda_config;
if (params->std == V4L2_STD_SECAM_LC) {
if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
- config |= TDA9887_PORT1_ACTIVE;
+ tda_config |= TDA9887_PORT1_ACTIVE;
if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
- config |= TDA9887_PORT2_ACTIVE;
+ tda_config |= TDA9887_PORT2_ACTIVE;
} else {
if (t_params->port1_active)
- config |= TDA9887_PORT1_ACTIVE;
+ tda_config |= TDA9887_PORT1_ACTIVE;
if (t_params->port2_active)
- config |= TDA9887_PORT2_ACTIVE;
+ tda_config |= TDA9887_PORT2_ACTIVE;
}
if (t_params->intercarrier_mode)
- config |= TDA9887_INTERCARRIER;
+ tda_config |= TDA9887_INTERCARRIER;
if (is_secam_l) {
if (i == 0 && t_params->default_top_secam_low)
- config |= TDA9887_TOP(t_params->default_top_secam_low);
+ tda_config |= TDA9887_TOP(t_params->default_top_secam_low);
else if (i == 1 && t_params->default_top_secam_mid)
- config |= TDA9887_TOP(t_params->default_top_secam_mid);
+ tda_config |= TDA9887_TOP(t_params->default_top_secam_mid);
else if (t_params->default_top_secam_high)
- config |= TDA9887_TOP(t_params->default_top_secam_high);
+ tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
} else {
if (i == 0 && t_params->default_top_low)
- config |= TDA9887_TOP(t_params->default_top_low);
+ tda_config |= TDA9887_TOP(t_params->default_top_low);
else if (i == 1 && t_params->default_top_mid)
- config |= TDA9887_TOP(t_params->default_top_mid);
+ tda_config |= TDA9887_TOP(t_params->default_top_mid);
else if (t_params->default_top_high)
- config |= TDA9887_TOP(t_params->default_top_high);
+ tda_config |= TDA9887_TOP(t_params->default_top_high);
}
if (t_params->default_pll_gating_18)
- config |= TDA9887_GATING_18;
+ tda_config |= TDA9887_GATING_18;
i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
&tda9887_cfg);
}
@@ -833,7 +835,8 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
static struct tuner_params *t_params;
u8 config, cb;
u32 div;
- int ret, frequency = params->frequency / 62500;
+ int ret;
+ unsigned frequency = params->frequency / 62500;
t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
@@ -1065,7 +1068,6 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
case 0:
mutex_unlock(&tuner_simple_list_mutex);
return NULL;
- break;
case 1:
fe->tuner_priv = priv;
diff --git a/linux/drivers/media/common/tuners/tuner-types.c b/linux/drivers/media/common/tuners/tuner-types.c
index b3f0f62e0..861d23872 100644
--- a/linux/drivers/media/common/tuners/tuner-types.c
+++ b/linux/drivers/media/common/tuners/tuner-types.c
@@ -1217,6 +1217,23 @@ static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
},
};
+/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */
+
+static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = {
+ { 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x04, },
+};
+
+static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_NTSC,
+ .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges),
+ .cb_first_if_lower_freq = 1,
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1642,6 +1659,11 @@ struct tunertype tuners[] = {
.name = "Xceive 5000 tuner",
/* see xc5000.c for details */
},
+ [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
+ .name = "TCL tuner MF02GIP-5N-E",
+ .params = tuner_tcl_mf02gip_5n_params,
+ .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params),
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/linux/drivers/media/common/tuners/tuner-xc2028.h b/linux/drivers/media/common/tuners/tuner-xc2028.h
index 216025cf5..2c5b6282b 100644
--- a/linux/drivers/media/common/tuners/tuner-xc2028.h
+++ b/linux/drivers/media/common/tuners/tuner-xc2028.h
@@ -10,6 +10,7 @@
#include "dvb_frontend.h"
#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
+#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw"
/* Dmoduler IF (kHz) */
#define XC3028_FE_DEFAULT 0 /* Don't load SCODE */
diff --git a/linux/drivers/media/common/tuners/xc5000.c b/linux/drivers/media/common/tuners/xc5000.c
index e0f045e1b..7d4d82d23 100644
--- a/linux/drivers/media/common/tuners/xc5000.c
+++ b/linux/drivers/media/common/tuners/xc5000.c
@@ -2,7 +2,7 @@
* Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
*
* Copyright (c) 2007 Xceive Corporation
- * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2007 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
@@ -30,7 +30,7 @@
#include "dvb_frontend.h"
#include "xc5000.h"
-#include "xc5000_priv.h"
+#include "tuner-i2c.h"
static int debug;
module_param(debug, int, 0644);
@@ -40,12 +40,28 @@ static int xc5000_load_fw_on_attach;
module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
+static DEFINE_MUTEX(xc5000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
#define dprintk(level,fmt, arg...) if (debug >= level) \
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+struct xc5000_priv {
+ struct tuner_i2c_props i2c_props;
+ struct list_head hybrid_tuner_instance_list;
+
+ u32 if_khz;
+ u32 freq_hz;
+ u32 bandwidth;
+ u8 video_standard;
+ u8 rf_mode;
+
+ int (*tuner_callback) (void *priv, int command, int arg);
+};
+
/* Misc Defines */
#define MAX_TV_STANDARD 23
#define XC_MAX_I2C_WRITE_LENGTH 64
@@ -216,9 +232,11 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
dprintk(1, "%s()\n", __func__);
- if (priv->cfg->tuner_callback) {
- ret = priv->cfg->tuner_callback(priv->devptr,
- XC5000_TUNER_RESET, 0);
+ if (priv->tuner_callback) {
+ ret = priv->tuner_callback(((fe->dvb) && (fe->dvb->priv)) ?
+ fe->dvb->priv :
+ priv->i2c_props.adap->algo_data,
+ XC5000_TUNER_RESET, 0);
if (ret)
printk(KERN_ERR "xc5000: reset failed\n");
} else
@@ -528,13 +546,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
u8 buf[2] = { reg >> 8, reg & 0xff };
u8 bval[2] = { 0, 0 };
struct i2c_msg msg[2] = {
- { .addr = priv->cfg->i2c_address,
+ { .addr = priv->i2c_props.addr,
.flags = 0, .buf = &buf[0], .len = 2 },
- { .addr = priv->cfg->i2c_address,
+ { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
};
- if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
printk(KERN_WARNING "xc5000: I2C read failed\n");
return -EREMOTEIO;
}
@@ -545,10 +563,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{
- struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = 0, .buf = buf, .len = len };
- if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
(int)len);
return -EREMOTEIO;
@@ -558,10 +576,10 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{
- struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = buf, .len = len };
- if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
return -EREMOTEIO;
}
@@ -578,7 +596,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
XC5000_DEFAULT_FIRMWARE);
- ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+ ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
if (ret) {
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
ret = XC_RESULT_RESET_FAILURE;
@@ -694,10 +712,10 @@ static int xc5000_set_params(struct dvb_frontend *fe,
return -EREMOTEIO;
}
- ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+ ret = xc_set_IF_frequency(priv, priv->if_khz);
if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
- priv->cfg->if_khz);
+ priv->if_khz);
return -EIO;
}
@@ -916,9 +934,19 @@ static int xc5000_init(struct dvb_frontend *fe)
static int xc5000_release(struct dvb_frontend *fe)
{
+ struct xc5000_priv *priv = fe->tuner_priv;
+
dprintk(1, "%s()\n", __func__);
- kfree(fe->tuner_priv);
+
+ mutex_lock(&xc5000_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&xc5000_list_mutex);
+
fe->tuner_priv = NULL;
+
return 0;
}
@@ -943,29 +971,44 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg, void *devptr)
+ struct xc5000_config *cfg)
{
struct xc5000_priv *priv = NULL;
+ int instance;
u16 id = 0;
- dprintk(1, "%s()\n", __func__);
+ dprintk(1, "%s(%d-%04x)\n", __func__,
+ i2c ? i2c_adapter_id(i2c) : -1,
+ cfg ? cfg->i2c_address : -1);
+
+ mutex_lock(&xc5000_list_mutex);
- priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
+ instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c, cfg->i2c_address, "xc5000");
+ switch (instance) {
+ case 0:
+ goto fail;
+ break;
+ case 1:
+ /* new tuner instance */
+ priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->if_khz = cfg->if_khz;
+ priv->tuner_callback = cfg->tuner_callback;
- priv->cfg = cfg;
- priv->bandwidth = BANDWIDTH_6_MHZ;
- priv->i2c = i2c;
- priv->devptr = devptr;
+ fe->tuner_priv = priv;
+ break;
+ default:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
*/
- if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
- kfree(priv);
- return NULL;
- }
+ if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+ goto fail;
switch(id) {
case XC_PRODUCT_ID_FW_LOADED:
@@ -986,19 +1029,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
printk(KERN_ERR
"xc5000: Device not found at addr 0x%02x (0x%x)\n",
cfg->i2c_address, id);
- kfree(priv);
- return NULL;
+ goto fail;
}
+ mutex_unlock(&xc5000_list_mutex);
+
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
sizeof(struct dvb_tuner_ops));
- fe->tuner_priv = priv;
-
if (xc5000_load_fw_on_attach)
xc5000_init(fe);
return fe;
+fail:
+ mutex_unlock(&xc5000_list_mutex);
+
+ xc5000_release(fe);
+ return NULL;
}
EXPORT_SYMBOL(xc5000_attach);
diff --git a/linux/drivers/media/common/tuners/xc5000.h b/linux/drivers/media/common/tuners/xc5000.h
index c910715ad..fa0321cfd 100644
--- a/linux/drivers/media/common/tuners/xc5000.h
+++ b/linux/drivers/media/common/tuners/xc5000.h
@@ -1,7 +1,7 @@
/*
* Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2007 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
@@ -49,13 +49,11 @@ struct xc5000_config {
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg,
- void *devptr);
+ struct xc5000_config *cfg);
#else
static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg,
- void *devptr)
+ struct xc5000_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/linux/drivers/media/common/tuners/xc5000_priv.h b/linux/drivers/media/common/tuners/xc5000_priv.h
deleted file mode 100644
index a72a9887f..000000000
--- a/linux/drivers/media/common/tuners/xc5000_priv.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
- *
- * Copyright (c) 2007 Steven Toth <stoth@hauppauge.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 XC5000_PRIV_H
-#define XC5000_PRIV_H
-
-struct xc5000_priv {
- struct xc5000_config *cfg;
- struct i2c_adapter *i2c;
-
- u32 freq_hz;
- u32 bandwidth;
- u8 video_standard;
- u8 rf_mode;
-
- void *devptr;
-};
-
-#endif