summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux/Documentation/dvb/get_dvb_firmware6
-rw-r--r--linux/drivers/media/common/saa7146_core.c172
-rw-r--r--linux/drivers/media/dvb/Kconfig6
-rw-r--r--linux/drivers/media/dvb/b2c2/Kconfig2
-rw-r--r--linux/drivers/media/dvb/b2c2/Makefile2
-rw-r--r--linux/drivers/media/dvb/b2c2/skystar2.c292
-rw-r--r--linux/drivers/media/dvb/bt8xx/Kconfig2
-rw-r--r--linux/drivers/media/dvb/bt8xx/Makefile2
-rw-r--r--linux/drivers/media/dvb/bt8xx/bt878.c2
-rw-r--r--linux/drivers/media/dvb/bt8xx/dst.c1103
-rw-r--r--linux/drivers/media/dvb/bt8xx/dst.h40
-rw-r--r--linux/drivers/media/dvb/bt8xx/dst_priv.h (renamed from linux/drivers/media/dvb/frontends/dst-bt878.h)0
-rw-r--r--linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c269
-rw-r--r--linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h6
-rw-r--r--linux/drivers/media/dvb/cinergyT2/cinergyT2.c92
-rw-r--r--linux/drivers/media/dvb/dibusb/Kconfig1
-rw-r--r--linux/drivers/media/dvb/dibusb/Makefile2
-rw-r--r--linux/drivers/media/dvb/dibusb/dvb-dibusb.c69
-rw-r--r--linux/drivers/media/dvb/dibusb/dvb-dibusb.h1
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c523
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.h122
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_ksyms.c4
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvbdev.h1
-rw-r--r--linux/drivers/media/dvb/frontends/Kconfig126
-rw-r--r--linux/drivers/media/dvb/frontends/Makefile13
-rw-r--r--linux/drivers/media/dvb/frontends/alps_tdlb7.c746
-rw-r--r--linux/drivers/media/dvb/frontends/alps_tdmb7.c532
-rw-r--r--linux/drivers/media/dvb/frontends/at76c651.c496
-rw-r--r--linux/drivers/media/dvb/frontends/at76c651.h47
-rw-r--r--linux/drivers/media/dvb/frontends/cx22700.c445
-rw-r--r--linux/drivers/media/dvb/frontends/cx22700.h41
-rw-r--r--linux/drivers/media/dvb/frontends/cx22702.c844
-rw-r--r--linux/drivers/media/dvb/frontends/cx22702.h46
-rw-r--r--linux/drivers/media/dvb/frontends/cx24110.c757
-rw-r--r--linux/drivers/media/dvb/frontends/cx24110.h45
-rw-r--r--linux/drivers/media/dvb/frontends/dib3000mb.c1093
-rw-r--r--linux/drivers/media/dvb/frontends/dib3000mb.h671
-rw-r--r--linux/drivers/media/dvb/frontends/dib3000mb_priv.h656
-rw-r--r--linux/drivers/media/dvb/frontends/dst.c1256
-rw-r--r--linux/drivers/media/dvb/frontends/dvb_dummy_fe.c413
-rw-r--r--linux/drivers/media/dvb/frontends/dvb_dummy_fe.h32
-rw-r--r--linux/drivers/media/dvb/frontends/grundig_29504-401.c749
-rw-r--r--linux/drivers/media/dvb/frontends/grundig_29504-491.c555
-rw-r--r--linux/drivers/media/dvb/frontends/l64781.c623
-rw-r--r--linux/drivers/media/dvb/frontends/l64781.h43
-rw-r--r--linux/drivers/media/dvb/frontends/mt312.c735
-rw-r--r--linux/drivers/media/dvb/frontends/mt312.h158
-rw-r--r--linux/drivers/media/dvb/frontends/mt312_priv.h162
-rw-r--r--linux/drivers/media/dvb/frontends/mt352.c847
-rw-r--r--linux/drivers/media/dvb/frontends/mt352.h152
-rw-r--r--linux/drivers/media/dvb/frontends/mt352_priv.h127
-rw-r--r--linux/drivers/media/dvb/frontends/nxt6000.c642
-rw-r--r--linux/drivers/media/dvb/frontends/nxt6000.h284
-rw-r--r--linux/drivers/media/dvb/frontends/nxt6000_priv.h265
-rw-r--r--linux/drivers/media/dvb/frontends/sp8870.c613
-rw-r--r--linux/drivers/media/dvb/frontends/sp8870.h45
-rw-r--r--linux/drivers/media/dvb/frontends/sp887x.c605
-rw-r--r--linux/drivers/media/dvb/frontends/sp887x.h29
-rw-r--r--linux/drivers/media/dvb/frontends/stv0297.c479
-rw-r--r--linux/drivers/media/dvb/frontends/stv0297.h40
-rw-r--r--linux/drivers/media/dvb/frontends/stv0299.c1522
-rw-r--r--linux/drivers/media/dvb/frontends/stv0299.h104
-rw-r--r--linux/drivers/media/dvb/frontends/tda10021.c483
-rw-r--r--linux/drivers/media/dvb/frontends/tda10021.h43
-rw-r--r--linux/drivers/media/dvb/frontends/tda1004x.c1188
-rw-r--r--linux/drivers/media/dvb/frontends/tda1004x.h53
-rw-r--r--linux/drivers/media/dvb/frontends/tda8083.c490
-rw-r--r--linux/drivers/media/dvb/frontends/tda8083.h45
-rw-r--r--linux/drivers/media/dvb/frontends/tda80xx.c749
-rw-r--r--linux/drivers/media/dvb/frontends/tda80xx.h51
-rw-r--r--linux/drivers/media/dvb/frontends/ves1820.c670
-rw-r--r--linux/drivers/media/dvb/frontends/ves1820.h52
-rw-r--r--linux/drivers/media/dvb/frontends/ves1x93.c735
-rw-r--r--linux/drivers/media/dvb/frontends/ves1x93.h50
-rw-r--r--linux/drivers/media/dvb/ttpci/Kconfig17
-rw-r--r--linux/drivers/media/dvb/ttpci/Makefile2
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.c618
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.h19
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-av.c344
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-ci.c384
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-core.c29
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-patch.c286
-rw-r--r--linux/drivers/media/dvb/ttpci/budget.c412
-rw-r--r--linux/drivers/media/dvb/ttpci/budget.h5
-rw-r--r--linux/drivers/media/dvb/ttusb-budget/Kconfig2
-rw-r--r--linux/drivers/media/dvb/ttusb-budget/Makefile2
-rw-r--r--linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c228
-rw-r--r--linux/drivers/media/dvb/ttusb-dec/Makefile2
-rw-r--r--linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c337
-rw-r--r--linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c258
-rw-r--r--linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h38
-rw-r--r--linux/include/linux/dvb/frontend.h2
92 files changed, 14136 insertions, 13215 deletions
diff --git a/linux/Documentation/dvb/get_dvb_firmware b/linux/Documentation/dvb/get_dvb_firmware
index 82bc4e58c..e1082e33f 100644
--- a/linux/Documentation/dvb/get_dvb_firmware
+++ b/linux/Documentation/dvb/get_dvb_firmware
@@ -21,7 +21,7 @@
use File::Temp qw/ tempdir /;
use IO::Handle;
-@components = ( "alps_tdlb7", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb" );
+@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb" );
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -47,11 +47,11 @@ syntax();
# ---------------------------------------------------------------
# Firmware-specific extraction subroutines
-sub alps_tdlb7 {
+sub sp8870 {
my $sourcefile = "tt_Premium_217g.zip";
my $url = "http://www.technotrend.de/new/217g/$sourcefile";
my $hash = "53970ec17a538945a6d8cb608a7b3899";
- my $outfile = "dvb-fe-tdlb7.fw";
+ my $outfile = "dvb-fe-sp8870.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
checkstandard();
diff --git a/linux/drivers/media/common/saa7146_core.c b/linux/drivers/media/common/saa7146_core.c
index 7c076b2ef..2c8e70a66 100644
--- a/linux/drivers/media/common/saa7146_core.c
+++ b/linux/drivers/media/common/saa7146_core.c
@@ -48,7 +48,7 @@ static void dump_registers(struct saa7146_dev* dev)
* gpio and debi helper functions
****************************************************************************/
-/* write "data" to the gpio-pin "pin" */
+/* write "data" to the gpio-pin "pin" -- unused */
void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data)
{
u32 value = 0;
@@ -250,7 +250,7 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
/* interrupt handler */
static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
{
- struct saa7146_dev *dev = (struct saa7146_dev*)dev_id;
+ struct saa7146_dev *dev = dev_id;
u32 isr = 0;
/* read out the interrupt status register */
@@ -317,16 +317,15 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent)
{
- unsigned long adr = 0, len = 0;
- struct saa7146_dev* dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL);
-
struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;
- struct saa7146_extension* ext = pci_ext->ext;
- int err = 0;
+ struct saa7146_extension *ext = pci_ext->ext;
+ struct saa7146_dev *dev;
+ int err = -ENOMEM;
- if (!(dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL))) {
+ dev = kmalloc(sizeof(struct saa7146_dev), GFP_KERNEL);
+ if (!dev) {
ERR(("out of memory.\n"));
- return -ENOMEM;
+ goto out;
}
/* clear out mem for sure */
@@ -334,38 +333,37 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
DEB_EE(("pci:%p\n",pci));
- if (pci_enable_device(pci)) {
+ err = pci_enable_device(pci);
+ if (err < 0) {
ERR(("pci_enable_device() failed.\n"));
- err = -EIO;
- goto pci_error;
+ goto err_free;
}
/* enable bus-mastering */
pci_set_master(pci);
dev->pci = pci;
+
/* get chip-revision; this is needed to enable bug-fixes */
- if( 0 > pci_read_config_dword(dev->pci, PCI_CLASS_REVISION, &dev->revision)) {
+ err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision);
+ if (err < 0) {
ERR(("pci_read_config_dword() failed.\n"));
- err = -ENODEV;
- goto pci_error;
+ goto err_disable;
}
dev->revision &= 0xf;
/* remap the memory from virtual to physical adress */
- adr = pci_resource_start(pci,0);
- len = pci_resource_len(pci,0);
- if (!request_mem_region(pci_resource_start(pci,0), pci_resource_len(pci,0), "saa7146")) {
- ERR(("request_mem_region() failed.\n"));
- err = -ENODEV;
- goto pci_error;
- }
+ err = pci_request_region(pci, 0, "saa7146");
+ if (err < 0)
+ goto err_disable;
- if (!(dev->mem = ioremap(adr,len))) {
+ dev->mem = ioremap(pci_resource_start(pci, 0),
+ pci_resource_len(pci, 0));
+ if (!dev->mem) {
ERR(("ioremap() failed.\n"));
err = -ENODEV;
- goto ioremap_error;
+ goto err_release;
}
/* we don't do a master reset here anymore, it screws up
@@ -385,45 +383,43 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
saa7146_write(dev, MC2, 0xf8000000);
/* request an interrupt for the saa7146 */
- if (request_irq(dev->pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT,
- dev->name, dev))
- {
+ err = request_irq(pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT,
+ dev->name, dev);
+ if (err < 0) {
ERR(("request_irq() failed.\n"));
- err = -ENODEV;
- goto irq_error;
+ goto err_unmap;
}
+ err = -ENOMEM;
+
/* get memory for various stuff */
- dev->d_rps0.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_rps0.dma_handle);
- if( NULL == dev->d_rps0.cpu_addr ) {
- err = -ENOMEM;
- goto kmalloc_error_1;
- }
+ dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+ &dev->d_rps0.dma_handle);
+ if (!dev->d_rps0.cpu_addr)
+ goto err_free_irq;
memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);
- dev->d_rps1.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_rps1.dma_handle);
- if( NULL == dev->d_rps1.cpu_addr ) {
- err = -ENOMEM;
- goto kmalloc_error_2;
- }
+ dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+ &dev->d_rps1.dma_handle);
+ if (!dev->d_rps1.cpu_addr)
+ goto err_free_rps0;
memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);
- dev->d_i2c.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_i2c.dma_handle);
- if( NULL == dev->d_i2c.cpu_addr ) {
- err = -ENOMEM;
- goto kmalloc_error_3;
- }
+ dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,
+ &dev->d_i2c.dma_handle);
+ if (!dev->d_i2c.cpu_addr)
+ goto err_free_rps1;
memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);
/* the rest + print status message */
/* create a nice device name */
- sprintf(&dev->name[0], "saa7146 (%d)",saa7146_num);
+ sprintf(dev->name, "saa7146 (%d)", saa7146_num);
- INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision,dev->pci->irq,dev->pci->subsystem_vendor,dev->pci->subsystem_device));
+ INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
dev->ext = ext;
- pci_set_drvdata(pci,dev);
+ pci_set_drvdata(pci, dev);
init_MUTEX(&dev->lock);
dev->int_slock = SPIN_LOCK_UNLOCKED;
@@ -437,18 +433,18 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
/* set some sane pci arbitrition values */
saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
- if( 0 != ext->probe) {
- if( 0 != ext->probe(dev) ) {
- DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));
- err = -ENODEV;
- goto probe_error;
- }
+ /* TODO: use the status code of the callback */
+
+ err = -ENODEV;
+
+ if (ext->probe && ext->probe(dev)) {
+ DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));
+ goto err_free_i2c;
}
- if( 0 != ext->attach(dev,pci_ext) ) {
+ if (ext->attach(dev, pci_ext)) {
DEB_D(("ext->attach() failed for %p. skipping device.\n",dev));
- err = -ENODEV;
- goto attach_error;
+ goto err_unprobe;
}
INIT_LIST_HEAD(&dev->item);
@@ -456,30 +452,46 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
saa7146_num++;
err = 0;
- goto out;
-attach_error:
-probe_error:
- pci_set_drvdata(pci,NULL);
- pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle);
-kmalloc_error_3:
- pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle);
-kmalloc_error_2:
- pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle);
-kmalloc_error_1:
- free_irq(dev->pci->irq, (void *)dev);
-irq_error:
- iounmap(dev->mem);
-ioremap_error:
- release_mem_region(adr,len);
-pci_error:
- kfree(dev);
out:
return err;
+
+err_unprobe:
+ pci_set_drvdata(pci, NULL);
+err_free_i2c:
+ pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,
+ dev->d_i2c.dma_handle);
+err_free_rps1:
+ pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,
+ dev->d_rps1.dma_handle);
+err_free_rps0:
+ pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,
+ dev->d_rps0.dma_handle);
+err_free_irq:
+ free_irq(pci->irq, (void *)dev);
+err_unmap:
+ iounmap(dev->mem);
+err_release:
+ pci_release_region(pci, 0);
+err_disable:
+ pci_disable_device(pci);
+err_free:
+ kfree(dev);
+ goto out;
}
static void saa7146_remove_one(struct pci_dev *pdev)
{
- struct saa7146_dev* dev = (struct saa7146_dev*) pci_get_drvdata(pdev);
+ struct saa7146_dev* dev = pci_get_drvdata(pdev);
+ struct {
+ void *addr;
+ dma_addr_t dma;
+ } dev_map[] = {
+ { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },
+ { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },
+ { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },
+ { NULL, 0 }
+ }, *p;
+
DEB_EE(("dev:%p\n",dev));
dev->ext->detach(dev);
@@ -490,17 +502,15 @@ static void saa7146_remove_one(struct pci_dev *pdev)
/* disable all irqs, release irq-routine */
saa7146_write(dev, IER, 0);
- free_irq(dev->pci->irq, (void *)dev);
+ free_irq(pdev->irq, dev);
- /* free kernel memory */
- pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle);
- pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle);
- pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle);
+ for (p = dev_map; p->addr; p++)
+ pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);
iounmap(dev->mem);
- release_mem_region(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0));
-
+ pci_release_region(pdev, 0);
list_del(&dev->item);
+ pci_disable_device(pdev);
kfree(dev);
saa7146_num--;
diff --git a/linux/drivers/media/dvb/Kconfig b/linux/drivers/media/dvb/Kconfig
index c011192fb..883ec0849 100644
--- a/linux/drivers/media/dvb/Kconfig
+++ b/linux/drivers/media/dvb/Kconfig
@@ -21,8 +21,6 @@ config DVB
source "drivers/media/dvb/dvb-core/Kconfig"
-source "drivers/media/dvb/frontends/Kconfig"
-
comment "Supported SAA7146 based PCI Adapters"
depends on DVB_CORE && PCI
source "drivers/media/dvb/ttpci/Kconfig"
@@ -42,4 +40,8 @@ comment "Supported BT878 Adapters"
depends on DVB_CORE && PCI
source "drivers/media/dvb/bt8xx/Kconfig"
+comment "Supported DVB Frontends"
+ depends on DVB_CORE
+source "drivers/media/dvb/frontends/Kconfig"
+
endmenu
diff --git a/linux/drivers/media/dvb/b2c2/Kconfig b/linux/drivers/media/dvb/b2c2/Kconfig
index b3a45b4fc..1c90520bf 100644
--- a/linux/drivers/media/dvb/b2c2/Kconfig
+++ b/linux/drivers/media/dvb/b2c2/Kconfig
@@ -1,6 +1,8 @@
config DVB_B2C2_SKYSTAR
tristate "Technisat Skystar2 PCI"
depends on DVB_CORE && PCI
+ select DVB_STV0299
+ select DVB_MT352
help
Support for the Skystar2 PCI DVB card by Technisat, which
is equipped with the FlexCopII chipset by B2C2.
diff --git a/linux/drivers/media/dvb/b2c2/Makefile b/linux/drivers/media/dvb/b2c2/Makefile
index df86d99af..f9cdc6f05 100644
--- a/linux/drivers/media/dvb/b2c2/Makefile
+++ b/linux/drivers/media/dvb/b2c2/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/linux/drivers/media/dvb/b2c2/skystar2.c b/linux/drivers/media/dvb/b2c2/skystar2.c
index 3c39ccbf7..9e7d270ea 100644
--- a/linux/drivers/media/dvb/b2c2/skystar2.c
+++ b/linux/drivers/media/dvb/b2c2/skystar2.c
@@ -50,6 +50,8 @@
#include "dvbdev.h"
#include "demux.h"
#include "dvb_net.h"
+#include "stv0299.h"
+#include "mt352.h"
static int debug;
@@ -118,10 +120,13 @@ struct adapter {
int pid_count;
int whole_bandwidth_count;
u32 mac_filter;
+
+ struct dvb_frontend* fe;
+ int (*fe_sleep)(struct dvb_frontend* fe);
};
-#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg)
-#define read_reg_dw(adapter,reg) readl(adapter->io_mem + reg)
+#define write_reg_dw(adapter,reg,value) writel(value, (void*) (adapter->io_mem + reg))
+#define read_reg_dw(adapter,reg) readl((void*) (adapter->io_mem + reg))
static void write_reg_bitfield(struct adapter *adapter, u32 reg, u32 zeromask, u32 orvalue)
{
@@ -297,13 +302,6 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msgs[], int n
for (i = 0; i < num; i++) {
ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
-
- /* allow only the mt312, mt352 and stv0299 frontends to access the bus */
- if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) &&
- (msgs[i].addr != 0x61) && (msgs[i].addr != 0x0f)) {
- up(&tmp->i2c_sem);
- return -EREMOTEIO;
- }
}
// read command
@@ -1594,7 +1592,7 @@ static void interrupt_service_dma1(struct adapter *adapter)
u8 gb_tmp_buffer[188];
u8 *pb_dma_buf_cur_pos;
- n_cur_dma_counter = readl(adapter->io_mem + 0x008) - adapter->dmaq1.bus_addr;
+ n_cur_dma_counter = readl((void*) (adapter->io_mem + 0x008)) - adapter->dmaq1.bus_addr;
n_cur_dma_counter = (n_cur_dma_counter / dw_default_packet_size) * dw_default_packet_size;
if ((n_cur_dma_counter < 0) || (n_cur_dma_counter > adapter->dmaq1.buffer_size)) {
@@ -2170,107 +2168,250 @@ int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg)
return 0;
}
-static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
- struct adapter *adapter = fe->before_after_data;
+ struct adapter* adapter = (struct adapter*) fe->dvb->priv;
- struct dvb_frontend_info info;
+ dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
- fe->ioctl(fe, FE_GET_INFO, &info);
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
+ set_tuner_polarity(adapter, 1);
+ return 0;
- // we must use different DiSEqC hw
+ case SEC_VOLTAGE_18:
+ dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
+ set_tuner_polarity(adapter, 2);
+ return 0;
- if (strcmp(info.name, "Zarlink MT312") == 0) {
- //VP310 using mt312 driver for tuning only: diseqc not wired
- //use FCII instead
- if (!soft_diseqc(adapter, cmd, arg))
- return 0;
+ default:
+ return -EINVAL;
}
+}
- switch (cmd) {
- case FE_SLEEP:
- {
- dprintk("%s: FE_SLEEP\n", __FUNCTION__);
-
- set_tuner_polarity(adapter, 0);
+static int flexcop_sleep(struct dvb_frontend* fe)
+{
+ struct adapter* adapter = (struct adapter*) fe->dvb->priv;
- // return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend.
- return -EOPNOTSUPP;
- }
+ dprintk("%s: FE_SLEEP\n", __FUNCTION__);
+ set_tuner_polarity(adapter, 0);
- case FE_SET_VOLTAGE:
- {
- dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
+ if (adapter->fe_sleep) return adapter->fe_sleep(fe);
+ return 0;
+}
- switch ((fe_sec_voltage_t) arg) {
- case SEC_VOLTAGE_13:
+u32 flexcop_i2c_func(struct i2c_adapter *adapter)
+{
+ printk("flexcop_i2c_func\n");
- dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
+ return I2C_FUNC_I2C;
+}
- set_tuner_polarity(adapter, 1);
+static struct i2c_algorithm flexcop_algo = {
+ .name = "flexcop i2c algorithm",
+ .id = I2C_ALGO_BIT,
+ .master_xfer = master_xfer,
+ .functionality = flexcop_i2c_func,
+};
- return 0;
- case SEC_VOLTAGE_18:
- dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
- set_tuner_polarity(adapter, 2);
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
- return 0;
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
- default:
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
- return -EINVAL;
- };
- }
+ return 0;
+}
+static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ u8 buf[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct adapter* adapter = (struct adapter*) fe->dvb->priv;
- default:
+ div = params->frequency / 125;
- return -EOPNOTSUPP;
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x84; // 0xC4
+ buf[3] = 0x08;
- };
+ if (params->frequency < 1500000) buf[3] |= 0x10;
+ if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
+static u8 samsung_tbmu24112_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7D,
+ 0x05, 0x35,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0xC3,
+ 0x0C, 0x00,
+ 0x0D, 0x81,
+ 0x0E, 0x23,
+ 0x0F, 0x12,
+ 0x10, 0x7E,
+ 0x11, 0x84,
+ 0x12, 0xB9,
+ 0x13, 0x88,
+ 0x14, 0x89,
+ 0x15, 0xC9,
+ 0x16, 0x00,
+ 0x17, 0x5C,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1A, 0x00,
+ 0x1C, 0x00,
+ 0x1D, 0x00,
+ 0x1E, 0x00,
+ 0x1F, 0x3A,
+ 0x20, 0x2E,
+ 0x21, 0x80,
+ 0x22, 0xFF,
+ 0x23, 0xC1,
+ 0x28, 0x00,
+ 0x29, 0x1E,
+ 0x2A, 0x14,
+ 0x2B, 0x0F,
+ 0x2C, 0x09,
+ 0x2D, 0x05,
+ 0x31, 0x1F,
+ 0x32, 0x19,
+ 0x33, 0xFE,
+ 0x34, 0x93,
+ 0xff, 0xff,
+};
+
+static struct stv0299_config samsung_tbmu24112_config = {
+ .demod_address = 0x68,
+ .inittab = samsung_tbmu24112_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_LK,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
+ .pll_set = samsung_tbmu24112_pll_set,
+};
+
+
-static int client_register(struct i2c_client *client)
+
+
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
{
- struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter);
+ static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d };
+ static u8 mt352_reset [] = { 0x50, 0x80 };
+ static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+ static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
+ static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+ mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+ udelay(2000);
+ mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+ mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
- dprintk("client_register\n");
+ mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+ mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
- if (client->driver->command)
- return client->driver->command(client, FE_REGISTER, adapter->dvb_adapter);
return 0;
}
-static int client_unregister(struct i2c_client *client)
+int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
{
- struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter);
+ u32 div;
+ unsigned char bs = 0;
+
+ #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
+ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+ if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
+ if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
+ if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
- dprintk("client_unregister\n");
+ pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+ pllbuf[1] = div >> 8;
+ pllbuf[2] = div & 0xff;
+ pllbuf[3] = 0xcc;
+ pllbuf[4] = bs;
- if (client->driver->command)
- return client->driver->command(client, FE_UNREGISTER, adapter->dvb_adapter);
return 0;
}
-u32 flexcop_i2c_func(struct i2c_adapter *adapter)
+static struct mt352_config samsung_tdtc9251dh0_config = {
+
+ .demod_address = 0x0f,
+ .demod_init = samsung_tdtc9251dh0_demod_init,
+ .pll_set = samsung_tdtc9251dh0_pll_set,
+};
+
+
+
+
+
+static void frontend_init(struct adapter *skystar2)
{
- printk("flexcop_i2c_func\n");
+ switch(skystar2->pdev->device) {
+ case 0x2103: // Technisat Skystar2 OR Technisat Airstar2
- return I2C_FUNC_I2C;
-}
+ // try the skystar2 first (stv0299/Samsung tbmu24112(sl1935))
+ skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap);
+ if (skystar2->fe != NULL) {
+ skystar2->fe->ops->set_voltage = flexcop_set_voltage;
+ skystar2->fe_sleep = skystar2->fe->ops->sleep;
+ skystar2->fe->ops->sleep = flexcop_sleep;
+ break;
+ }
-static struct i2c_algorithm flexcop_algo = {
- .name = "flexcop i2c algorithm",
- .id = I2C_ALGO_BIT,
- .master_xfer = master_xfer,
- .functionality = flexcop_i2c_func,
-};
+ // try the airstar2 (mt352/Samsung tdtc9251dh0(??))
+ skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap);
+ if (skystar2->fe != NULL) {
+ skystar2->fe->ops->info.frequency_min = 474000000;
+ skystar2->fe->ops->info.frequency_max = 858000000;
+ break;
+ }
+ break;
+ }
+
+ if (skystar2->fe == NULL) {
+ printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ skystar2->pdev->vendor,
+ skystar2->pdev->device,
+ skystar2->pdev->subsystem_vendor,
+ skystar2->pdev->subsystem_device);
+ } else {
+ if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) {
+ printk("skystar2: Frontend registration failed!\n");
+ if (skystar2->fe->ops->release)
+ skystar2->fe->ops->release(skystar2->fe);
+ skystar2->fe = NULL;
+ }
+ }
+}
static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -2299,8 +2440,10 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter = (struct adapter *) pci_get_drvdata(pdev);
+ dvb_adapter->priv = adapter;
adapter->dvb_adapter = dvb_adapter;
+
init_MUTEX(&adapter->i2c_sem);
@@ -2317,16 +2460,12 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->i2c_adap.algo = &flexcop_algo;
adapter->i2c_adap.algo_data = NULL;
adapter->i2c_adap.id = I2C_ALGO_BIT;
- adapter->i2c_adap.client_register = client_register;
- adapter->i2c_adap.client_unregister = client_unregister;
if (i2c_add_adapter(&adapter->i2c_adap) < 0) {
dvb_unregister_adapter (adapter->dvb_adapter);
return -ENOMEM;
}
- dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter);
-
dvbdemux = &adapter->demux;
dvbdemux->priv = (void *) adapter;
@@ -2362,6 +2501,9 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return ret;
dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
+
+ frontend_init(adapter);
+
return 0;
}
@@ -2386,9 +2528,9 @@ static void skystar2_remove(struct pci_dev *pdev)
dvb_dmxdev_release(&adapter->dmxdev);
dvb_dmx_release(&adapter->demux);
- if (adapter->dvb_adapter != NULL) {
- dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL);
+ if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe);
+ if (adapter->dvb_adapter != NULL) {
i2c_del_adapter(&adapter->i2c_adap);
dvb_unregister_adapter(adapter->dvb_adapter);
@@ -2399,7 +2541,7 @@ static void skystar2_remove(struct pci_dev *pdev)
static struct pci_device_id skystar2_pci_tbl[] = {
{0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},
- {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, //FCIII
+/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII
{0,},
};
diff --git a/linux/drivers/media/dvb/bt8xx/Kconfig b/linux/drivers/media/dvb/bt8xx/Kconfig
index 30ff34f86..abcb5b905 100644
--- a/linux/drivers/media/dvb/bt8xx/Kconfig
+++ b/linux/drivers/media/dvb/bt8xx/Kconfig
@@ -1,6 +1,8 @@
config DVB_BT8XX
tristate "Nebula/Pinnacle PCTV/Twinhan PCI cards"
depends on DVB_CORE && PCI && VIDEO_BT848
+ select DVB_MT352
+ select DVB_SP887X
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards.
diff --git a/linux/drivers/media/dvb/bt8xx/Makefile b/linux/drivers/media/dvb/bt8xx/Makefile
index 6db28906a..9da8604b9 100644
--- a/linux/drivers/media/dvb/bt8xx/Makefile
+++ b/linux/drivers/media/dvb/bt8xx/Makefile
@@ -1,5 +1,5 @@
-obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o
+obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/dvb/bt8xx/bt878.c b/linux/drivers/media/dvb/bt8xx/bt878.c
index 3dc3f94bf..0973588d4 100644
--- a/linux/drivers/media/dvb/bt8xx/bt878.c
+++ b/linux/drivers/media/dvb/bt8xx/bt878.c
@@ -44,7 +44,7 @@
#include "dmxdev.h"
#include "dvbdev.h"
#include "bt878.h"
-#include "dst-bt878.h"
+#include "dst_priv.h"
/**************************************/
diff --git a/linux/drivers/media/dvb/bt8xx/dst.c b/linux/drivers/media/dvb/bt8xx/dst.c
new file mode 100644
index 000000000..49c46d7f8
--- /dev/null
+++ b/linux/drivers/media/dvb/bt8xx/dst.c
@@ -0,0 +1,1103 @@
+/*
+ Frontend-driver for TwinHan DST Frontend
+
+ Copyright (C) 2003 Jamie Honan
+
+ 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "dst_priv.h"
+#include "dst.h"
+
+
+struct dst_state {
+
+ struct i2c_adapter* i2c;
+
+ struct bt878* bt;
+
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct dst_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* private demodulator data */
+ u8 tx_tuna[10];
+ u8 rx_tuna[10];
+ u8 rxbuffer[10];
+ u8 diseq_flags;
+ u8 dst_type;
+ u32 type_flags;
+ u32 frequency; /* intermediate frequency in kHz for QPSK */
+ fe_spectral_inversion_t inversion;
+ u32 symbol_rate; /* symbol rate in Symbols per second */
+ fe_code_rate_t fec;
+ fe_sec_voltage_t voltage;
+ fe_sec_tone_mode_t tone;
+ u32 decode_freq;
+ u8 decode_lock;
+ u16 decode_strength;
+ u16 decode_snr;
+ unsigned long cur_jiff;
+ u8 k22;
+ fe_bandwidth_t bandwidth;
+};
+
+
+
+unsigned int dst_verbose = 0;
+MODULE_PARM(dst_verbose, "i");
+MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
+unsigned int dst_debug = 0;
+MODULE_PARM(dst_debug, "i");
+MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
+
+#define dprintk if (dst_debug) printk
+
+#define DST_TYPE_IS_SAT 0
+#define DST_TYPE_IS_TERR 1
+#define DST_TYPE_IS_CABLE 2
+
+#define DST_TYPE_HAS_NEWTUNE 1
+#define DST_TYPE_HAS_TS204 2
+#define DST_TYPE_HAS_SYMDIV 4
+
+#define HAS_LOCK 1
+#define ATTEMPT_TUNE 2
+#define HAS_POWER 4
+
+static void dst_packsize(struct dst_state* state, int psize)
+{
+ union dst_gpio_packet bits;
+
+ bits.psize = psize;
+ bt878_device_control(state->bt, DST_IG_TS, &bits);
+}
+
+static int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh)
+{
+ union dst_gpio_packet enb;
+ union dst_gpio_packet bits;
+ int err;
+
+ enb.enb.mask = mask;
+ enb.enb.enable = enbb;
+ if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) {
+ dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb);
+ return -EREMOTEIO;
+ }
+
+ /* because complete disabling means no output, no need to do output packet */
+ if (enbb == 0)
+ return 0;
+
+ bits.outp.mask = enbb;
+ bits.outp.highvals = outhigh;
+
+ if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) {
+ dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int dst_gpio_inb(struct dst_state *state, u8 * result)
+{
+ union dst_gpio_packet rd_packet;
+ int err;
+
+ *result = 0;
+
+ if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
+ dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err);
+ return -EREMOTEIO;
+ }
+ *result = (u8) rd_packet.rd.value;
+ return 0;
+}
+
+#define DST_I2C_ENABLE 1
+#define DST_8820 2
+
+static int dst_reset8820(struct dst_state *state)
+{
+ int retval;
+ /* pull 8820 gpio pin low, wait, high, wait, then low */
+ // dprintk ("%s: reset 8820\n", __FUNCTION__);
+ retval = dst_gpio_outb(state, DST_8820, DST_8820, 0);
+ if (retval < 0)
+ return retval;
+ msleep(10);
+ retval = dst_gpio_outb(state, DST_8820, DST_8820, DST_8820);
+ if (retval < 0)
+ return retval;
+ /* wait for more feedback on what works here *
+ msleep(10);
+ retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
+ if (retval < 0)
+ return retval;
+ */
+ return 0;
+}
+
+static int dst_i2c_enable(struct dst_state *state)
+{
+ int retval;
+ /* pull I2C enable gpio pin low, wait */
+ // dprintk ("%s: i2c enable\n", __FUNCTION__);
+ retval = dst_gpio_outb(state, ~0, DST_I2C_ENABLE, 0);
+ if (retval < 0)
+ return retval;
+ // dprintk ("%s: i2c enable delay\n", __FUNCTION__);
+ msleep(33);
+ return 0;
+}
+
+static int dst_i2c_disable(struct dst_state *state)
+{
+ int retval;
+ /* release I2C enable gpio pin, wait */
+ // dprintk ("%s: i2c disable\n", __FUNCTION__);
+ retval = dst_gpio_outb(state, ~0, 0, 0);
+ if (retval < 0)
+ return retval;
+ // dprintk ("%s: i2c disable delay\n", __FUNCTION__);
+ msleep(33);
+ return 0;
+}
+
+static int dst_wait_dst_ready(struct dst_state *state)
+{
+ u8 reply;
+ int retval;
+ int i;
+ for (i = 0; i < 200; i++) {
+ retval = dst_gpio_inb(state, &reply);
+ if (retval < 0)
+ return retval;
+ if ((reply & DST_I2C_ENABLE) == 0) {
+ dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i);
+ return 1;
+ }
+ msleep(5);
+ }
+ dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
+ return 0;
+}
+
+static int write_dst(struct dst_state *state, u8 * data, u8 len)
+{
+ struct i2c_msg msg = {
+ .addr = state->config->demod_address,.flags = 0,.buf = data,.len = len
+ };
+ int err;
+ int cnt;
+
+ if (dst_debug && dst_verbose) {
+ u8 i;
+ dprintk("%s writing", __FUNCTION__);
+ for (i = 0; i < len; i++) {
+ dprintk(" 0x%02x", data[i]);
+ }
+ dprintk("\n");
+ }
+ msleep(30);
+ for (cnt = 0; cnt < 4; cnt++) {
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+ dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]);
+ dst_i2c_disable(state);
+ msleep(500);
+ dst_i2c_enable(state);
+ msleep(500);
+ continue;
+ } else
+ break;
+ }
+ if (cnt >= 4)
+ return -EREMOTEIO;
+ return 0;
+}
+
+static int read_dst(struct dst_state *state, u8 * ret, u8 len)
+{
+ struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len };
+ int err;
+ int cnt;
+
+ for (cnt = 0; cnt < 4; cnt++) {
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+ dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]);
+ dst_i2c_disable(state);
+ dst_i2c_enable(state);
+ continue;
+ } else
+ break;
+ }
+ if (cnt >= 4)
+ return -EREMOTEIO;
+ dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]);
+ if (dst_debug && dst_verbose) {
+ for (err = 1; err < len; err++)
+ dprintk(" 0x%x", ret[err]);
+ if (err > 1)
+ dprintk("\n");
+ }
+ return 0;
+}
+
+static int dst_set_freq(struct dst_state *state, u32 freq)
+{
+ u8 *val;
+
+ state->frequency = freq;
+
+ // dprintk("%s: set frequency %u\n", __FUNCTION__, freq);
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ freq = freq / 1000;
+ if (freq < 950 || freq > 2150)
+ return -EINVAL;
+ val = &state->tx_tuna[0];
+ val[2] = (freq >> 8) & 0x7f;
+ val[3] = (u8) freq;
+ val[4] = 1;
+ val[8] &= ~4;
+ if (freq < 1531)
+ val[8] |= 4;
+ } else if (state->dst_type == DST_TYPE_IS_TERR) {
+ freq = freq / 1000;
+ if (freq < 137000 || freq > 858000)
+ return -EINVAL;
+ val = &state->tx_tuna[0];
+ val[2] = (freq >> 16) & 0xff;
+ val[3] = (freq >> 8) & 0xff;
+ val[4] = (u8) freq;
+ val[5] = 0;
+ switch (state->bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ val[6] = 6;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ case BANDWIDTH_AUTO:
+ val[6] = 7;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ val[6] = 8;
+ break;
+ }
+
+ val[7] = 0;
+ val[8] = 0;
+ } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ /* guess till will get one */
+ freq = freq / 1000;
+ val = &state->tx_tuna[0];
+ val[2] = (freq >> 16) & 0xff;
+ val[3] = (freq >> 8) & 0xff;
+ val[4] = (u8) freq;
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth)
+{
+ u8 *val;
+
+ state->bandwidth = bandwidth;
+
+ if (state->dst_type != DST_TYPE_IS_TERR)
+ return 0;
+
+ val = &state->tx_tuna[0];
+ switch (bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ val[6] = 6;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ val[6] = 7;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ val[6] = 8;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion)
+{
+ u8 *val;
+
+ state->inversion = inversion;
+
+ val = &state->tx_tuna[0];
+
+ val[8] &= ~0x80;
+
+ switch (inversion) {
+ case INVERSION_OFF:
+ break;
+ case INVERSION_ON:
+ val[8] |= 0x80;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+static int dst_set_fec(struct dst_state* state, fe_code_rate_t fec)
+{
+ state->fec = fec;
+ return 0;
+}
+
+static fe_code_rate_t dst_get_fec(struct dst_state* state)
+{
+ return state->fec;
+}
+
+static int dst_set_symbolrate(struct dst_state* state, u32 srate)
+{
+ u8 *val;
+ u32 symcalc;
+ u64 sval;
+
+ state->symbol_rate = srate;
+
+ if (state->dst_type == DST_TYPE_IS_TERR) {
+ return 0;
+ }
+ // dprintk("%s: set srate %u\n", __FUNCTION__, srate);
+ srate /= 1000;
+ val = &state->tx_tuna[0];
+
+ if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+ sval = srate;
+ sval <<= 20;
+ do_div(sval, 88000);
+ symcalc = (u32) sval;
+ // dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc);
+ val[5] = (u8) (symcalc >> 12);
+ val[6] = (u8) (symcalc >> 4);
+ val[7] = (u8) (symcalc << 4);
+ } else {
+ val[5] = (u8) (srate >> 16) & 0x7f;
+ val[6] = (u8) (srate >> 8);
+ val[7] = (u8) srate;
+ }
+ val[8] &= ~0x20;
+ if (srate > 8000)
+ val[8] |= 0x20;
+ return 0;
+}
+
+
+static u8 dst_check_sum(u8 * buf, u32 len)
+{
+ u32 i;
+ u8 val = 0;
+ if (!len)
+ return 0;
+ for (i = 0; i < len; i++) {
+ val += buf[i];
+ }
+ return ((~val) + 1);
+}
+
+typedef struct dst_types {
+ char *mstr;
+ int offs;
+ u8 dst_type;
+ u32 type_flags;
+} DST_TYPES;
+
+struct dst_types dst_tlist[] = {
+ {"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
+ {"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
+ {"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204},
+ {"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
+ {"DST-CI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
+ {"DSTMCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
+ {"DSTFCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
+ {"DCTNEW", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE},
+ {"DCT_CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204},
+ {"DTTDIG", 1, DST_TYPE_IS_TERR, 0}
+};
+
+/* DCTNEW and DCT-CI are guesses */
+
+static void dst_type_flags_print(u32 type_flags)
+{
+ printk("DST type flags :");
+ if (type_flags & DST_TYPE_HAS_NEWTUNE)
+ printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+ if (type_flags & DST_TYPE_HAS_TS204)
+ printk(" 0x%x ts204", DST_TYPE_HAS_TS204);
+ if (type_flags & DST_TYPE_HAS_SYMDIV)
+ printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
+ printk("\n");
+}
+
+static int dst_type_print(u8 type)
+{
+ char *otype;
+ switch (type) {
+ case DST_TYPE_IS_SAT:
+ otype = "satellite";
+ break;
+ case DST_TYPE_IS_TERR:
+ otype = "terrestial TV";
+ break;
+ case DST_TYPE_IS_CABLE:
+ otype = "terrestial TV";
+ break;
+ default:
+ printk("%s: invalid dst type %d\n", __FUNCTION__, type);
+ return -EINVAL;
+ }
+ printk("DST type : %s\n", otype);
+ return 0;
+}
+
+static int dst_check_ci(struct dst_state *state)
+{
+ u8 txbuf[8];
+ u8 rxbuf[8];
+ int retval;
+ int i;
+ struct dst_types *dsp;
+ u8 use_dst_type;
+ u32 use_type_flags;
+
+ memset(txbuf, 0, sizeof(txbuf));
+ txbuf[1] = 6;
+ txbuf[7] = dst_check_sum(txbuf, 7);
+
+ dst_i2c_enable(state);
+ dst_reset8820(state);
+ retval = write_dst(state, txbuf, 8);
+ if (retval < 0) {
+ dst_i2c_disable(state);
+ dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__);
+ return retval;
+ }
+ msleep(3);
+ retval = read_dst(state, rxbuf, 1);
+ dst_i2c_disable(state);
+ if (retval < 0) {
+ dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__);
+ return retval;
+ }
+ if (rxbuf[0] != 0xff) {
+ dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]);
+ return retval;
+ }
+ if (!dst_wait_dst_ready(state))
+ return 0;
+ // dst_i2c_enable(i2c); Dimitri
+ retval = read_dst(state, rxbuf, 8);
+ dst_i2c_disable(state);
+ if (retval < 0) {
+ dprintk("%s: read not successful\n", __FUNCTION__);
+ return retval;
+ }
+ if (rxbuf[7] != dst_check_sum(rxbuf, 7)) {
+ dprintk("%s: checksum failure\n", __FUNCTION__);
+ return retval;
+ }
+ rxbuf[7] = '\0';
+ for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) {
+ if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) {
+ use_type_flags = dsp->type_flags;
+ use_dst_type = dsp->dst_type;
+ printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr);
+ break;
+ }
+ }
+ if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) {
+ printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]);
+ printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__);
+ use_dst_type = DST_TYPE_IS_SAT;
+ use_type_flags = DST_TYPE_HAS_SYMDIV;
+ }
+ dst_type_print(use_dst_type);
+
+ state->type_flags = use_type_flags;
+ state->dst_type = use_dst_type;
+ dst_type_flags_print(state->type_flags);
+
+ if (state->type_flags & DST_TYPE_HAS_TS204) {
+ dst_packsize(state, 204);
+ }
+ return 0;
+}
+
+static int dst_command(struct dst_state* state, u8 * data, u8 len)
+{
+ int retval;
+ u8 reply;
+
+ dst_i2c_enable(state);
+ dst_reset8820(state);
+ retval = write_dst(state, data, len);
+ if (retval < 0) {
+ dst_i2c_disable(state);
+ dprintk("%s: write not successful\n", __FUNCTION__);
+ return retval;
+ }
+ msleep(33);
+ retval = read_dst(state, &reply, 1);
+ dst_i2c_disable(state);
+ if (retval < 0) {
+ dprintk("%s: read verify not successful\n", __FUNCTION__);
+ return retval;
+ }
+ if (reply != 0xff) {
+ dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
+ return 0;
+ }
+ if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
+ return 0;
+ if (!dst_wait_dst_ready(state))
+ return 0;
+ // dst_i2c_enable(i2c); Per dimitri
+ retval = read_dst(state, state->rxbuffer, 8);
+ dst_i2c_disable(state);
+ if (retval < 0) {
+ dprintk("%s: read not successful\n", __FUNCTION__);
+ return 0;
+ }
+ if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
+ dprintk("%s: checksum failure\n", __FUNCTION__);
+ return 0;
+ }
+ return 0;
+}
+
+static int dst_get_signal(struct dst_state* state)
+{
+ int retval;
+ u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
+
+ if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
+ state->decode_lock = state->decode_strength = state->decode_snr = 0;
+ return 0;
+ }
+ if (0 == (state->diseq_flags & HAS_LOCK)) {
+ state->decode_lock = state->decode_strength = state->decode_snr = 0;
+ return 0;
+ }
+ if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) {
+ retval = dst_command(state, get_signal, 8);
+ if (retval < 0)
+ return retval;
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
+ state->decode_strength = state->rxbuffer[5] << 8;
+ state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
+ } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) {
+ state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
+ state->decode_strength = state->rxbuffer[4] << 8;
+ state->decode_snr = state->rxbuffer[3] << 8;
+ }
+ state->cur_jiff = jiffies;
+ }
+ return 0;
+}
+
+static int dst_tone_power_cmd(struct dst_state* state)
+{
+ u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
+
+ if (state->dst_type == DST_TYPE_IS_TERR)
+ return 0;
+
+ if (state->voltage == SEC_VOLTAGE_OFF)
+ paket[4] = 0;
+ else
+ paket[4] = 1;
+ if (state->tone == SEC_TONE_ON)
+ paket[2] = state->k22;
+ else
+ paket[2] = 0;
+ paket[7] = dst_check_sum(&paket[0], 7);
+ dst_command(state, paket, 8);
+ return 0;
+}
+
+static int dst_get_tuna(struct dst_state* state)
+{
+ int retval;
+ if ((state->diseq_flags & ATTEMPT_TUNE) == 0)
+ return 0;
+ state->diseq_flags &= ~(HAS_LOCK);
+ if (!dst_wait_dst_ready(state))
+ return 0;
+ if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ /* how to get variable length reply ???? */
+ retval = read_dst(state, state->rx_tuna, 10);
+ } else {
+ retval = read_dst(state, &state->rx_tuna[2], 8);
+ }
+ if (retval < 0) {
+ dprintk("%s: read not successful\n", __FUNCTION__);
+ return 0;
+ }
+ if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
+ dprintk("%s: checksum failure?\n", __FUNCTION__);
+ return 0;
+ }
+ } else {
+ if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
+ dprintk("%s: checksum failure?\n", __FUNCTION__);
+ return 0;
+ }
+ }
+ if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
+ return 0;
+ state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+
+ state->decode_lock = 1;
+ /*
+ dst->decode_n1 = (dst->rx_tuna[4] << 8) +
+ (dst->rx_tuna[5]);
+
+ dst->decode_n2 = (dst->rx_tuna[8] << 8) +
+ (dst->rx_tuna[7]);
+ */
+ state->diseq_flags |= HAS_LOCK;
+ /* dst->cur_jiff = jiffies; */
+ return 1;
+}
+
+static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+
+static int dst_write_tuna(struct dvb_frontend* fe)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ int retval;
+ u8 reply;
+
+ dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags);
+ state->decode_freq = 0;
+ state->decode_lock = state->decode_strength = state->decode_snr = 0;
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (!(state->diseq_flags & HAS_POWER))
+ dst_set_voltage(fe, SEC_VOLTAGE_13);
+ }
+ state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
+ dst_i2c_enable(state);
+ if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ dst_reset8820(state);
+ state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
+ retval = write_dst(state, &state->tx_tuna[0], 10);
+ } else {
+ state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7);
+ retval = write_dst(state, &state->tx_tuna[2], 8);
+ }
+ if (retval < 0) {
+ dst_i2c_disable(state);
+ dprintk("%s: write not successful\n", __FUNCTION__);
+ return retval;
+ }
+ msleep(3);
+ retval = read_dst(state, &reply, 1);
+ dst_i2c_disable(state);
+ if (retval < 0) {
+ dprintk("%s: read verify not successful\n", __FUNCTION__);
+ return retval;
+ }
+ if (reply != 0xff) {
+ dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
+ return 0;
+ }
+ state->diseq_flags |= ATTEMPT_TUNE;
+ return dst_get_tuna(state);
+}
+
+
+
+
+
+
+
+
+/*
+ * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
+ * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
+ * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
+ * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
+ * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
+ * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
+ * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
+ * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
+ * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8
+ * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4
+ * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0
+ */
+
+static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
+
+ if (state->dst_type == DST_TYPE_IS_TERR)
+ return 0;
+
+ if (cmd->msg_len == 0 || cmd->msg_len > 4)
+ return -EINVAL;
+ memcpy(&paket[3], cmd->msg, cmd->msg_len);
+ paket[7] = dst_check_sum(&paket[0], 7);
+ dst_command(state, paket, 8);
+ return 0;
+}
+
+static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ u8 *val;
+ int need_cmd;
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+ state->voltage = voltage;
+
+ if (state->dst_type == DST_TYPE_IS_TERR)
+ return 0;
+
+ need_cmd = 0;
+ val = &state->tx_tuna[0];
+ val[8] &= ~0x40;
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ if ((state->diseq_flags & HAS_POWER) == 0)
+ need_cmd = 1;
+ state->diseq_flags |= HAS_POWER;
+ break;
+ case SEC_VOLTAGE_18:
+ if ((state->diseq_flags & HAS_POWER) == 0)
+ need_cmd = 1;
+ state->diseq_flags |= HAS_POWER;
+ val[8] |= 0x40;
+ break;
+ case SEC_VOLTAGE_OFF:
+ need_cmd = 1;
+ state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (need_cmd) {
+ dst_tone_power_cmd(state);
+ }
+ return 0;
+}
+
+
+static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ u8 *val;
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+ state->tone = tone;
+
+ if (state->dst_type == DST_TYPE_IS_TERR)
+ return 0;
+
+ val = &state->tx_tuna[0];
+
+ val[8] &= ~0x1;
+
+ switch (tone) {
+ case SEC_TONE_OFF:
+ break;
+ case SEC_TONE_ON:
+ val[8] |= 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ dst_tone_power_cmd(state);
+ return 0;
+}
+
+
+static int dst_init(struct dvb_frontend* fe)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
+ static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
+ static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+ static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+ static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+ static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+ state->inversion = INVERSION_ON;
+ state->voltage = SEC_VOLTAGE_13;
+ state->tone = SEC_TONE_OFF;
+ state->symbol_rate = 29473000;
+ state->fec = FEC_AUTO;
+ state->diseq_flags = 0;
+ state->k22 = 0x02;
+ state->bandwidth = BANDWIDTH_7_MHZ;
+ state->cur_jiff = jiffies;
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ state->frequency = 950000;
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna));
+ } else if (state->dst_type == DST_TYPE_IS_TERR) {
+ state->frequency = 137000000;
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna));
+ } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ state->frequency = 51000000;
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna));
+ }
+
+ return 0;
+}
+
+static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+ *status = 0;
+ if (state->diseq_flags & HAS_LOCK) {
+ dst_get_signal(state);
+ if (state->decode_lock)
+ *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
+ }
+
+ return 0;
+}
+
+static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+ dst_get_signal(state);
+ *strength = state->decode_strength;
+
+ return 0;
+}
+
+static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+ dst_get_signal(state);
+ *snr = state->decode_snr;
+
+ return 0;
+}
+
+static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+ dst_set_freq(state, p->frequency);
+ dst_set_inversion(state, p->inversion);
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ dst_set_fec(state, p->u.qpsk.fec_inner);
+ dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ } else if (state->dst_type == DST_TYPE_IS_TERR) {
+ dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+ } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ dst_set_fec(state, p->u.qam.fec_inner);
+ dst_set_symbolrate(state, p->u.qam.symbol_rate);
+ }
+ dst_write_tuna(fe);
+
+ return 0;
+}
+
+static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+ p->frequency = state->decode_freq;
+ p->inversion = state->inversion;
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ p->u.qpsk.symbol_rate = state->symbol_rate;
+ p->u.qpsk.fec_inner = dst_get_fec(state);
+ } else if (state->dst_type == DST_TYPE_IS_TERR) {
+ p->u.ofdm.bandwidth = state->bandwidth;
+ } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ p->u.qam.symbol_rate = state->symbol_rate;
+ p->u.qam.fec_inner = dst_get_fec(state);
+ p->u.qam.modulation = QAM_AUTO;
+ }
+
+ return 0;
+}
+
+static void dst_release(struct dvb_frontend* fe)
+{
+ struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops dst_dvbt_ops;
+static struct dvb_frontend_ops dst_dvbs_ops;
+static struct dvb_frontend_ops dst_dvbc_ops;
+
+struct dvb_frontend* dst_attach(const struct dst_config* config,
+ struct i2c_adapter* i2c,
+ struct bt878 *bt)
+{
+ struct dst_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct dst_state*) kmalloc(sizeof(struct dst_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->bt = bt;
+
+ /* check if the demod is there */
+ if (dst_check_ci(state) < 0) goto error;
+
+ /* determine settings based on type */
+ switch (state->dst_type) {
+ case DST_TYPE_IS_TERR:
+ memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+ break;
+ case DST_TYPE_IS_CABLE:
+ memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+ break;
+ case DST_TYPE_IS_SAT:
+ memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+ break;
+ default:
+ printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n");
+ goto error;
+ }
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops dst_dvbt_ops = {
+
+ .info = {
+ .name = "DST DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 137000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166667,
+ .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+ },
+
+ .release = dst_release,
+
+ .init = dst_init,
+
+ .set_frontend = dst_set_frontend,
+ .get_frontend = dst_get_frontend,
+
+ .read_status = dst_read_status,
+ .read_signal_strength = dst_read_signal_strength,
+ .read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_dvbs_ops = {
+
+ .info = {
+ .name = "DST DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 1000, /* kHz for QPSK frontends */
+ .frequency_tolerance = 29500,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ /* . symbol_rate_tolerance = ???,*/
+ .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
+ },
+
+ .release = dst_release,
+
+ .init = dst_init,
+
+ .set_frontend = dst_set_frontend,
+ .get_frontend = dst_get_frontend,
+
+ .read_status = dst_read_status,
+ .read_signal_strength = dst_read_signal_strength,
+ .read_snr = dst_read_snr,
+
+ .diseqc_send_master_cmd = dst_set_diseqc,
+ .set_voltage = dst_set_voltage,
+ .set_tone = dst_set_tone,
+};
+
+static struct dvb_frontend_ops dst_dvbc_ops = {
+
+ .info = {
+ .name = "DST DVB-C",
+ .type = FE_QAM,
+ .frequency_stepsize = 62500,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ /* . symbol_rate_tolerance = ???,*/
+ .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
+ },
+
+ .release = dst_release,
+
+ .init = dst_init,
+
+ .set_frontend = dst_set_frontend,
+ .get_frontend = dst_get_frontend,
+
+ .read_status = dst_read_status,
+ .read_signal_strength = dst_read_signal_strength,
+ .read_snr = dst_read_snr,
+};
+
+
+MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+MODULE_AUTHOR("Jamie Honan");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dst_attach);
diff --git a/linux/drivers/media/dvb/bt8xx/dst.h b/linux/drivers/media/dvb/bt8xx/dst.h
new file mode 100644
index 000000000..79fbe24ad
--- /dev/null
+++ b/linux/drivers/media/dvb/bt8xx/dst.h
@@ -0,0 +1,40 @@
+/*
+ Frontend-driver for TwinHan DST Frontend
+
+ Copyright (C) 2003 Jamie Honan
+
+ 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 DST_H
+#define DST_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/device.h>
+#include "bt878.h"
+
+struct dst_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+};
+
+extern struct dvb_frontend* dst_attach(const struct dst_config* config,
+ struct i2c_adapter* i2c,
+ struct bt878 *bt);
+
+#endif // DST_H
diff --git a/linux/drivers/media/dvb/frontends/dst-bt878.h b/linux/drivers/media/dvb/bt8xx/dst_priv.h
index b3d5e6fc6..b3d5e6fc6 100644
--- a/linux/drivers/media/dvb/frontends/dst-bt878.h
+++ b/linux/drivers/media/dvb/bt8xx/dst_priv.h
diff --git a/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index c12c11ec4..3e81996f6 100644
--- a/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -126,7 +126,242 @@ static struct bt878 __init *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci
return NULL;
}
-static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card)
+
+static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
+{
+ static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 };
+ static u8 mt352_reset [] = { 0x50, 0x80 };
+ static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+ static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
+ static u8 mt352_gpp_ctl_cfg [] = { 0x75, 0x33 };
+ static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+ mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+ udelay(2000);
+ mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+ mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+ mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+ mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
+ mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+ return 0;
+}
+
+static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+{
+ u32 div;
+ unsigned char bs = 0;
+ unsigned char cp = 0;
+
+ #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
+ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+ if (params->frequency < 542000000) cp = 0xb4;
+ else if (params->frequency < 771000000) cp = 0xbc;
+ else cp = 0xf4;
+
+ if (params->frequency == 0) bs = 0x03;
+ else if (params->frequency < 443250000) bs = 0x02;
+ else bs = 0x08;
+
+ pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+ pllbuf[1] = div >> 8;
+ pllbuf[2] = div & 0xff;
+ pllbuf[3] = cp;
+ pllbuf[4] = bs;
+
+ return 0;
+}
+
+static struct mt352_config thomson_dtt7579_config = {
+
+ .demod_address = 0x0f,
+ .demod_init = thomson_dtt7579_demod_init,
+ .pll_set = thomson_dtt7579_pll_set,
+};
+
+
+
+static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
+ u8 cfg, cpump, band_select;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (36000000 + params->frequency + 83333) / 166666;
+ cfg = 0x88;
+
+ if (params->frequency < 175000000) cpump = 2;
+ else if (params->frequency < 390000000) cpump = 1;
+ else if (params->frequency < 470000000) cpump = 2;
+ else if (params->frequency < 750000000) cpump = 2;
+ else cpump = 3;
+
+ if (params->frequency < 175000000) band_select = 0x0e;
+ else if (params->frequency < 470000000) band_select = 0x05;
+ else band_select = 0x03;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = ((div >> 10) & 0x60) | cfg;
+ data[3] = cpump | band_select;
+
+ i2c_transfer(card->i2c_adapter, &msg, 1);
+ return (div * 166666 - 36000000);
+}
+
+static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &bt->bt->dev->dev);
+}
+
+struct sp887x_config microtune_mt7202dtf_config = {
+
+ .demod_address = 0x70,
+ .pll_set = microtune_mt7202dtf_pll_set,
+ .request_firmware = microtune_mt7202dtf_request_firmware,
+};
+
+
+
+
+static int advbt771_demod_init(struct dvb_frontend* fe)
+{
+ static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
+ static u8 mt352_reset [] = { 0x50, 0x80 };
+ static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+ static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+ 0x00, 0xFF, 0x00, 0x40, 0x40 };
+ static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
+ static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+
+ mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+ udelay(2000);
+ mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+ mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+ mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
+ udelay(2000);
+ mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra));
+ mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+ return 0;
+}
+
+static int advbt771_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+{
+ u32 div;
+ unsigned char bs = 0;
+ unsigned char cp = 0;
+
+ #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
+ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+ if (params->frequency < 150000000) cp = 0xB4;
+ else if (params->frequency < 173000000) cp = 0xBC;
+ else if (params->frequency < 250000000) cp = 0xB4;
+ else if (params->frequency < 400000000) cp = 0xBC;
+ else if (params->frequency < 420000000) cp = 0xF4;
+ else if (params->frequency < 470000000) cp = 0xFC;
+ else if (params->frequency < 600000000) cp = 0xBC;
+ else if (params->frequency < 730000000) cp = 0xF4;
+ else cp = 0xFC;
+
+ if (params->frequency < 150000000) bs = 0x01;
+ else if (params->frequency < 173000000) bs = 0x01;
+ else if (params->frequency < 250000000) bs = 0x02;
+ else if (params->frequency < 400000000) bs = 0x02;
+ else if (params->frequency < 420000000) bs = 0x02;
+ else if (params->frequency < 470000000) bs = 0x02;
+ else if (params->frequency < 600000000) bs = 0x08;
+ else if (params->frequency < 730000000) bs = 0x08;
+ else bs = 0x08;
+
+ pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+ pllbuf[1] = div >> 8;
+ pllbuf[2] = div & 0xff;
+ pllbuf[3] = cp;
+ pllbuf[4] = bs;
+
+ return 0;
+}
+
+static struct mt352_config advbt771_config = {
+
+ .demod_address = 0x0f,
+ .demod_init = advbt771_demod_init,
+ .pll_set = advbt771_pll_set,
+};
+
+
+static struct dst_config dst_config = {
+
+ .demod_address = 0x55,
+};
+
+
+
+static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
+{
+ switch(type) {
+#ifdef BTTV_DVICO_DVBT_LITE
+ case BTTV_DVICO_DVBT_LITE:
+ card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter, card->dvb_adapter);
+ if (card->fe != NULL) {
+ card->fe->ops->info.frequency_min = 174000000;
+ card->fe->ops->info.frequency_max = 862000000;
+ break;
+ }
+ break;
+#endif
+
+ case BTTV_AVDVBT_761:
+ card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+ if (card->fe != NULL) {
+ break;
+ }
+ break;
+
+ case BTTV_AVDVBT_771:
+ card->fe = mt352_attach(&advbt771_config, card->i2c_adapter);
+ if (card->fe != NULL) {
+ card->fe->ops->info.frequency_min = 174000000;
+ card->fe->ops->info.frequency_max = 862000000;
+ break;
+ }
+ break;
+
+ case BTTV_TWINHAN_DST:
+ card->fe = dst_attach(&dst_config, card->i2c_adapter, card->bt);
+ if (card->fe != NULL) {
+ break;
+ }
+ break;
+ }
+
+ if (card->fe == NULL) {
+ printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ card->bt->dev->vendor,
+ card->bt->dev->device,
+ card->bt->dev->subsystem_vendor,
+ card->bt->dev->subsystem_device);
+ } else {
+ if (dvb_register_frontend(card->dvb_adapter, card->fe)) {
+ printk("dvb-bt8xx: Frontend registration failed!\n");
+ if (card->fe->ops->release)
+ card->fe->ops->release(card->fe);
+ card->fe = NULL;
+ }
+ }
+}
+
+static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
{
int result;
@@ -136,6 +371,7 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card)
return result;
}
+ card->dvb_adapter->priv = card;
card->bt->adapter = card->i2c_adapter;
@@ -206,7 +442,9 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card)
dvb_net_init(card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
-
+
+ frontend_init(card, type);
+
return 0;
}
@@ -228,7 +466,7 @@ static int dvb_bt8xx_probe(struct device *dev)
switch(sub->core->type)
{
- case BTTV_PINNACLESAT:
+/* case BTTV_PINNACLESAT: UNDEFINED HARDWARE */
#ifdef BTTV_DVICO_DVBT_LITE
case BTTV_DVICO_DVBT_LITE:
#endif
@@ -239,8 +477,7 @@ static int dvb_bt8xx_probe(struct device *dev)
* A_PWRDN DA_DPM DA_SBR DA_IOM_DA
* DA_APP(parallel) */
break;
-
- case BTTV_NEBULA_DIGITV:
+/* case BTTV_NEBULA_DIGITV: UNDEFINED HARDWARE */
case BTTV_AVDVBT_761:
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
card->op_sync_orin = 0;
@@ -302,7 +539,7 @@ static int dvb_bt8xx_probe(struct device *dev)
init_MUTEX(&card->bt->gpio_lock);
card->bt->bttv_nr = sub->core->nr;
- if ( (ret = dvb_bt8xx_load_card(card)) ) {
+ if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
kfree(card);
return ret;
}
@@ -324,6 +561,7 @@ static int dvb_bt8xx_remove(struct device *dev)
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
dvb_dmxdev_release(&card->dmxdev);
dvb_dmx_release(&card->demux);
+ if (card->fe) dvb_unregister_frontend(card->fe);
dvb_unregister_adapter(card->dvb_adapter);
kfree(card);
@@ -331,24 +569,6 @@ static int dvb_bt8xx_remove(struct device *dev)
return 0;
}
-static void dvb_bt8xx_i2c_info(struct bttv_sub_device *sub,
- struct i2c_client *client, int attach)
-{
- struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
-
- if (attach) {
- printk("xxx attach\n");
- if (client->driver->command)
- client->driver->command(client, FE_REGISTER,
- card->dvb_adapter);
- } else {
- printk("xxx detach\n");
- if (client->driver->command)
- client->driver->command(client, FE_UNREGISTER,
- card->dvb_adapter);
- }
-}
-
static struct bttv_sub_driver driver = {
.drv = {
.name = "dvb-bt8xx",
@@ -360,7 +580,6 @@ static struct bttv_sub_driver driver = {
* .resume = dvb_bt8xx_resume,
*/
},
- .i2c_info = dvb_bt8xx_i2c_info,
};
static int __init dvb_bt8xx_init(void)
diff --git a/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index a7f2408a0..2869c4909 100644
--- a/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -26,6 +26,9 @@
#include "dvbdev.h"
#include "dvb_net.h"
#include "bttv.h"
+#include "mt352.h"
+#include "sp887x.h"
+#include "dst.h"
struct dvb_bt8xx_card {
struct semaphore lock;
@@ -43,5 +46,6 @@ struct dvb_bt8xx_card {
u32 irq_err_ignore;
struct i2c_adapter *i2c_adapter;
struct dvb_net dvbnet;
-};
+ struct dvb_frontend* fe;
+};
diff --git a/linux/drivers/media/dvb/cinergyT2/cinergyT2.c b/linux/drivers/media/dvb/cinergyT2/cinergyT2.c
index 3f8e4b59d..ad1aed31a 100644
--- a/linux/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/linux/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -94,7 +94,32 @@ struct dvbt_get_status_msg {
uint8_t prev_lock_bits;
} __attribute__((packed));
-static struct dvb_frontend_info cinergyt2_fe_info = {
+struct dvbt_set_parameters_msg {
+ uint8_t cmd;
+ uint32_t freq;
+ uint8_t bandwidth;
+ uint16_t tps;
+ uint8_t flags;
+} __attribute__((packed));
+
+
+struct dvbt_get_status_msg {
+ uint32_t freq;
+ uint8_t bandwidth;
+ uint16_t tps;
+ uint8_t flags;
+ uint16_t gain;
+ uint8_t snr;
+ uint32_t viterbi_error_rate;
+ uint32_t rs_error_rate;
+ uint32_t uncorrected_block_count;
+ uint8_t lock_bits;
+ uint8_t prev_lock_bits;
+} __attribute__((packed));
+
+
+static
+struct dvb_frontend_info cinergyt2_fe_info = {
.name = DRIVER_NAME,
.type = FE_OFDM,
.frequency_min = 174000000,
@@ -330,7 +355,9 @@ static int cinergyt2_start_stream_xfer (struct cinergyt2 *cinergyt2)
return 0;
}
-static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+
+static
+int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv;
@@ -346,7 +373,9 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
return 0;
}
-static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+
+static
+int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv;
@@ -370,7 +399,8 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
*
* We replace errornous fields by default TPS fields (the ones with value 0).
*/
-static uint16_t compute_tps (struct dvb_frontend_parameters *p)
+static
+uint16_t compute_tps (struct dvb_frontend_parameters *p)
{
struct dvb_ofdm_parameters *op = &p->u.ofdm;
uint16_t tps = 0;
@@ -467,7 +497,8 @@ static uint16_t compute_tps (struct dvb_frontend_parameters *p)
return tps;
}
-static int cinergyt2_open (struct inode *inode, struct file *file)
+static
+int cinergyt2_open (struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
@@ -488,7 +519,8 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
return 0;
}
-static int cinergyt2_release (struct inode *inode, struct file *file)
+static
+int cinergyt2_release (struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
@@ -507,7 +539,9 @@ static int cinergyt2_release (struct inode *inode, struct file *file)
return dvb_generic_release(inode, file);
}
-static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait)
+
+static
+unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait)
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
@@ -515,7 +549,10 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
return (POLLIN | POLLRDNORM | POLLPRI);
}
-static int cinergyt2_ioctl (struct inode *inode, struct file *file,
+
+
+static
+int cinergyt2_ioctl (struct inode *inode, struct file *file,
unsigned cmd, unsigned long arg)
{
struct dvb_device *dvbdev = file->private_data;
@@ -600,7 +637,9 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
return -EINVAL;
}
-static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma)
+
+static
+int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
@@ -630,7 +669,9 @@ bailout:
return ret;
}
-static struct file_operations cinergyt2_fops = {
+
+static
+struct file_operations cinergyt2_fops = {
.owner = THIS_MODULE,
.ioctl = cinergyt2_ioctl,
.poll = cinergyt2_poll,
@@ -646,6 +687,7 @@ static struct dvb_device cinergyt2_fe_template = {
.fops = &cinergyt2_fops
};
+
#ifdef ENABLE_RC
static void cinergyt2_query_rc (void *data)
{
@@ -728,7 +770,8 @@ static void cinergyt2_query (void *data)
up(&cinergyt2->sem);
}
-static int cinergyt2_probe (struct usb_interface *intf,
+static
+int cinergyt2_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
struct cinergyt2 *cinergyt2;
@@ -766,7 +809,8 @@ static int cinergyt2_probe (struct usb_interface *intf,
DMX_MEMORY_BASED_FILTERING;
if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) {
- dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err);
+ printk("%s: dvb_dmx_init() failed (err = %d)\n",
+ __FUNCTION__, err);
goto bailout;
}
@@ -775,12 +819,13 @@ static int cinergyt2_probe (struct usb_interface *intf,
cinergyt2->dmxdev.capabilities = 0;
if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, cinergyt2->adapter)) < 0) {
- dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err);
+ printk("%s: dvb_dmxdev_init() failed (err = %d)\n",
+ __FUNCTION__, err);
goto bailout;
}
if (dvb_net_init(cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx))
- dprintk(1, "dvb_net_init() failed!\n");
+ printk("%s: dvb_net_init failed!\n", __FUNCTION__);
dvb_register_device(cinergyt2->adapter, &cinergyt2->fedev,
&cinergyt2_fe_template, cinergyt2,
@@ -840,7 +885,8 @@ static void cinergyt2_disconnect (struct usb_interface *intf)
kfree(cinergyt2);
}
-static int cinergyt2_suspend (struct usb_interface *intf, u32 state)
+static
+int cinergyt2_suspend (struct usb_interface *intf, u32 state)
{
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
@@ -863,7 +909,9 @@ static int cinergyt2_suspend (struct usb_interface *intf, u32 state)
return 0;
}
-static int cinergyt2_resume (struct usb_interface *intf)
+
+static
+int cinergyt2_resume (struct usb_interface *intf)
{
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
struct dvbt_set_parameters_msg *param = &cinergyt2->param;
@@ -886,11 +934,14 @@ static int cinergyt2_resume (struct usb_interface *intf)
return 0;
}
-static const struct usb_device_id cinergyt2_table [] __devinitdata = {
+
+static const
+struct usb_device_id cinergyt2_table [] __devinitdata = {
{ USB_DEVICE(0x0ccd, 0x0038) },
{ 0 }
};
+
MODULE_DEVICE_TABLE(usb, cinergyt2_table);
static struct usb_driver cinergyt2_driver = {
@@ -903,12 +954,15 @@ static struct usb_driver cinergyt2_driver = {
.id_table = cinergyt2_table
};
-static int __init cinergyt2_init (void)
+
+static
+int __init cinergyt2_init (void)
{
int err;
if ((err = usb_register(&cinergyt2_driver)) < 0)
- dprintk(1, "usb_register() failed! (err %i)\n", err);
+ printk("%s: usb_register() failed! (err %i)\n",
+ __FUNCTION__, err);
return err;
}
diff --git a/linux/drivers/media/dvb/dibusb/Kconfig b/linux/drivers/media/dvb/dibusb/Kconfig
index f4eb6566e..afe683681 100644
--- a/linux/drivers/media/dvb/dibusb/Kconfig
+++ b/linux/drivers/media/dvb/dibusb/Kconfig
@@ -2,6 +2,7 @@ config DVB_DIBUSB
tristate "DiBcom/Twinhan/KWorld/Hama/Artec/Compro USB DVB-T devices"
depends on DVB_CORE && USB
select FW_LOADER
+ select DVB_DIB3000MB
help
Support for USB 1.1 DVB-T devices based on a reference design made by
DiBcom (http://www.dibcom.fr).
diff --git a/linux/drivers/media/dvb/dibusb/Makefile b/linux/drivers/media/dvb/dibusb/Makefile
index 72cd6a241..ab990cd3b 100644
--- a/linux/drivers/media/dvb/dibusb/Makefile
+++ b/linux/drivers/media/dvb/dibusb/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/linux/drivers/media/dvb/dibusb/dvb-dibusb.c b/linux/drivers/media/dvb/dibusb/dvb-dibusb.c
index f6854f443..88092509c 100644
--- a/linux/drivers/media/dvb/dibusb/dvb-dibusb.c
+++ b/linux/drivers/media/dvb/dibusb/dvb-dibusb.c
@@ -36,9 +36,11 @@
#include "dvb_filter.h"
#include "dvb_net.h"
#include "dvb_frontend.h"
+#include "dib3000mb.h"
#include "dvb-dibusb.h"
+
/* debug */
#ifdef CONFIG_DVB_DIBCOM_DEBUG
@@ -394,22 +396,40 @@ static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
return I2C_FUNC_I2C;
}
-static int dibusb_i2c_client_register (struct i2c_client *i2c)
+static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
- struct usb_dibusb *dib = i2c_get_adapdata(i2c->adapter);
- if (i2c->driver->command)
- return i2c->driver->command(i2c,FE_REGISTER,dib->adapter);
- return 0;
-}
+ struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ u32 tfreq = (params->frequency + 36125000) / 62500;
+ int vu,p0,p1,p2;
+
+ if (params->frequency > 403250000)
+ vu = 1, p2 = 1, p1 = 0, p0 = 1;
+ else if (params->frequency > 115750000)
+ vu = 0, p2 = 1, p1 = 1, p0 = 0;
+ else if (params->frequency > 44250000)
+ vu = 0, p2 = 0, p1 = 1, p0 = 1;
+ else
+ return -EINVAL;
-static int dibusb_i2c_client_unregister (struct i2c_client *i2c)
-{
- struct usb_dibusb *dib = i2c_get_adapdata(i2c->adapter);
- if (i2c->driver->command)
- return i2c->driver->command(i2c,FE_UNREGISTER,dib->adapter);
+ buf[0] = (tfreq >> 8) & 0x7f;
+ buf[1] = tfreq & 0xff;
+ buf[2] = 0x8e;
+ buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
+
+ if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ msleep(1);
return 0;
}
+static struct dib3000mb_config thomson_cable_eu_config = {
+ .demod_address = 0x10,
+ .pll_addr = 0x61,
+ .pll_set = thomson_cable_eu_pll_set,
+};
+
static struct i2c_algorithm dibusb_algo = {
.name = "DiBcom USB i2c algorithm",
.id = I2C_ALGO_BIT,
@@ -417,6 +437,25 @@ static struct i2c_algorithm dibusb_algo = {
.functionality = dibusb_i2c_func,
};
+static void frontend_init(struct usb_dibusb* dib)
+{
+ dib->fe = dib3000mb_attach(&thomson_cable_eu_config, &dib->i2c_adap);
+
+ if (dib->fe == NULL) {
+ printk("dvb-dibusb: A frontend driver was not found for device %04x/%04x\n",
+ dib->udev->descriptor.idVendor,
+ dib->udev->descriptor.idProduct);
+ } else {
+ if (dvb_register_frontend(dib->adapter, dib->fe)) {
+ printk("dvb-dibusb: Frontend registration failed!\n");
+ if (dib->fe->ops->release)
+ dib->fe->ops->release(dib->fe);
+ dib->fe = NULL;
+ }
+ }
+}
+
+
static int dibusb_dvb_init(struct usb_dibusb *dib)
{
int ret;
@@ -430,6 +469,7 @@ static int dibusb_dvb_init(struct usb_dibusb *dib)
deb_info("dvb_register_adapter failed: error %d", ret);
goto err;
}
+ dib->adapter->priv = dib;
strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE);
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
@@ -440,8 +480,6 @@ static int dibusb_dvb_init(struct usb_dibusb *dib)
dib->i2c_adap.algo = &dibusb_algo;
dib->i2c_adap.algo_data = NULL;
dib->i2c_adap.id = I2C_ALGO_BIT;
- dib->i2c_adap.client_register = dibusb_i2c_client_register,
- dib->i2c_adap.client_unregister = dibusb_i2c_client_unregister,
i2c_set_adapdata(&dib->i2c_adap, dib);
@@ -472,7 +510,9 @@ static int dibusb_dvb_init(struct usb_dibusb *dib)
}
dvb_net_init(dib->adapter, &dib->dvb_net, &dib->demux.dmx);
-
+
+ frontend_init(dib);
+
goto success;
err_dmx_dev:
dvb_dmx_release(&dib->demux);
@@ -495,6 +535,7 @@ static int dibusb_dvb_exit(struct usb_dibusb *dib)
dib->demux.dmx.close(&dib->demux.dmx);
dvb_dmxdev_release(&dib->dmxdev);
dvb_dmx_release(&dib->demux);
+ if (dib->fe != NULL) dvb_unregister_frontend(dib->fe);
i2c_del_adapter(&dib->i2c_adap);
dvb_unregister_adapter(dib->adapter);
diff --git a/linux/drivers/media/dvb/dibusb/dvb-dibusb.h b/linux/drivers/media/dvb/dibusb/dvb-dibusb.h
index 4d33dc469..b2b12a774 100644
--- a/linux/drivers/media/dvb/dibusb/dvb-dibusb.h
+++ b/linux/drivers/media/dvb/dibusb/dvb-dibusb.h
@@ -164,6 +164,7 @@ struct usb_dibusb {
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dvb_net dvb_net;
+ struct dvb_frontend* fe;
};
#define COMMAND_PIPE usb_sndbulkpipe(dib->udev, 0x01)
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index d2b4b9f80..a5b516fbb 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/list.h>
+#include <linux/suspend.h>
#include <asm/processor.h>
#include <asm/semaphore.h>
@@ -45,6 +46,7 @@ static int dvb_shutdown_timeout = 5;
static int dvb_override_frequency_bending;
static int dvb_force_auto_inversion;
static int dvb_override_tune_delay;
+static int dvb_powerdown_on_sleep = 1;
static int do_frequency_bending;
module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
@@ -57,6 +59,8 @@ module_param(dvb_force_auto_inversion, int, 0444);
MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
module_param(dvb_override_tune_delay, int, 0444);
MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
+module_param(dvb_powerdown_on_sleep, int, 0444);
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
#define dprintk if (dvb_frontend_debug) printk
@@ -100,12 +104,10 @@ struct dvb_fe_events {
struct dvb_frontend_data {
- struct dvb_frontend_info *info;
- struct dvb_frontend frontend;
+ struct dvb_frontend *frontend;
struct dvb_device *dvbdev;
struct dvb_frontend_parameters parameters;
struct dvb_fe_events events;
- struct module *module;
struct semaphore sem;
struct list_head list_head;
wait_queue_head_t wait_queue;
@@ -126,53 +128,11 @@ struct dvb_frontend_data {
fe_status_t status;
};
-
-struct dvb_frontend_ioctl_data {
- struct list_head list_head;
- struct dvb_adapter *adapter;
- int (*before_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg);
- int (*after_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg);
- void *before_after_data;
-};
-
-
-struct dvb_frontend_notifier_data {
- struct list_head list_head;
- struct dvb_adapter *adapter;
- void (*callback) (fe_status_t s, void *data);
- void *data;
-};
-
-
static LIST_HEAD(frontend_list);
-static LIST_HEAD(frontend_ioctl_list);
-static LIST_HEAD(frontend_notifier_list);
static DECLARE_MUTEX(frontend_mutex);
-static int dvb_frontend_internal_ioctl (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg)
-{
- int err = -EOPNOTSUPP;
-
- dprintk ("%s\n", __FUNCTION__);
-
- if (frontend->before_ioctl)
- err = frontend->before_ioctl (frontend, cmd, arg);
-
- if (err == -EOPNOTSUPP) {
- err = frontend->ioctl (frontend, cmd, arg);
-
- if ((err == -EOPNOTSUPP) && frontend->after_ioctl)
- err = frontend->after_ioctl (frontend, cmd, arg);
- }
-
- return err;
-}
-
/**
* if 2 tuners are located side by side you can get interferences when
@@ -184,8 +144,8 @@ static int dvb_frontend_internal_ioctl (struct dvb_frontend *frontend,
static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive)
{
struct list_head *entry;
- int stepsize = this_fe->info->frequency_stepsize;
- int this_fe_adap_num = this_fe->frontend.dvb_adapter->num;
+ int stepsize = this_fe->frontend->ops->info.frequency_stepsize;
+ int this_fe_adap_num = this_fe->frontend->dvb->num;
int frequency;
if (!stepsize || recursive > 10) {
@@ -209,7 +169,7 @@ static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive
fe = list_entry (entry, struct dvb_frontend_data, list_head);
- if (fe->frontend.dvb_adapter->num != this_fe_adap_num)
+ if (fe->frontend->dvb->num != this_fe_adap_num)
continue;
f = fe->parameters.frequency;
@@ -237,25 +197,6 @@ done:
up (&frontend_mutex);
}
-
-static void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe,
- fe_status_t s)
-{
- dprintk ("%s\n", __FUNCTION__);
-
- if (((s ^ fe->status) & FE_HAS_LOCK) && (s & FE_HAS_LOCK))
- msleep (fe->info->notifier_delay);
-
- fe->status = s;
-
- /**
- * now tell the Demux about the TS status changes...
- */
- if (fe->frontend.notifier_callback)
- fe->frontend.notifier_callback(fe->status, fe->frontend.notifier_data);
-}
-
-
static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t status)
{
struct dvb_fe_events *events = &fe->events;
@@ -280,15 +221,13 @@ static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t st
sizeof (struct dvb_frontend_parameters));
if (status & FE_HAS_LOCK)
- dvb_frontend_internal_ioctl (&fe->frontend,
- FE_GET_FRONTEND,
- &e->parameters);
+ if (fe->frontend->ops->get_frontend) fe->frontend->ops->get_frontend(fe->frontend, &e->parameters);
+
events->eventw = wp;
up (&events->sem);
e->status = status;
- dvb_call_frontend_notifiers (fe, status);
wake_up_interruptible (&events->wait_queue);
}
@@ -339,13 +278,11 @@ static int dvb_frontend_get_event (struct dvb_frontend_data *fe,
static void dvb_frontend_init (struct dvb_frontend_data *fe)
{
- struct dvb_frontend *frontend = &fe->frontend;
-
dprintk ("DVB: initialising frontend %i (%s)...\n",
- frontend->dvb_adapter->num,
- fe->info->name);
+ fe->frontend->dvb->num,
+ fe->frontend->ops->info.name);
- dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL);
+ fe->frontend->ops->init(fe->frontend);
}
static void update_delay (int *quality, int *delay, int min_delay, int locked)
@@ -380,7 +317,7 @@ static int dvb_frontend_autotune(struct dvb_frontend_data *fe, int check_wrapped
u32 original_frequency = fe->parameters.frequency;
/* are we using autoinversion? */
- autoinversion = ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) &&
+ autoinversion = ((!(fe->frontend->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
(fe->parameters.inversion == INVERSION_AUTO));
/* setup parameters correctly */
@@ -453,7 +390,7 @@ static int dvb_frontend_autotune(struct dvb_frontend_data *fe, int check_wrapped
/* set the frontend itself */
fe->parameters.frequency += fe->lnb_drift + fe->bending;
if (autoinversion) fe->parameters.inversion = fe->inversion;
- dvb_frontend_internal_ioctl (&fe->frontend, FE_SET_FRONTEND, &fe->parameters);
+ if (fe->frontend->ops->set_frontend) fe->frontend->ops->set_frontend(fe->frontend, &fe->parameters);
fe->parameters.frequency = original_frequency;
fe->parameters.inversion = original_inversion;
@@ -489,6 +426,9 @@ static void dvb_frontend_wakeup (struct dvb_frontend_data *fe) {
wake_up_interruptible(&fe->wait_queue);
}
+/*
+ * FIXME: use linux/kthread.h
+ */
static int dvb_frontend_thread (void *data)
{
struct dvb_frontend_data *fe = (struct dvb_frontend_data *) data;
@@ -501,14 +441,14 @@ static int dvb_frontend_thread (void *data)
dprintk ("%s\n", __FUNCTION__);
snprintf (name, sizeof(name), "kdvb-fe-%i",
- fe->frontend.dvb_adapter->num);
+ fe->frontend->dvb->num);
lock_kernel ();
daemonize (name);
sigfillset (&current->blocked);
unlock_kernel ();
- dvb_call_frontend_notifiers (fe, 0);
+ fe->status = 0;
dvb_frontend_init (fe);
fe->wakeup = 0;
@@ -516,11 +456,14 @@ static int dvb_frontend_thread (void *data)
up (&fe->sem); /* is locked when we enter the thread... */
timeout = wait_event_interruptible_timeout(fe->wait_queue,0 != dvb_frontend_should_wakeup (fe), delay);
- if (-ERESTARTSYS == timeout || 0 != dvb_frontend_is_exiting (fe)) {
+ if (0 != dvb_frontend_is_exiting (fe)) {
/* got signal or quitting */
break;
}
+ if (current->flags & PF_FREEZE)
+ refrigerator(PF_FREEZE);
+
if (down_interruptible (&fe->sem))
break;
@@ -535,9 +478,10 @@ static int dvb_frontend_thread (void *data)
if (fe->state & FESTATE_RETUNE) {
s = 0;
} else {
- dvb_frontend_internal_ioctl (&fe->frontend, FE_READ_STATUS, &s);
+ if (fe->frontend->ops->read_status) fe->frontend->ops->read_status(fe->frontend, &s);
if (s != fe->status) {
dvb_frontend_add_event (fe, s);
+ fe->status = s;
}
}
/* if we're not tuned, and we have a lock, move to the TUNED state */
@@ -546,7 +490,7 @@ static int dvb_frontend_thread (void *data)
fe->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */
- if ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) &&
+ if ((!(fe->frontend->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
(fe->parameters.inversion == INVERSION_AUTO)) {
fe->parameters.inversion = fe->inversion;
}
@@ -572,7 +516,7 @@ static int dvb_frontend_thread (void *data)
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fe->state & FESTATE_LOSTLOCK) &&
- (fe->info->caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) {
+ (fe->frontend->ops->info.caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) {
update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
continue;
}
@@ -630,8 +574,11 @@ static int dvb_frontend_thread (void *data)
}
};
- if (dvb_shutdown_timeout)
- dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL);
+ if (dvb_shutdown_timeout) {
+ if (dvb_powerdown_on_sleep)
+ if (fe->frontend->ops->set_voltage) fe->frontend->ops->set_voltage(fe->frontend, SEC_VOLTAGE_OFF);
+ if (fe->frontend->ops->sleep) fe->frontend->ops->sleep(fe->frontend);
+ }
fe->thread_pid = 0;
mb();
@@ -721,12 +668,11 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend_data *fe = dvbdev->priv;
- struct dvb_frontend_tune_settings fetunesettings;
- int err = 0;
+ int err = -EOPNOTSUPP;
dprintk ("%s\n", __FUNCTION__);
- if (!fe || !fe->frontend.ioctl || fe->exit)
+ if (!fe || fe->exit)
return -ENODEV;
if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
@@ -738,18 +684,103 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
return -ERESTARTSYS;
switch (cmd) {
+ case FE_GET_INFO: {
+ struct dvb_frontend_info* info = (struct dvb_frontend_info*) parg;
+ memcpy(info, &fe->frontend->ops->info, sizeof(struct dvb_frontend_info));
+
+ /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
+ * do it, it is done for it. */
+ info->caps |= FE_CAN_INVERSION_AUTO;
+ err = 0;
+ break;
+ }
+
+ case FE_READ_STATUS:
+ if (fe->frontend->ops->read_status)
+ err = fe->frontend->ops->read_status(fe->frontend, (fe_status_t*) parg);
+ break;
+
+ case FE_READ_BER:
+ if (fe->frontend->ops->read_ber)
+ err = fe->frontend->ops->read_ber(fe->frontend, (__u32*) parg);
+ break;
+
+ case FE_READ_SIGNAL_STRENGTH:
+ if (fe->frontend->ops->read_signal_strength)
+ err = fe->frontend->ops->read_signal_strength(fe->frontend, (__u16*) parg);
+ break;
+
+ case FE_READ_SNR:
+ if (fe->frontend->ops->read_snr)
+ err = fe->frontend->ops->read_snr(fe->frontend, (__u16*) parg);
+ break;
+
+ case FE_READ_UNCORRECTED_BLOCKS:
+ if (fe->frontend->ops->read_ucblocks)
+ err = fe->frontend->ops->read_ucblocks(fe->frontend, (__u32*) parg);
+ break;
+
+
+ case FE_DISEQC_RESET_OVERLOAD:
+ if (fe->frontend->ops->diseqc_reset_overload) {
+ err = fe->frontend->ops->diseqc_reset_overload(fe->frontend);
+ fe->state = FESTATE_DISEQC;
+ fe->status = 0;
+ }
+ break;
+
case FE_DISEQC_SEND_MASTER_CMD:
+ if (fe->frontend->ops->diseqc_send_master_cmd) {
+ err = fe->frontend->ops->diseqc_send_master_cmd(fe->frontend, (struct dvb_diseqc_master_cmd*) parg);
+ fe->state = FESTATE_DISEQC;
+ fe->status = 0;
+ }
+ break;
+
case FE_DISEQC_SEND_BURST:
+ if (fe->frontend->ops->diseqc_send_burst) {
+ err = fe->frontend->ops->diseqc_send_burst(fe->frontend, (fe_sec_mini_cmd_t) parg);
+ fe->state = FESTATE_DISEQC;
+ fe->status = 0;
+ }
+ break;
+
case FE_SET_TONE:
+ if (fe->frontend->ops->set_tone) {
+ err = fe->frontend->ops->set_tone(fe->frontend, (fe_sec_tone_mode_t) parg);
+ fe->state = FESTATE_DISEQC;
+ fe->status = 0;
+ }
+ break;
+
case FE_SET_VOLTAGE:
- if (fe->status)
- dvb_call_frontend_notifiers (fe, 0);
- dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);
- fe->state = FESTATE_DISEQC;
+ if (fe->frontend->ops->set_voltage) {
+ err = fe->frontend->ops->set_voltage(fe->frontend, (fe_sec_voltage_t) parg);
+ fe->state = FESTATE_DISEQC;
+ fe->status = 0;
+ }
break;
- case FE_SET_FRONTEND:
- fe->state = FESTATE_RETUNE;
+ case FE_DISHNETWORK_SEND_LEGACY_CMD:
+ if (fe->frontend->ops->dishnetwork_send_legacy_command) {
+ err = fe->frontend->ops->dishnetwork_send_legacy_command(fe->frontend, (unsigned int) parg);
+ fe->state = FESTATE_DISEQC;
+ fe->status = 0;
+ }
+ break;
+
+ case FE_DISEQC_RECV_SLAVE_REPLY:
+ if (fe->frontend->ops->diseqc_recv_slave_reply)
+ err = fe->frontend->ops->diseqc_recv_slave_reply(fe->frontend, (struct dvb_diseqc_slave_reply*) parg);
+ break;
+
+ case FE_ENABLE_HIGH_LNB_VOLTAGE:
+ if (fe->frontend->ops->enable_high_lnb_voltage);
+ err = fe->frontend->ops->enable_high_lnb_voltage(fe->frontend, (int) parg);
+ break;
+
+ case FE_SET_FRONTEND: {
+ struct dvb_frontend_tune_settings fetunesettings;
memcpy (&fe->parameters, parg,
sizeof (struct dvb_frontend_parameters));
@@ -763,7 +794,7 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
fe->parameters.inversion = INVERSION_AUTO;
fetunesettings.parameters.inversion = INVERSION_AUTO;
}
- if (fe->info->type == FE_OFDM) {
+ if (fe->frontend->ops->info.type == FE_OFDM) {
/* without hierachical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */
if (fe->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
@@ -772,14 +803,13 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
}
/* get frontend-specific tuning settings */
- if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS,
- &fetunesettings) == 0) {
+ if (fe->frontend->ops->get_tune_settings && (fe->frontend->ops->get_tune_settings(fe->frontend, &fetunesettings) == 0)) {
fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
fe->max_drift = fetunesettings.max_drift;
fe->step_size = fetunesettings.step_size;
} else {
/* default values */
- switch(fe->info->type) {
+ switch(fe->frontend->ops->info.type) {
case FE_QPSK:
fe->min_delay = HZ/20;
fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000;
@@ -794,8 +824,8 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
case FE_OFDM:
fe->min_delay = HZ/20;
- fe->step_size = fe->info->frequency_stepsize * 2;
- fe->max_drift = (fe->info->frequency_stepsize * 2) + 1;
+ fe->step_size = fe->frontend->ops->info.frequency_stepsize * 2;
+ fe->max_drift = (fe->frontend->ops->info.frequency_stepsize * 2) + 1;
break;
case FE_ATSC:
printk("dvb-core: FE_ATSC not handled yet.\n");
@@ -806,33 +836,27 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
fe->min_delay = (dvb_override_tune_delay * HZ) / 1000;
}
+ fe->state = FESTATE_RETUNE;
dvb_frontend_wakeup(fe);
dvb_frontend_add_event (fe, 0);
+ fe->status = 0;
+ err = 0;
break;
+ }
case FE_GET_EVENT:
err = dvb_frontend_get_event (fe, parg, file->f_flags);
break;
case FE_GET_FRONTEND:
- memcpy (parg, &fe->parameters,
- sizeof (struct dvb_frontend_parameters));
- /* fall-through... */
- default:
- err = dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);
+ if (fe->frontend->ops->get_frontend) {
+ memcpy (parg, &fe->parameters, sizeof (struct dvb_frontend_parameters));
+ err = fe->frontend->ops->get_frontend(fe->frontend, (struct dvb_frontend_parameters*) parg);
+ }
+ break;
};
up (&fe->sem);
- if (err < 0)
- return err;
-
- /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
- * do it, it is done for it. */
- if ((cmd == FE_GET_INFO) && (err == 0)) {
- struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) parg;
- tmp->caps |= FE_CAN_INVERSION_AUTO;
- }
-
return err;
}
@@ -873,11 +897,6 @@ static int dvb_frontend_open (struct inode *inode, struct file *file)
fe->events.eventr = fe->events.eventw = 0;
}
- if (!ret && fe->module) {
- if (!try_module_get(fe->module))
- return -EINVAL;
- }
-
return ret;
}
@@ -886,206 +905,13 @@ static int dvb_frontend_release (struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend_data *fe = dvbdev->priv;
- int ret = 0;
dprintk ("%s\n", __FUNCTION__);
if ((file->f_flags & O_ACCMODE) != O_RDONLY)
fe->release_jiffies = jiffies;
- ret = dvb_generic_release (inode, file);
-
- if (!ret && fe->module)
- module_put(fe->module);
-
- return ret;
-}
-
-
-
-int
-dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
- int (*before_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- int (*after_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- void *before_after_data)
-{
- struct dvb_frontend_ioctl_data *ioctl;
- struct list_head *entry;
-
- dprintk ("%s\n", __FUNCTION__);
-
- if (down_interruptible (&frontend_mutex))
- return -ERESTARTSYS;
-
- ioctl = kmalloc (sizeof(struct dvb_frontend_ioctl_data), GFP_KERNEL);
-
- if (!ioctl) {
- up (&frontend_mutex);
- return -ENOMEM;
- }
-
- ioctl->adapter = adapter;
- ioctl->before_ioctl = before_ioctl;
- ioctl->after_ioctl = after_ioctl;
- ioctl->before_after_data = before_after_data;
-
- list_add_tail (&ioctl->list_head, &frontend_ioctl_list);
-
- list_for_each (entry, &frontend_list) {
- struct dvb_frontend_data *fe;
-
- fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
- if (fe->frontend.dvb_adapter == adapter &&
- fe->frontend.before_ioctl == NULL &&
- fe->frontend.after_ioctl == NULL)
- {
- fe->frontend.before_ioctl = before_ioctl;
- fe->frontend.after_ioctl = after_ioctl;
- fe->frontend.before_after_data = before_after_data;
- }
- }
-
- up (&frontend_mutex);
-
- return 0;
-}
-
-
-void
-dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
- int (*before_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- int (*after_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg))
-{
- struct list_head *entry, *n;
-
- dprintk ("%s\n", __FUNCTION__);
-
- down (&frontend_mutex);
-
- list_for_each (entry, &frontend_list) {
- struct dvb_frontend_data *fe;
-
- fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
- if (fe->frontend.dvb_adapter == adapter &&
- fe->frontend.before_ioctl == before_ioctl &&
- fe->frontend.after_ioctl == after_ioctl)
- {
- fe->frontend.before_ioctl = NULL;
- fe->frontend.after_ioctl = NULL;
-
- }
- }
-
- list_for_each_safe (entry, n, &frontend_ioctl_list) {
- struct dvb_frontend_ioctl_data *ioctl;
-
- ioctl = list_entry (entry, struct dvb_frontend_ioctl_data, list_head);
-
- if (ioctl->adapter == adapter &&
- ioctl->before_ioctl == before_ioctl &&
- ioctl->after_ioctl == after_ioctl)
- {
- list_del (&ioctl->list_head);
- kfree (ioctl);
-
- break;
- }
- }
-
- up (&frontend_mutex);
-}
-
-
-int
-dvb_add_frontend_notifier (struct dvb_adapter *adapter,
- void (*callback) (fe_status_t s, void *data),
- void *data)
-{
- struct dvb_frontend_notifier_data *notifier;
- struct list_head *entry;
-
- dprintk ("%s\n", __FUNCTION__);
-
- if (down_interruptible (&frontend_mutex))
- return -ERESTARTSYS;
-
- notifier = kmalloc (sizeof(struct dvb_frontend_notifier_data), GFP_KERNEL);
-
- if (!notifier) {
- up (&frontend_mutex);
- return -ENOMEM;
- }
-
- notifier->adapter = adapter;
- notifier->callback = callback;
- notifier->data = data;
-
- list_add_tail (&notifier->list_head, &frontend_notifier_list);
-
- list_for_each (entry, &frontend_list) {
- struct dvb_frontend_data *fe;
-
- fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
- if (fe->frontend.dvb_adapter == adapter &&
- fe->frontend.notifier_callback == NULL)
- {
- fe->frontend.notifier_callback = callback;
- fe->frontend.notifier_data = data;
- }
- }
-
- up (&frontend_mutex);
-
- return 0;
-}
-
-
-void
-dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
- void (*callback) (fe_status_t s, void *data))
-{
- struct list_head *entry, *n;
-
- dprintk ("%s\n", __FUNCTION__);
-
- down (&frontend_mutex);
-
- list_for_each (entry, &frontend_list) {
- struct dvb_frontend_data *fe;
-
- fe = list_entry (entry, struct dvb_frontend_data, list_head);
-
- if (fe->frontend.dvb_adapter == adapter &&
- fe->frontend.notifier_callback == callback)
- {
- fe->frontend.notifier_callback = NULL;
-
- }
- }
-
- list_for_each_safe (entry, n, &frontend_notifier_list) {
- struct dvb_frontend_notifier_data *notifier;
-
- notifier = list_entry (entry, struct dvb_frontend_notifier_data, list_head);
-
- if (notifier->adapter == adapter &&
- notifier->callback == callback)
- {
- list_del (&notifier->list_head);
- kfree (notifier);
-
- break;
- }
- }
-
- up (&frontend_mutex);
+ return dvb_generic_release (inode, file);
}
@@ -1097,15 +923,10 @@ static struct file_operations dvb_frontend_fops = {
.release = dvb_frontend_release
};
-int
-dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- struct dvb_adapter *dvb_adapter,
- void *data,
- struct dvb_frontend_info *info,
- struct module *module)
+
+int dvb_register_frontend(struct dvb_adapter* dvb,
+ struct dvb_frontend* frontend)
{
- struct list_head *entry;
struct dvb_frontend_data *fe;
static const struct dvb_device dvbdev_template = {
.users = ~0,
@@ -1133,62 +954,29 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
init_MUTEX (&fe->events.sem);
fe->events.eventw = fe->events.eventr = 0;
fe->events.overflow = 0;
- fe->module = module;
- fe->frontend.ioctl = ioctl;
- fe->frontend.dvb_adapter = dvb_adapter;
- fe->frontend.data = data;
- fe->info = info;
- fe->inversion = INVERSION_OFF;
+ fe->frontend = frontend;
+ fe->frontend->dvb = dvb;
- list_for_each (entry, &frontend_ioctl_list) {
- struct dvb_frontend_ioctl_data *ioctl;
-
- ioctl = list_entry (entry,
- struct dvb_frontend_ioctl_data,
- list_head);
-
- if (ioctl->adapter == dvb_adapter) {
- fe->frontend.before_ioctl = ioctl->before_ioctl;
- fe->frontend.after_ioctl = ioctl->after_ioctl;
- fe->frontend.before_after_data = ioctl->before_after_data;
- break;
- }
- }
-
- list_for_each (entry, &frontend_notifier_list) {
- struct dvb_frontend_notifier_data *notifier;
-
- notifier = list_entry (entry,
- struct dvb_frontend_notifier_data,
- list_head);
-
- if (notifier->adapter == dvb_adapter) {
- fe->frontend.notifier_callback = notifier->callback;
- fe->frontend.notifier_data = notifier->data;
- break;
- }
- }
+ fe->inversion = INVERSION_OFF;
list_add_tail (&fe->list_head, &frontend_list);
printk ("DVB: registering frontend %i (%s)...\n",
- fe->frontend.dvb_adapter->num,
- fe->info->name);
+ fe->frontend->dvb->num,
+ fe->frontend->ops->info.name);
- dvb_register_device (dvb_adapter, &fe->dvbdev, &dvbdev_template,
+ dvb_register_device (fe->frontend->dvb, &fe->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND);
- if ((info->caps & FE_NEEDS_BENDING) || (dvb_override_frequency_bending == 2))
+ if ((fe->frontend->ops->info.caps & FE_NEEDS_BENDING) || (dvb_override_frequency_bending == 2))
do_frequency_bending = 1;
up (&frontend_mutex);
return 0;
}
-int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- struct dvb_adapter *dvb_adapter)
+int dvb_unregister_frontend (struct dvb_frontend* frontend)
{
struct list_head *entry, *n;
@@ -1201,11 +989,16 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
fe = list_entry (entry, struct dvb_frontend_data, list_head);
- if (fe->frontend.ioctl == ioctl && fe->frontend.dvb_adapter == dvb_adapter) {
+ if (fe->frontend == frontend) {
dvb_unregister_device (fe->dvbdev);
list_del (entry);
up (&frontend_mutex);
dvb_frontend_stop (fe);
+ if (fe->frontend->ops->release) {
+ fe->frontend->ops->release(fe->frontend);
+ } else {
+ printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->frontend->ops->info.name);
+ }
kfree (fe);
return 0;
}
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
index acfd1ddf3..1d19c267a 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -41,8 +41,8 @@
#include "dvbdev.h"
/* FIXME: Move to i2c-id.h */
-#define I2C_DRIVERID_DVBFE_ALPS_TDLB7 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_ALPS_TDMB7 I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_SP8870 I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_CX22700 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_CX22702 I2C_DRIVERID_EXP2
@@ -59,22 +59,8 @@
#define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2
+#define I2C_DRIVERID_DVBFE_TDA80XX I2C_DRIVERID_EXP2
-/**
- * when before_ioctl is registered and returns value 0, ioctl and after_ioctl
- * are not executed.
- */
-
-struct dvb_frontend {
- int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
- int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
- int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
- void (*notifier_callback) (fe_status_t s, void *data);
- struct dvb_adapter *dvb_adapter;
- void *before_after_data; /* can be used by hardware module... */
- void *notifier_data; /* can be used by hardware module... */
- void *data; /* can be used by hardware module... */
-};
struct dvb_frontend_tune_settings {
int min_delay_ms;
@@ -83,67 +69,47 @@ struct dvb_frontend_tune_settings {
struct dvb_frontend_parameters parameters;
};
+struct dvb_frontend;
-/**
- * private frontend command ioctl's.
- * keep them in sync with the public ones defined in linux/dvb/frontend.h
- *
- * FE_SLEEP. Ioctl used to put frontend into a low power mode.
- * FE_INIT. Ioctl used to initialise the frontend.
- * FE_GET_TUNE_SETTINGS. Get the frontend-specific tuning loop settings for the supplied set of parameters.
- */
-#define FE_SLEEP _IO ('v', 80)
-#define FE_INIT _IO ('v', 81)
-#define FE_GET_TUNE_SETTINGS _IOWR('v', 83, struct dvb_frontend_tune_settings)
-#define FE_REGISTER _IO ('v', 84)
-#define FE_UNREGISTER _IO ('v', 85)
-
-extern int
-dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- struct dvb_adapter *dvb_adapter,
- void *data,
- struct dvb_frontend_info *info,
- struct module *module);
-
-extern int
-dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- struct dvb_adapter *dvb_adapter);
-
-
-/**
- * Add special ioctl code performed before and after the main ioctl
- * to all frontend devices on the specified DVB adapter.
- * This is necessairy because the 22kHz/13V-18V/DiSEqC stuff depends
- * heavily on the hardware around the frontend, the same tuner can create
- * these signals on about a million different ways...
- *
- * Return value: number of frontends where the ioctl's were applied.
- */
-extern int
-dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
- int (*before_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- int (*after_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- void *before_after_data);
-
-
-extern void
-dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
- int (*before_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg),
- int (*after_ioctl) (struct dvb_frontend *frontend,
- unsigned int cmd, void *arg));
-
-extern int
-dvb_add_frontend_notifier (struct dvb_adapter *adapter,
- void (*callback) (fe_status_t s, void *data),
- void *data);
-extern void
-dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
- void (*callback) (fe_status_t s, void *data));
+struct dvb_frontend_ops {
-#endif
+ struct dvb_frontend_info info;
+
+ void (*release)(struct dvb_frontend* fe);
+
+ int (*init)(struct dvb_frontend* fe);
+ int (*sleep)(struct dvb_frontend* fe);
+
+ int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
+ int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
+ int (*read_ber)(struct dvb_frontend* fe, u32* ber);
+ int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
+ int (*read_snr)(struct dvb_frontend* fe, u16* snr);
+ int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
+
+ int (*diseqc_reset_overload)(struct dvb_frontend* fe);
+ int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+ int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
+ int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+ int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+ int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+ int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg);
+ int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+};
+
+struct dvb_frontend {
+
+ struct dvb_frontend_ops* ops;
+ struct dvb_adapter *dvb;
+ void* demodulator_priv;
+};
+
+extern int dvb_register_frontend(struct dvb_adapter* dvb,
+ struct dvb_frontend* fe);
+
+extern int dvb_unregister_frontend(struct dvb_frontend* fe);
+
+#endif
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_ksyms.c b/linux/drivers/media/dvb/dvb-core/dvb_ksyms.c
index 553200e9e..b1841e46c 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_ksyms.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_ksyms.c
@@ -25,10 +25,6 @@ EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
EXPORT_SYMBOL(dvb_register_frontend);
EXPORT_SYMBOL(dvb_unregister_frontend);
-EXPORT_SYMBOL(dvb_add_frontend_ioctls);
-EXPORT_SYMBOL(dvb_remove_frontend_ioctls);
-EXPORT_SYMBOL(dvb_add_frontend_notifier);
-EXPORT_SYMBOL(dvb_remove_frontend_notifier);
EXPORT_SYMBOL(dvb_net_init);
EXPORT_SYMBOL(dvb_net_release);
diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.h b/linux/drivers/media/dvb/dvb-core/dvbdev.h
index ad386e57d..ef1f5f9d9 100644
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h
@@ -49,6 +49,7 @@ struct dvb_adapter {
struct list_head device_list;
const char *name;
u8 proposed_mac [6];
+ void* priv;
struct module *module;
};
diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig
index 4ea2a897e..9cb9534eb 100644
--- a/linux/drivers/media/dvb/frontends/Kconfig
+++ b/linux/drivers/media/dvb/frontends/Kconfig
@@ -1,3 +1,6 @@
+menu "Customise DVB Frontends"
+ depends on DVB_CORE
+
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
@@ -7,32 +10,23 @@ config DVB_STV0299
help
A DVB-S tuner module. Say Y when you want to support this frontend.
- Some examples are the Alps BSRU6, the Philips SU1278 and
- the LG TDQB-S00x.
-
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
config DVB_CX24110
- tristate "Connexant CX24110 based"
+ tristate "Conexant CX24110 based"
depends on DVB_CORE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
-config DVB_GRUNDIG_29504_491
- tristate "Grundig 29504-491 based"
+config DVB_TDA8083
+ tristate "Philips TDA8083 based"
depends on DVB_CORE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
+config DVB_TDA80XX
+ tristate "Philips TDA8044 or TDA8083 based"
+ depends on DVB_CORE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_MT312
tristate "Zarlink MT312 based"
@@ -40,81 +34,53 @@ config DVB_MT312
help
A DVB-S tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
config DVB_VES1X93
tristate "VLSI VES1893 or VES1993 based"
depends on DVB_CORE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
-config DVB_SP887X
- tristate "Microtune sp887x based (i.e. Microtune DTF7072)"
+config DVB_SP8870
+ tristate "Spase sp8870 based"
depends on DVB_CORE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
This driver needs external firmware. Please use the command
- "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
download/extract it, and then copy it to /usr/lib/hotplug/firmware.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
-config DVB_ALPS_TDLB7
- tristate "Alps TDLB7 based"
- depends on DVB_CORE
- help
- A DVB-T tuner module. Say Y when you want to support this frontend.
+config DVB_SP887X
+ tristate "Spase sp887x based"
+ depends on DVB_CORE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
This driver needs external firmware. Please use the command
- "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
download/extract it, and then copy it to /usr/lib/hotplug/firmware.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
-config DVB_ALPS_TDMB7
- tristate "Alps TDMB7 based"
+config DVB_CX22700
+ tristate "Conexant CX22700 based"
depends on DVB_CORE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
config DVB_CX22702
tristate "Conexant cx22702 demodulator (OFDM)"
depends on DVB_CORE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
-
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-config DVB_GRUNDIG_29504_401
- tristate "Grundig 29504-401 based"
+config DVB_L64781
+ tristate "LSI L64781"
depends on DVB_CORE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
depends on DVB_CORE
@@ -126,44 +92,24 @@ config DVB_TDA1004X
"<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
download/extract them, and then copy them to /usr/lib/hotplug/firmware.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
config DVB_NXT6000
tristate "NxtWave Communications NXT6000 based"
depends on DVB_CORE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
config DVB_MT352
tristate "Zarlink MT352 based"
depends on DVB_CORE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
config DVB_DIB3000MB
tristate "DiBcom 3000-MB"
depends on DVB_CORE
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
-
- Used on USB-powered devices. You should also say Y to DVB_DIBUSB
- (DiBcom USB DVB-T Adapter) to support the actual device,
- this is "only" the frontend/tuner.
-
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
comment "DVB-C (cable) frontends"
depends on DVB_CORE
@@ -174,28 +120,22 @@ config DVB_ATMEL_AT76C651
help
A DVB-C tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
config DVB_VES1820
tristate "VLSI VES1820 based"
depends on DVB_CORE
help
A DVB-C tuner module. Say Y when you want to support this frontend.
- If you don't know what tuner module is soldered on your
- DVB adapter simply enable all supported frontends, the
- right one will get autodetected.
-
-comment "Misc. Frontend Modules"
+config DVB_TDA10021
+ tristate "Philips TDA10021 based"
depends on DVB_CORE
+ help
+ A DVB-C tuner module. Say Y when you want to support this frontend.
-config DVB_TWINHAN_DST
- tristate "Twinhan DST based DVB-S/-T frontend"
- depends on DVB_CORE && DVB_BT8XX
+config DVB_STV0297
+ tristate "ST STV0297 based"
+ depends on DVB_CORE
help
- Used in such cards as the VP-1020/1030, Twinhan DST,
- VVmer TV@SAT. Say Y when you want to support frontends
- using this asic.
+ A DVB-C tuner module. Say Y when you want to support this frontend.
+endmenu
diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile
index 9a0b7f44a..310728ebc 100644
--- a/linux/drivers/media/dvb/frontends/Makefile
+++ b/linux/drivers/media/dvb/frontends/Makefile
@@ -4,14 +4,13 @@
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
-obj-$(CONFIG_DVB_TWINHAN_DST) += dst.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
-obj-$(CONFIG_DVB_ALPS_TDLB7) += alps_tdlb7.o
-obj-$(CONFIG_DVB_ALPS_TDMB7) += alps_tdmb7.o
+obj-$(CONFIG_DVB_SP8870) += sp8870.o
+obj-$(CONFIG_DVB_CX22700) += cx22700.o
obj-$(CONFIG_DVB_ATMEL_AT76C651) += at76c651.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
-obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o
-obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o
+obj-$(CONFIG_DVB_TDA8083) += tda8083.o
+obj-$(CONFIG_DVB_L64781) += l64781.o
obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
obj-$(CONFIG_DVB_MT312) += mt312.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
@@ -21,4 +20,6 @@ obj-$(CONFIG_DVB_SP887X) += sp887x.o
obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
obj-$(CONFIG_DVB_MT352) += mt352.o
obj-$(CONFIG_DVB_CX22702) += cx22702.o
-
+obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o
+obj-$(CONFIG_DVB_TDA10021) += tda10021.o
+obj-$(CONFIG_DVB_STV0297) += stv0297.o
diff --git a/linux/drivers/media/dvb/frontends/alps_tdlb7.c b/linux/drivers/media/dvb/frontends/alps_tdlb7.c
deleted file mode 100644
index 04b1a8d3c..000000000
--- a/linux/drivers/media/dvb/frontends/alps_tdlb7.c
+++ /dev/null
@@ -1,746 +0,0 @@
-/*
- Driver for Alps TDLB7 Frontend
-
- Copyright (C) 1999 Juergen Peitz
-
- 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.
-
-*/
-/*
- * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
- * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
- */
-#define SP887X_DEFAULT_FIRMWARE "dvb-fe-tdlb7-2.16.fw"
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/delay.h>
-
-#include "dvb_frontend.h"
-
-#define FRONTEND_NAME "dvbfe_alps_tdlb7"
-
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-
-/* firmware size for sp8870 */
-#define SP8870_FIRMWARE_SIZE 16382
-
-/* starting point for firmware in file 'Sc_main.mc' */
-#define SP8870_FIRMWARE_OFFSET 0x0A
-
-static struct dvb_frontend_info tdlb7_info = {
- .name = "Alps TDLB7",
- .type = FE_OFDM,
- .frequency_min = 470000000,
- .frequency_max = 860000000,
- .frequency_stepsize = 166666,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
- FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 |
- FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER
-};
-
-struct tdlb7_state {
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
-};
-
-static int sp8870_writereg (struct i2c_adapter *i2c, u16 reg, u16 data)
-{
- u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
- struct i2c_msg msg = { .addr = 0x71, .flags = 0, .buf = buf, .len = 4 };
- int err;
-
- if ((err = i2c_transfer (i2c, &msg, 1)) != 1) {
- dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static u16 sp8870_readreg (struct i2c_adapter *i2c, u16 reg)
-{
- int ret;
- u8 b0 [] = { reg >> 8 , reg & 0xff };
- u8 b1 [] = { 0, 0 };
- struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
- { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
-
- ret = i2c_transfer (i2c, msg, 2);
-
- if (ret != 2) {
- dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
- return -1;
- }
-
- return (b1[0] << 8 | b1[1]);
-}
-
-static int sp5659_write (struct i2c_adapter *i2c, u8 data [4])
-{
- int ret;
-
- u8 buf_open [] = { 0x206 >> 8, 0x206 & 0xff, 0x001 >> 8, 0x001 & 0xff };
- u8 buf_close [] = { 0x206 >> 8, 0x206 & 0xff, 0x000 >> 8, 0x000 & 0xff };
-
- struct i2c_msg msg[3] = { {.addr = 0x71, .flags = 0, .buf = buf_open, .len = 4 },
- {.addr = 0x60, .flags = 0, .buf = data, .len = 4 },
- {.addr = 0x71, .flags = 0, .buf = buf_close, .len = 4 } };
-
- ret = i2c_transfer (i2c, &msg[0], 3);
-
- if (ret != 3)
- printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
-
- return (ret != 3) ? -EREMOTEIO : 0;
-}
-
-static void sp5659_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
-{
- u32 div = (freq + 36200000) / 166666;
- u8 buf [4];
- int pwr;
-
- if (freq <= 782000000)
- pwr = 1;
- else
- pwr = 2;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x85;
- buf[3] = pwr << 6;
-
- /* open i2c gate for PLL message transmission... */
- sp5659_write (i2c, buf);
-}
-
-static int sp8870_firmware_upload (struct i2c_adapter *i2c, const struct firmware *fw)
-{
- struct i2c_msg msg;
- char *fw_buf = fw->data;
- int fw_pos;
- u8 tx_buf[255];
- int tx_len;
- int err = 0;
-
- dprintk ("%s: ...\n", __FUNCTION__);
-
- if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
- return -EINVAL;
-
- // system controller stop
- sp8870_writereg(i2c, 0x0F00, 0x0000);
-
- // instruction RAM register hiword
- sp8870_writereg(i2c, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
-
- // instruction RAM MWR
- sp8870_writereg(i2c, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
-
- // do firmware upload
- fw_pos = SP8870_FIRMWARE_OFFSET;
- while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
- tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
- // write register 0xCF0A
- tx_buf[0] = 0xCF;
- tx_buf[1] = 0x0A;
- memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
- msg.addr = 0x71;
- msg.flags = 0;
- msg.buf = tx_buf;
- msg.len = tx_len + 2;
- if ((err = i2c_transfer (i2c, &msg, 1)) != 1) {
- printk("%s: firmware upload failed!\n", __FUNCTION__);
- printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
- return err;
- }
- fw_pos += tx_len;
- }
-
- dprintk ("%s: done!\n", __FUNCTION__);
- return 0;
-};
-
-static void sp8870_microcontroller_stop (struct i2c_adapter *i2c)
-{
- sp8870_writereg(i2c, 0x0F08, 0x000);
- sp8870_writereg(i2c, 0x0F09, 0x000);
-
- // microcontroller STOP
- sp8870_writereg(i2c, 0x0F00, 0x000);
-}
-
-static void sp8870_microcontroller_start (struct i2c_adapter *i2c)
-{
- sp8870_writereg(i2c, 0x0F08, 0x000);
- sp8870_writereg(i2c, 0x0F09, 0x000);
-
- // microcontroller START
- sp8870_writereg(i2c, 0x0F00, 0x001);
- // not documented but if we don't read 0x0D01 out here
- // we don't get a correct data valid signal
- sp8870_readreg(i2c, 0x0D01);
-}
-
-static int sp8870_init (struct i2c_adapter *i2c)
-{
- dprintk ("%s\n", __FUNCTION__);
-
- /* enable TS output and interface pins */
- sp8870_writereg(i2c, 0xc18, 0x00d);
-
- // system controller stop
- sp8870_microcontroller_stop(i2c);
-
- // ADC mode
- sp8870_writereg(i2c, 0x0301, 0x0003);
-
- // Reed Solomon parity bytes passed to output
- sp8870_writereg(i2c, 0x0C13, 0x0001);
-
- // MPEG clock is suppressed if no valid data
- sp8870_writereg(i2c, 0x0C14, 0x0001);
-
- /* bit 0x010: enable data valid signal */
- sp8870_writereg(i2c, 0x0D00, 0x010);
- sp8870_writereg(i2c, 0x0D01, 0x000);
-
- return 0;
-}
-
-static int sp8870_read_status (struct i2c_adapter *i2c, fe_status_t * fe_status)
-{
- int status;
- int signal;
-
- *fe_status = 0;
-
- status = sp8870_readreg (i2c, 0x0200);
- if (status < 0)
- return -EIO;
-
- signal = sp8870_readreg (i2c, 0x0303);
- if (signal < 0)
- return -EIO;
-
- if (signal > 0x0F)
- *fe_status |= FE_HAS_SIGNAL;
- if (status & 0x08)
- *fe_status |= FE_HAS_SYNC;
- if (status & 0x04)
- *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
-
- return 0;
-}
-
-static int sp8870_read_ber (struct i2c_adapter *i2c, u32 * ber)
-{
- int ret;
- u32 tmp;
-
- *ber = 0;
-
- ret = sp8870_readreg(i2c, 0xC08);
- if (ret < 0)
- return -EIO;
-
- tmp = ret & 0x3F;
-
- ret = sp8870_readreg(i2c, 0xC07);
- if (ret < 0)
- return -EIO;
-
- tmp = ret << 6;
-
- if (tmp >= 0x3FFF0)
- tmp = ~0;
-
- *ber = tmp;
-
- return 0;
-}
-
-static int sp8870_read_signal_strength (struct i2c_adapter *i2c, u16 * signal)
-{
- int ret;
- u16 tmp;
-
- *signal = 0;
-
- ret = sp8870_readreg (i2c, 0x306);
- if (ret < 0)
- return -EIO;
-
- tmp = ret << 8;
-
- ret = sp8870_readreg (i2c, 0x303);
- if (ret < 0)
- return -EIO;
-
- tmp |= ret;
-
- if (tmp)
- *signal = 0xFFFF - tmp;
-
- return 0;
-}
-
-static int sp8870_read_snr(struct i2c_adapter *i2c, u32* snr)
-{
- *snr = 0;
- return -EOPNOTSUPP;
-}
-
-static int sp8870_read_uncorrected_blocks (struct i2c_adapter *i2c, u32* ublocks)
-{
- int ret;
-
- *ublocks = 0;
-
- ret = sp8870_readreg(i2c, 0xC0C);
- if (ret < 0)
- return -EIO;
-
- if (ret == 0xFFFF)
- ret = ~0;
-
- *ublocks = ret;
-
- return 0;
-}
-
-static int sp8870_read_data_valid_signal(struct i2c_adapter *i2c)
-{
- return (sp8870_readreg(i2c, 0x0D02) > 0);
-}
-
-static
-int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
-{
- int known_parameters = 1;
-
- *reg0xc05 = 0x000;
-
- switch (p->u.ofdm.constellation) {
- case QPSK:
- break;
- case QAM_16:
- *reg0xc05 |= (1 << 10);
- break;
- case QAM_64:
- *reg0xc05 |= (2 << 10);
- break;
- case QAM_AUTO:
- known_parameters = 0;
- break;
- default:
- return -EINVAL;
- };
-
- switch (p->u.ofdm.hierarchy_information) {
- case HIERARCHY_NONE:
- break;
- case HIERARCHY_1:
- *reg0xc05 |= (1 << 7);
- break;
- case HIERARCHY_2:
- *reg0xc05 |= (2 << 7);
- break;
- case HIERARCHY_4:
- *reg0xc05 |= (3 << 7);
- break;
- case HIERARCHY_AUTO:
- known_parameters = 0;
- break;
- default:
- return -EINVAL;
- };
-
- switch (p->u.ofdm.code_rate_HP) {
- case FEC_1_2:
- break;
- case FEC_2_3:
- *reg0xc05 |= (1 << 3);
- break;
- case FEC_3_4:
- *reg0xc05 |= (2 << 3);
- break;
- case FEC_5_6:
- *reg0xc05 |= (3 << 3);
- break;
- case FEC_7_8:
- *reg0xc05 |= (4 << 3);
- break;
- case FEC_AUTO:
- known_parameters = 0;
- break;
- default:
- return -EINVAL;
- };
-
- if (known_parameters)
- *reg0xc05 |= (2 << 1); /* use specified parameters */
- else
- *reg0xc05 |= (1 << 1); /* enable autoprobing */
-
- return 0;
-}
-
-static int sp8870_set_frontend_parameters (struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *p)
-{
- int err;
- u16 reg0xc05;
-
- if ((err = configure_reg0xc05(p, &reg0xc05)))
- return err;
-
- // system controller stop
- sp8870_microcontroller_stop(i2c);
-
- // set tuner parameters
- sp5659_set_tv_freq (i2c, p->frequency);
-
- // sample rate correction bit [23..17]
- sp8870_writereg(i2c, 0x0319, 0x000A);
-
- // sample rate correction bit [16..0]
- sp8870_writereg(i2c, 0x031A, 0x0AAB);
-
- // integer carrier offset
- sp8870_writereg(i2c, 0x0309, 0x0400);
-
- // fractional carrier offset
- sp8870_writereg(i2c, 0x030A, 0x0000);
-
- // filter for 6/7/8 Mhz channel
- if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
- sp8870_writereg(i2c, 0x0311, 0x0002);
- else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
- sp8870_writereg(i2c, 0x0311, 0x0001);
- else
- sp8870_writereg(i2c, 0x0311, 0x0000);
-
- // scan order: 2k first = 0x0000, 8k first = 0x0001
- if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
- sp8870_writereg(i2c, 0x0338, 0x0000);
- else
- sp8870_writereg(i2c, 0x0338, 0x0001);
-
- sp8870_writereg(i2c, 0xc05, reg0xc05);
-
- // read status reg in order to clear pending irqs
- sp8870_readreg(i2c, 0x200);
-
- // system controller start
- sp8870_microcontroller_start(i2c);
-
- return 0;
-}
-
-// number of trials to recover from lockup
-#define MAXTRIALS 5
-// maximum checks for data valid signal
-#define MAXCHECKS 100
-
-// only for debugging: counter for detected lockups
-static int lockups = 0;
-// only for debugging: counter for channel switches
-static int switches = 0;
-
-static int sp8870_set_frontend (struct i2c_adapter *i2c, struct dvb_frontend_parameters *p)
-{
- /*
- The firmware of the sp8870 sometimes locks up after setting frontend parameters.
- We try to detect this by checking the data valid signal.
- If it is not set after MAXCHECKS we try to recover the lockup by setting
- the frontend parameters again.
- */
-
- int err = 0;
- int valid = 0;
- int trials = 0;
- int check_count = 0;
-
- dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency);
-
- for (trials = 1; trials <= MAXTRIALS; trials++) {
-
- if ((err = sp8870_set_frontend_parameters(i2c, p)))
- return err;
-
- for (check_count = 0; check_count < MAXCHECKS; check_count++) {
-// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
- valid = sp8870_read_data_valid_signal(i2c);
- if (valid) {
- dprintk("%s: delay = %i usec\n",
- __FUNCTION__, check_count * 10);
- break;
- }
- udelay(10);
- }
- if (valid)
- break;
- }
-
- if (!valid) {
- printk("%s: firmware crash!!!!!!\n", __FUNCTION__);
- return -EIO;
- }
-
- if (debug) {
- if (valid) {
- if (trials > 1) {
- printk("%s: firmware lockup!!!\n", __FUNCTION__);
- printk("%s: recovered after %i trial(s))\n", __FUNCTION__, trials - 1);
- lockups++;
- }
- }
- switches++;
- printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups);
- }
-
- return 0;
-}
-
-static int sp8870_sleep(struct i2c_adapter *i2c)
-{
- // tristate TS output and disable interface pins
- return sp8870_writereg(i2c, 0xC18, 0x000);
-}
-
-static int sp8870_wake_up(struct i2c_adapter *i2c)
-{
- // enable TS output and interface pins
- return sp8870_writereg(i2c, 0xC18, 0x00D);
-}
-
-static int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct tdlb7_state *state = (struct tdlb7_state *) fe->data;
- struct i2c_adapter *i2c = state->i2c;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, &tdlb7_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- return sp8870_read_status(i2c, (fe_status_t *) arg);
-
- case FE_READ_BER:
- return sp8870_read_ber(i2c, (u32 *) arg);
-
- case FE_READ_SIGNAL_STRENGTH:
- return sp8870_read_signal_strength(i2c, (u16 *) arg);
-
- case FE_READ_SNR: // not supported by hardware?
- return sp8870_read_snr(i2c, (u32 *) arg);
-
- case FE_READ_UNCORRECTED_BLOCKS:
- return sp8870_read_uncorrected_blocks(i2c, (u32 *) arg);
-
- case FE_SET_FRONTEND:
- return sp8870_set_frontend(i2c, (struct dvb_frontend_parameters*) arg);
-
- case FE_GET_FRONTEND: // FIXME: read known values back from Hardware...
- return -EOPNOTSUPP;
-
- case FE_SLEEP:
- return sp8870_sleep(i2c);
-
- case FE_INIT:
- sp8870_wake_up(i2c);
- if (fe->data == NULL) { // first time initialisation...
- fe->data = (void*) ~0;
- sp8870_init (i2c);
- }
- break;
-
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
- fesettings->min_delay_ms = 150;
- fesettings->step_size = 166667;
- fesettings->max_drift = 166667*2;
- return 0;
- }
-
- default:
- return -EOPNOTSUPP;
- };
-
- return 0;
-}
-
-static struct i2c_client client_template;
-
-static int attach_adapter(struct i2c_adapter *adapter)
-{
- struct i2c_client *client;
- struct tdlb7_state *state;
- const struct firmware *fw;
- int ret;
-
- u8 b0 [] = { 0x02 , 0x00 };
- u8 b1 [] = { 0, 0 };
- struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 },
- { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
-
- dprintk ("%s\n", __FUNCTION__);
-
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- return -ENOMEM;
- }
-
- if (NULL == (state = kmalloc(sizeof(struct tdlb7_state), GFP_KERNEL))) {
- kfree(client);
- return -ENOMEM;
- }
- state->i2c = adapter;
-
- if (i2c_transfer (adapter, msg, 2) != 2) {
- kfree(state);
- kfree(client);
- return -ENODEV;
- }
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- i2c_set_clientdata(client, (void*)state);
-
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(client);
- kfree(state);
- return ret;
- }
-
- /* request the firmware, this will block until someone uploads it */
- printk("tdlb7: waiting for firmware upload...\n");
- ret = request_firmware(&fw, SP887X_DEFAULT_FIRMWARE, &client->dev);
- if (ret) {
- printk("tdlb7: no firmware upload (timeout or file not found?)\n");
- goto out;
- }
-
- ret = sp8870_firmware_upload(adapter, fw);
- if (ret) {
- printk("tdlb7: writing firmware to device failed\n");
- release_firmware(fw);
- goto out;
- }
-
- ret = dvb_register_frontend(tdlb7_ioctl, state->dvb, state,
- &tdlb7_info, THIS_MODULE);
- if (ret) {
- printk("tdlb7: registering frontend to dvb-core failed.\n");
- release_firmware(fw);
- goto out;
- }
-
- return 0;
-out:
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return ret;
-}
-
-static int detach_client(struct i2c_client *client)
-{
- struct tdlb7_state *state = (struct tdlb7_state*)i2c_get_clientdata(client);
-
- dprintk ("%s\n", __FUNCTION__);
-
- dvb_unregister_frontend (tdlb7_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
- return 0;
-}
-
-static int command (struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct tdlb7_state *state = (struct tdlb7_state*)i2c_get_clientdata(client);
-
- dprintk ("%s\n", __FUNCTION__);
-
- switch (cmd) {
- case FE_REGISTER:
- state->dvb = (struct dvb_adapter*)arg;
- break;
- case FE_UNREGISTER:
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_ALPS_TDLB7,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
-
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
-
-static int __init init_tdlb7(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit exit_tdlb7(void)
-{
- if (i2c_del_driver(&driver))
- printk("tdlb7: driver deregistration failed\n");
-}
-
-module_init(init_tdlb7);
-module_exit(exit_tdlb7);
-
-MODULE_DESCRIPTION("TDLB7 DVB-T Frontend");
-MODULE_AUTHOR("Juergen Peitz");
-MODULE_LICENSE("GPL");
-
diff --git a/linux/drivers/media/dvb/frontends/alps_tdmb7.c b/linux/drivers/media/dvb/frontends/alps_tdmb7.c
deleted file mode 100644
index e07db4bb1..000000000
--- a/linux/drivers/media/dvb/frontends/alps_tdmb7.c
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- Alps TDMB7 DVB OFDM frontend driver
-
- Copyright (C) 2001-2002 Convergence Integrated Media GmbH
- Holger Waechtler <holger@convergence.de>
-
- 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/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#define FRONTEND_NAME "dvbfe_alps_tdmb7"
-
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-
-static struct dvb_frontend_info tdmb7_info = {
- .name = "Alps TDMB7",
- .type = FE_OFDM,
- .frequency_min = 470000000,
- .frequency_max = 860000000,
- .frequency_stepsize = 166667,
-#if 0
- .frequency_tolerance = ???,
- .symbol_rate_min = ???,
- .symbol_rate_max = ???,
- .symbol_rate_tolerance = 500, /* ppm */
- .notifier_delay = 0,
-#endif
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
- FE_CAN_RECOVER
-};
-
-struct tdmb7_state {
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
-};
-
-static u8 init_tab [] = {
- 0x04, 0x10,
- 0x05, 0x09,
- 0x06, 0x00,
- 0x08, 0x04,
- 0x09, 0x00,
- 0x0a, 0x01,
- 0x15, 0x40,
- 0x16, 0x10,
- 0x17, 0x87,
- 0x18, 0x17,
- 0x1a, 0x10,
- 0x25, 0x04,
- 0x2e, 0x00,
- 0x39, 0x00,
- 0x3a, 0x04,
- 0x45, 0x08,
- 0x46, 0x02,
- 0x47, 0x05,
-};
-
-static int cx22700_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
-{
- int ret;
- u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = 0x43, .flags = 0, .buf = buf, .len = 2 };
-
- dprintk ("%s\n", __FUNCTION__);
-
- ret = i2c_transfer (i2c, &msg, 1);
-
- if (ret != 1)
- printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
- __FUNCTION__, reg, data, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-static u8 cx22700_readreg (struct i2c_adapter *i2c, u8 reg)
-{
- int ret;
- u8 b0 [] = { reg };
- u8 b1 [] = { 0 };
- struct i2c_msg msg [] = { { .addr = 0x43, .flags = 0, .buf = b0, .len = 1 },
- { .addr = 0x43, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
- dprintk ("%s\n", __FUNCTION__);
-
- ret = i2c_transfer (i2c, msg, 2);
-
- if (ret != 2)
- printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
- return b1[0];
-}
-
-static int pll_write (struct i2c_adapter *i2c, u8 data [4])
-{
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 };
- int ret;
-
- cx22700_writereg (i2c, 0x0a, 0x00); /* open i2c bus switch */
- ret = i2c_transfer (i2c, &msg, 1);
- cx22700_writereg (i2c, 0x0a, 0x01); /* close i2c bus switch */
-
- if (ret != 1)
- printk("%s: i/o error (addr == 0x%02x, ret == %i)\n", __FUNCTION__, msg.addr, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-/**
- * set up the downconverter frequency divisor for a
- * reference clock comparision frequency of 125 kHz.
- */
-static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
-{
- u32 div = (freq + 36166667) / 166667;
-#if 1 //ALPS_SETTINGS
- u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, ((div >> 10) & 0x60) | 0x85,
- freq < 592000000 ? 0x40 : 0x80 };
-#else
- u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, ((div >> 10) & 0x60) | 0x85,
- freq < 470000000 ? 0x42 : freq < 862000000 ? 0x41 : 0x81 };
-#endif
-
- dprintk ("%s: freq == %i, div == %i\n", __FUNCTION__, (int) freq, (int) div);
-
- return pll_write (i2c, buf);
-}
-
-static int cx22700_init (struct i2c_adapter *i2c)
-{
- int i;
-
- dprintk("cx22700_init: init chip\n");
-
- cx22700_writereg (i2c, 0x00, 0x02); /* soft reset */
- cx22700_writereg (i2c, 0x00, 0x00);
-
- msleep(10);
-
- for (i=0; i<sizeof(init_tab); i+=2)
- cx22700_writereg (i2c, init_tab[i], init_tab[i+1]);
-
- cx22700_writereg (i2c, 0x00, 0x01);
-
- return 0;
-}
-
-static int cx22700_set_inversion (struct i2c_adapter *i2c, int inversion)
-{
- u8 val;
-
- dprintk ("%s\n", __FUNCTION__);
-
- switch (inversion) {
- case INVERSION_AUTO:
- return -EOPNOTSUPP;
- case INVERSION_ON:
- val = cx22700_readreg (i2c, 0x09);
- return cx22700_writereg (i2c, 0x09, val | 0x01);
- case INVERSION_OFF:
- val = cx22700_readreg (i2c, 0x09);
- return cx22700_writereg (i2c, 0x09, val & 0xfe);
- default:
- return -EINVAL;
- }
-}
-
-static int cx22700_set_tps (struct i2c_adapter *i2c, struct dvb_ofdm_parameters *p)
-{
- static const u8 qam_tab [4] = { 0, 1, 0, 2 };
- static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
- u8 val;
-
- dprintk ("%s\n", __FUNCTION__);
-
- if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8)
- return -EINVAL;
-
- if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8)
-
- if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5)
- return -EINVAL;
-
- if (p->guard_interval < GUARD_INTERVAL_1_32 ||
- p->guard_interval > GUARD_INTERVAL_1_4)
- return -EINVAL;
-
- if (p->transmission_mode != TRANSMISSION_MODE_2K &&
- p->transmission_mode != TRANSMISSION_MODE_8K)
- return -EINVAL;
-
- if (p->constellation != QPSK &&
- p->constellation != QAM_16 &&
- p->constellation != QAM_64)
- return -EINVAL;
-
- if (p->hierarchy_information < HIERARCHY_NONE ||
- p->hierarchy_information > HIERARCHY_4)
- return -EINVAL;
-
- if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ)
- return -EINVAL;
-
- if (p->bandwidth == BANDWIDTH_7_MHZ)
- cx22700_writereg (i2c, 0x09, cx22700_readreg (i2c, 0x09 | 0x10));
- else
- cx22700_writereg (i2c, 0x09, cx22700_readreg (i2c, 0x09 & ~0x10));
-
- val = qam_tab[p->constellation - QPSK];
- val |= p->hierarchy_information - HIERARCHY_NONE;
-
- cx22700_writereg (i2c, 0x04, val);
-
- val = fec_tab[p->code_rate_HP - FEC_1_2] << 3;
- val |= fec_tab[p->code_rate_LP - FEC_1_2];
-
- cx22700_writereg (i2c, 0x05, val);
-
- val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2;
- val |= p->transmission_mode - TRANSMISSION_MODE_2K;
-
- cx22700_writereg (i2c, 0x06, val);
-
- cx22700_writereg (i2c, 0x08, 0x04 | 0x02); /* use user tps parameters */
- cx22700_writereg (i2c, 0x08, 0x04); /* restart aquisition */
-
- return 0;
-}
-
-static int cx22700_get_tps (struct i2c_adapter *i2c, struct dvb_ofdm_parameters *p)
-{
- static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
- static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
- FEC_5_6, FEC_7_8 };
- u8 val;
-
- dprintk ("%s\n", __FUNCTION__);
-
- if (!(cx22700_readreg(i2c, 0x07) & 0x20)) /* tps valid? */
- return -EAGAIN;
-
- val = cx22700_readreg (i2c, 0x01);
-
- if ((val & 0x7) > 4)
- p->hierarchy_information = HIERARCHY_AUTO;
- else
- p->hierarchy_information = HIERARCHY_NONE + (val & 0x7);
-
- if (((val >> 3) & 0x3) > 2)
- p->constellation = QAM_AUTO;
- else
- p->constellation = qam_tab[(val >> 3) & 0x3];
-
- val = cx22700_readreg (i2c, 0x02);
-
- if (((val >> 3) & 0x07) > 4)
- p->code_rate_HP = FEC_AUTO;
- else
- p->code_rate_HP = fec_tab[(val >> 3) & 0x07];
-
- if ((val & 0x07) > 4)
- p->code_rate_LP = FEC_AUTO;
- else
- p->code_rate_LP = fec_tab[val & 0x07];
-
- val = cx22700_readreg (i2c, 0x03);
-
- p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3);
- p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1);
-
- return 0;
-}
-
-static int tdmb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct tdmb7_state *state = fe->data;
- struct i2c_adapter *i2c = state->i2c;
-
- dprintk ("%s\n", __FUNCTION__);
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, &tdmb7_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = (fe_status_t *) arg;
- u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9)
- | (cx22700_readreg (i2c, 0x0e) << 1);
- u8 sync = cx22700_readreg (i2c, 0x07);
-
- *status = 0;
-
- if (rs_ber < 0xff00)
- *status |= FE_HAS_SIGNAL;
-
- if (sync & 0x20)
- *status |= FE_HAS_CARRIER;
-
- if (sync & 0x10)
- *status |= FE_HAS_VITERBI;
-
- if (sync & 0x10)
- *status |= FE_HAS_SYNC;
-
- if (*status == 0x0f)
- *status |= FE_HAS_LOCK;
-
- break;
- }
-
- case FE_READ_BER:
- *((u32*) arg) = cx22700_readreg (i2c, 0x0c) & 0x7f;
- cx22700_writereg (i2c, 0x0c, 0x00);
- break;
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9)
- | (cx22700_readreg (i2c, 0x0e) << 1);
- *((u16*) arg) = ~rs_ber;
- break;
- }
- case FE_READ_SNR:
- {
- u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9)
- | (cx22700_readreg (i2c, 0x0e) << 1);
- *((u16*) arg) = ~rs_ber;
- break;
- }
- case FE_READ_UNCORRECTED_BLOCKS:
- *((u32*) arg) = cx22700_readreg (i2c, 0x0f);
- cx22700_writereg (i2c, 0x0f, 0x00);
- break;
-
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
-
- cx22700_writereg (i2c, 0x00, 0x02); /* XXX CHECKME: soft reset*/
- cx22700_writereg (i2c, 0x00, 0x00);
-
- pll_set_tv_freq (i2c, p->frequency);
- cx22700_set_inversion (i2c, p->inversion);
- cx22700_set_tps (i2c, &p->u.ofdm);
- cx22700_writereg (i2c, 0x37, 0x01); /* PAL loop filter off */
- cx22700_writereg (i2c, 0x00, 0x01); /* restart acquire */
- break;
- }
-
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- u8 reg09 = cx22700_readreg (i2c, 0x09);
-
- p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
- return cx22700_get_tps (i2c, &p->u.ofdm);
- }
-
- case FE_INIT:
- return cx22700_init (i2c);
-
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
- fesettings->min_delay_ms = 150;
- fesettings->step_size = 166667;
- fesettings->max_drift = 166667*2;
- return 0;
- }
-
- default:
- return -EOPNOTSUPP;
- };
-
- return 0;
-}
-
-static struct i2c_client client_template;
-
-static int attach_adapter (struct i2c_adapter *adapter)
-{
- struct tdmb7_state *state;
- struct i2c_client *client;
- int ret;
-
- u8 b0 [] = { 0x7 };
- u8 b1 [] = { 0 };
- struct i2c_msg msg [] = { { .addr = 0x43, .flags = 0, .buf = b0, .len = 1 },
- { .addr = 0x43, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
- dprintk ("%s\n", __FUNCTION__);
-
- if (i2c_transfer(adapter, msg, 2) != 2)
- return -ENODEV;
-
- if (NULL == (state = kmalloc(sizeof(struct tdmb7_state), GFP_KERNEL)))
- return -ENOMEM;
-
- state->i2c = adapter;
-
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- kfree(state);
- return -ENOMEM;
- }
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- i2c_set_clientdata(client, state);
-
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(state);
- kfree(client);
- return ret;
- }
-
- BUG_ON(!state->dvb);
-
- ret = dvb_register_frontend (tdmb7_ioctl, state->dvb, state,
- &tdmb7_info, THIS_MODULE);
- if (ret) {
- i2c_detach_client(client);
- kfree(state);
- kfree(client);
- return ret;
- }
-
- return 0;
-}
-
-static int detach_client (struct i2c_client *client)
-{
- struct tdmb7_state *state = i2c_get_clientdata(client);
-
- dprintk ("%s\n", __FUNCTION__);
-
- dvb_unregister_frontend (tdmb7_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
- return 0;
-}
-
-static int command (struct i2c_client *client,
- unsigned int cmd, void *arg)
-{
- struct tdmb7_state *state = i2c_get_clientdata(client);
-
- dprintk("%s\n", __FUNCTION__);
-
- switch (cmd) {
- case FE_REGISTER:
- state->dvb = arg;
- break;
- case FE_UNREGISTER:
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_ALPS_TDMB7,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
-
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
-
-static int __init init_tdmb7 (void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit exit_tdmb7 (void)
-{
- if (i2c_del_driver(&driver))
- printk(KERN_ERR "alps_tdmb7: driver deregistration failed.\n");
-}
-
-module_init (init_tdmb7);
-module_exit (exit_tdmb7);
-
-MODULE_DESCRIPTION("TDMB7 DVB Frontend driver");
-MODULE_AUTHOR("Holger Waechtler");
-MODULE_LICENSE("GPL");
-
diff --git a/linux/drivers/media/dvb/frontends/at76c651.c b/linux/drivers/media/dvb/frontends/at76c651.c
index b96e1274e..812d814dc 100644
--- a/linux/drivers/media/dvb/frontends/at76c651.c
+++ b/linux/drivers/media/dvb/frontends/at76c651.c
@@ -1,6 +1,6 @@
/*
* at76c651.c
- *
+ *
* Atmel DVB-C Frontend Driver (at76c651/tua6010xs)
*
* Copyright (C) 2001 fnbrd <fnbrd@gmx.de>
@@ -24,9 +24,6 @@
* AT76C651
* http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf
* http://www.atmel.com/atmel/acrobat/doc1320.pdf
- *
- * TUA6010XS
- * http://www.infineon.com/cgi/ecrm.dll/ecrm/scripts/public_download.jsp?oid=19512
*/
#include <linux/init.h>
@@ -36,48 +33,34 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/bitops.h>
-
#include "dvb_frontend.h"
+#include "at76c651.h"
-#define FRONTEND_NAME "dvbfe_at76c651"
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
+struct at76c651_state {
-static int debug;
+ struct i2c_adapter* i2c;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+ struct dvb_frontend_ops ops;
+ const struct at76c651_config* config;
-static struct dvb_frontend_info at76c651_info = {
- .name = "Atmel AT76C651B with TUA6010XS",
- .type = FE_QAM,
- .frequency_min = 48250000,
- .frequency_max = 863250000,
- .frequency_stepsize = 62500,
- /*.frequency_tolerance = */ /* FIXME: 12% of SR */
- .symbol_rate_min = 0, /* FIXME */
- .symbol_rate_max = 9360000, /* FIXME */
- .symbol_rate_tolerance = 4000,
- .notifier_delay = 0,
- .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_8_9 | FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 |
- FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER
-};
+ struct dvb_frontend frontend;
-struct at76c651_state {
+ /* revision of the chip */
u8 revision;
+
+ /* last QAM value set */
u8 qam;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
};
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "at76c651: " args); \
+ } while (0)
+
+
#if ! defined(__powerpc__)
static __inline__ int __ilog2(unsigned long x)
{
@@ -93,14 +76,14 @@ static __inline__ int __ilog2(unsigned long x)
}
#endif
-static int at76c651_writereg(struct i2c_adapter *i2c, u8 reg, u8 data)
+static int at76c651_writereg(struct at76c651_state* state, u8 reg, u8 data)
{
int ret;
u8 buf[] = { reg, data };
struct i2c_msg msg =
- { .addr = 0x1a >> 1, .flags = 0, .buf = buf, .len = 2 };
+ { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
- ret = i2c_transfer(i2c, &msg, 1);
+ ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
dprintk("%s: writereg error "
@@ -112,16 +95,16 @@ static int at76c651_writereg(struct i2c_adapter *i2c, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-static u8 at76c651_readreg(struct i2c_adapter *i2c, u8 reg)
+static u8 at76c651_readreg(struct at76c651_state* state, u8 reg)
{
int ret;
u8 val;
struct i2c_msg msg[] = {
- { .addr = 0x1a >> 1, .flags = 0, .buf = &reg, .len = 1 },
- { .addr = 0x1a >> 1, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+ { .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = &val, .len = 1 }
};
- ret = i2c_transfer(i2c, msg, 2);
+ ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -129,112 +112,64 @@ static u8 at76c651_readreg(struct i2c_adapter *i2c, u8 reg)
return val;
}
-static int at76c651_reset(struct i2c_adapter *i2c)
+static int at76c651_reset(struct at76c651_state* state)
{
- return at76c651_writereg(i2c, 0x07, 0x01);
+ return at76c651_writereg(state, 0x07, 0x01);
}
-static void at76c651_disable_interrupts(struct i2c_adapter *i2c)
+static void at76c651_disable_interrupts(struct at76c651_state* state)
{
- at76c651_writereg(i2c, 0x0b, 0x00);
+ at76c651_writereg(state, 0x0b, 0x00);
}
static int at76c651_set_auto_config(struct at76c651_state *state)
{
- struct i2c_adapter *i2c = state->i2c;
-
/*
* Autoconfig
*/
- at76c651_writereg(i2c, 0x06, 0x01);
+ at76c651_writereg(state, 0x06, 0x01);
/*
* Performance optimizations, should be done after autoconfig
*/
- at76c651_writereg(i2c, 0x10, 0x06);
- at76c651_writereg(i2c, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10);
- at76c651_writereg(i2c, 0x15, 0x28);
- at76c651_writereg(i2c, 0x20, 0x09);
- at76c651_writereg(i2c, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90);
- at76c651_writereg(i2c, 0x30, 0x90);
+ at76c651_writereg(state, 0x10, 0x06);
+ at76c651_writereg(state, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10);
+ at76c651_writereg(state, 0x15, 0x28);
+ at76c651_writereg(state, 0x20, 0x09);
+ at76c651_writereg(state, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90);
+ at76c651_writereg(state, 0x30, 0x90);
if (state->qam == 5)
- at76c651_writereg(i2c, 0x35, 0x2A);
+ at76c651_writereg(state, 0x35, 0x2A);
/*
* Initialize A/D-converter
*/
if (state->revision == 0x11) {
- at76c651_writereg(i2c, 0x2E, 0x38);
- at76c651_writereg(i2c, 0x2F, 0x13);
+ at76c651_writereg(state, 0x2E, 0x38);
+ at76c651_writereg(state, 0x2F, 0x13);
}
- at76c651_disable_interrupts(i2c);
+ at76c651_disable_interrupts(state);
/*
* Restart operation
*/
- at76c651_reset(i2c);
-
- return 0;
-}
-
-static void at76c651_set_bbfreq(struct i2c_adapter *i2c)
-{
- at76c651_writereg(i2c, 0x04, 0x3f);
- at76c651_writereg(i2c, 0x05, 0xee);
-}
-
-static int at76c651_pll_write(struct i2c_adapter *i2c, u8 *buf, size_t len)
-{
- int ret;
- struct i2c_msg msg =
- { .addr = 0xc2 >> 1, .flags = 0, .buf = buf, .len = len };
-
- at76c651_writereg(i2c, 0x0c, 0xc3);
-
- ret = i2c_transfer(i2c, &msg, 1);
-
- at76c651_writereg(i2c, 0x0c, 0xc2);
-
- if (ret < 0)
- return ret;
- else if (ret != 1)
- return -EREMOTEIO;
+ at76c651_reset(state);
return 0;
}
-static int tua6010_setfreq(struct i2c_adapter *i2c, u32 freq)
+static void at76c651_set_bbfreq(struct at76c651_state* state)
{
- u32 div;
- u8 buf[4];
- u8 vu, p2, p1, p0;
-
- if ((freq < 50000000) || (freq > 900000000))
- return -EINVAL;
-
- div = (freq + 36125000) / 62500;
-
- if (freq > 400000000)
- vu = 1, p2 = 1, p1 = 0, p0 = 1;
- else if (freq > 140000000)
- vu = 0, p2 = 1, p1 = 1, p0 = 0;
- else
- vu = 0, p2 = 0, p1 = 1, p0 = 1;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = (div >> 0) & 0xff;
- buf[2] = 0x8e;
- buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
-
- return at76c651_pll_write(i2c, buf, 4);
+ at76c651_writereg(state, 0x04, 0x3f);
+ at76c651_writereg(state, 0x05, 0xee);
}
-static int at76c651_set_symbol_rate(struct i2c_adapter *i2c, u32 symbol_rate)
+static int at76c651_set_symbol_rate(struct at76c651_state* state, u32 symbol_rate)
{
u8 exponent;
u32 mantissa;
@@ -251,9 +186,9 @@ static int at76c651_set_symbol_rate(struct i2c_adapter *i2c, u32 symbol_rate)
exponent = __ilog2((symbol_rate << 4) / 903125);
mantissa = ((symbol_rate / 3125) * (1 << (24 - exponent))) / 289;
- at76c651_writereg(i2c, 0x00, mantissa >> 13);
- at76c651_writereg(i2c, 0x01, mantissa >> 5);
- at76c651_writereg(i2c, 0x02, (mantissa << 3) | exponent);
+ at76c651_writereg(state, 0x00, mantissa >> 13);
+ at76c651_writereg(state, 0x01, mantissa >> 5);
+ at76c651_writereg(state, 0x02, (mantissa << 3) | exponent);
return 0;
}
@@ -292,13 +227,12 @@ static int at76c651_set_qam(struct at76c651_state *state, fe_modulation_t qam)
}
- return at76c651_writereg(state->i2c, 0x03, state->qam);
+ return at76c651_writereg(state, 0x03, state->qam);
}
-static int at76c651_set_inversion(struct i2c_adapter *i2c,
- fe_spectral_inversion_t inversion)
+static int at76c651_set_inversion(struct at76c651_state* state, fe_spectral_inversion_t inversion)
{
- u8 feciqinv = at76c651_readreg(i2c, 0x60);
+ u8 feciqinv = at76c651_readreg(state, 0x60);
switch (inversion) {
case INVERSION_OFF:
@@ -318,250 +252,208 @@ static int at76c651_set_inversion(struct i2c_adapter *i2c,
return -EINVAL;
}
- return at76c651_writereg(i2c, 0x60, feciqinv);
+ return at76c651_writereg(state, 0x60, feciqinv);
}
-static int at76c651_set_parameters(struct at76c651_state *state,
+
+
+
+
+
+
+
+
+static int at76c651_set_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *p)
{
- struct i2c_adapter *i2c = state->i2c;
int ret;
+ struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
- if ((ret = tua6010_setfreq(i2c, p->frequency)))
- return ret;
+ at76c651_writereg(state, 0x0c, 0xc3);
+ state->config->pll_set(fe, p);
+ at76c651_writereg(state, 0x0c, 0xc2);
- if ((ret = at76c651_set_symbol_rate(i2c, p->u.qam.symbol_rate)))
+ if ((ret = at76c651_set_symbol_rate(state, p->u.qam.symbol_rate)))
return ret;
- if ((ret = at76c651_set_inversion(i2c, p->inversion)))
+ if ((ret = at76c651_set_inversion(state, p->inversion)))
return ret;
return at76c651_set_auto_config(state);
}
-static int at76c651_set_defaults(struct at76c651_state *state)
+static int at76c651_set_defaults(struct dvb_frontend* fe)
{
- struct i2c_adapter *i2c = state->i2c;
+ struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
- at76c651_set_symbol_rate(i2c, 6900000);
+ at76c651_set_symbol_rate(state, 6900000);
at76c651_set_qam(state, QAM_64);
- at76c651_set_bbfreq(i2c);
+ at76c651_set_bbfreq(state);
at76c651_set_auto_config(state);
+ if (state->config->pll_init) {
+ at76c651_writereg(state, 0x0c, 0xc3);
+ state->config->pll_init(fe);
+ at76c651_writereg(state, 0x0c, 0xc2);
+ }
+
return 0;
}
-static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- struct at76c651_state *state = fe->data;
- struct i2c_adapter *i2c = state->i2c;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy(arg, &at76c651_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = arg;
- u8 sync;
-
- /*
- * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0)
- */
- sync = at76c651_readreg(i2c, 0x80);
-
- *status = 0;
-
- if (sync & (0x04 | 0x10)) /* AGC1 || TIM */
- *status |= FE_HAS_SIGNAL;
- if (sync & 0x10) /* TIM */
- *status |= FE_HAS_CARRIER;
- if (sync & 0x80) /* FEC */
- *status |= FE_HAS_VITERBI;
- if (sync & 0x40) /* CAR */
- *status |= FE_HAS_SYNC;
- if ((sync & 0xF0) == 0xF0) /* TIM && EQU && CAR && FEC */
- *status |= FE_HAS_LOCK;
- break;
- }
-
- case FE_READ_BER:
- {
- u32 *ber = arg;
- *ber = (at76c651_readreg(i2c, 0x81) & 0x0F) << 16;
- *ber |= at76c651_readreg(i2c, 0x82) << 8;
- *ber |= at76c651_readreg(i2c, 0x83);
- *ber *= 10;
- break;
- }
+ struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
+ u8 sync;
- case FE_READ_SIGNAL_STRENGTH:
- {
- u8 gain = ~at76c651_readreg(i2c, 0x91);
- *(u16 *)arg = (gain << 8) | gain;
- break;
- }
-
- case FE_READ_SNR:
- *(u16 *)arg = 0xFFFF -
- ((at76c651_readreg(i2c, 0x8F) << 8) |
- at76c651_readreg(i2c, 0x90));
- break;
-
- case FE_READ_UNCORRECTED_BLOCKS:
- *(u32 *)arg = at76c651_readreg(i2c, 0x82);
- break;
-
- case FE_SET_FRONTEND:
- return at76c651_set_parameters(state, arg);
-
- case FE_GET_FRONTEND:
- break;
-
- case FE_SLEEP:
- break;
+ /*
+ * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0)
+ */
+ sync = at76c651_readreg(state, 0x80);
+ *status = 0;
+
+ if (sync & (0x04 | 0x10)) /* AGC1 || TIM */
+ *status |= FE_HAS_SIGNAL;
+ if (sync & 0x10) /* TIM */
+ *status |= FE_HAS_CARRIER;
+ if (sync & 0x80) /* FEC */
+ *status |= FE_HAS_VITERBI;
+ if (sync & 0x40) /* CAR */
+ *status |= FE_HAS_SYNC;
+ if ((sync & 0xF0) == 0xF0) /* TIM && EQU && CAR && FEC */
+ *status |= FE_HAS_LOCK;
- case FE_INIT:
- return at76c651_set_defaults(state);
+ return 0;
+}
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings *fesettings = arg;
- fesettings->min_delay_ms = 50;
- fesettings->step_size = 0;
- fesettings->max_drift = 0;
- break;
- }
+static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
- default:
- return -ENOIOCTLCMD;
- }
+ *ber = (at76c651_readreg(state, 0x81) & 0x0F) << 16;
+ *ber |= at76c651_readreg(state, 0x82) << 8;
+ *ber |= at76c651_readreg(state, 0x83);
+ *ber *= 10;
return 0;
}
-static struct i2c_client client_template;
-
-static int attach_adapter(struct i2c_adapter *adapter)
+static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
- struct at76c651_state *state;
- struct i2c_client *client;
- int ret;
-
- if (at76c651_readreg(adapter, 0x0E) != 0x65)
- return -ENODEV;
+ struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
- if (!(state = kmalloc(sizeof(struct at76c651_state), GFP_KERNEL)))
- return -ENOMEM;
+ u8 gain = ~at76c651_readreg(state, 0x91);
+ *strength = (gain << 8) | gain;
- state->i2c = adapter;
- state->revision = at76c651_readreg(adapter, 0x0F) & 0xFE;
+ return 0;
+}
- switch (state->revision) {
- case 0x10:
- at76c651_info.name[14] = 'A';
- break;
- case 0x11:
- at76c651_info.name[14] = 'B';
- break;
- default:
- kfree(state);
- return -ENODEV;
- }
+static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
- if (!(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- kfree(state);
- return -ENOMEM;
- }
+ *snr = 0xFFFF -
+ ((at76c651_readreg(state, 0x8F) << 8) |
+ at76c651_readreg(state, 0x90));
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = 0x1a >> 1;
- i2c_set_clientdata(client, state);
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(state);
- kfree(client);
- return ret;
- }
+ return 0;
+}
- BUG_ON(!state->dvb);
+static int at76c651_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
- ret = dvb_register_frontend(at76c651_ioctl, state->dvb, state,
- &at76c651_info, THIS_MODULE);
- if (ret) {
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return ret;
- }
+ *ucblocks = at76c651_readreg(state, 0x82);
return 0;
}
-static int detach_client(struct i2c_client *client)
+static int at76c651_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *fesettings)
{
- struct at76c651_state *state = i2c_get_clientdata(client);
+ fesettings->min_delay_ms = 50;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
- dvb_unregister_frontend(at76c651_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
+static void at76c651_release(struct dvb_frontend* fe)
+{
+ struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv;
kfree(state);
-
- return 0;
}
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static struct dvb_frontend_ops at76c651_ops;
+
+struct dvb_frontend* at76c651_attach(const struct at76c651_config* config,
+ struct i2c_adapter* i2c)
{
- struct at76c651_state *state = i2c_get_clientdata(client);
+ struct at76c651_state* state = NULL;
- switch (cmd) {
- case FE_REGISTER:
- state->dvb = arg;
- break;
- case FE_UNREGISTER:
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
+ /* allocate memory for the internal state */
+ state = (struct at76c651_state*) kmalloc(sizeof(struct at76c651_state), GFP_KERNEL);
+ if (state == NULL) goto error;
- return 0;
-}
+ /* setup the state */
+ state->config = config;
+ state->qam = 0;
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_AT76C651,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
+ /* check if the demod is there */
+ if (at76c651_readreg(state, 0x0e) != 0x65) goto error;
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+ /* finalise state setup */
+ state->i2c = i2c;
+ state->revision = at76c651_readreg(state, 0x0f) & 0xfe;
+ memcpy(&state->ops, &at76c651_ops, sizeof(struct dvb_frontend_ops));
-static int __init at76c651_init(void)
-{
- return i2c_add_driver(&driver);
-}
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
-static void __exit at76c651_exit(void)
-{
- if (i2c_del_driver(&driver))
- printk(KERN_ERR "at76c651: driver deregistration failed.\n");
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init(at76c651_init);
-module_exit(at76c651_exit);
+static struct dvb_frontend_ops at76c651_ops = {
+
+ .info = {
+ .name = "Atmel AT76C651B DVB-C",
+ .type = FE_QAM,
+ .frequency_min = 48250000,
+ .frequency_max = 863250000,
+ .frequency_stepsize = 62500,
+ /*.frequency_tolerance = */ /* FIXME: 12% of SR */
+ .symbol_rate_min = 0, /* FIXME */
+ .symbol_rate_max = 9360000, /* FIXME */
+ .symbol_rate_tolerance = 4000,
+ .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_8_9 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 |
+ FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER
+ },
+
+ .release = at76c651_release,
+
+ .init = at76c651_set_defaults,
+
+ .set_frontend = at76c651_set_parameters,
+ .get_tune_settings = at76c651_get_tune_settings,
+
+ .read_status = at76c651_read_status,
+ .read_ber = at76c651_read_ber,
+ .read_signal_strength = at76c651_read_signal_strength,
+ .read_snr = at76c651_read_snr,
+ .read_ucblocks = at76c651_read_ucblocks,
+};
-MODULE_DESCRIPTION("at76c651/tua6010xs dvb-c frontend driver");
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Atmel AT76C651 DVB-C Demodulator Driver");
MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(at76c651_attach);
diff --git a/linux/drivers/media/dvb/frontends/at76c651.h b/linux/drivers/media/dvb/frontends/at76c651.h
new file mode 100644
index 000000000..47fd9af48
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/at76c651.h
@@ -0,0 +1,47 @@
+/*
+ * at76c651.c
+ *
+ * Atmel DVB-C Frontend Driver (at76c651)
+ *
+ * Copyright (C) 2001 fnbrd <fnbrd@gmx.de>
+ * & 2002-2004 Andreas Oberritter <obi@linuxtv.org>
+ * & 2003 Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ * 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.
+ *
+ * AT76C651
+ * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf
+ * http://www.atmel.com/atmel/acrobat/doc1320.pdf
+ */
+
+#ifndef AT76C651_H
+#define AT76C651_H
+
+#include <linux/dvb/frontend.h>
+
+struct at76c651_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* at76c651_attach(const struct at76c651_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // AT76C651_H
diff --git a/linux/drivers/media/dvb/frontends/cx22700.c b/linux/drivers/media/dvb/frontends/cx22700.c
new file mode 100644
index 000000000..26744e71f
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/cx22700.c
@@ -0,0 +1,445 @@
+#/*
+ Conexant cx22700 DVB OFDM demodulator driver
+
+ Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+ Holger Waechtler <holger@convergence.de>
+
+ 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "cx22700.h"
+
+
+struct cx22700_state {
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ const struct cx22700_config* config;
+
+ struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "cx22700: " args); \
+ } while (0)
+
+static u8 init_tab [] = {
+ 0x04, 0x10,
+ 0x05, 0x09,
+ 0x06, 0x00,
+ 0x08, 0x04,
+ 0x09, 0x00,
+ 0x0a, 0x01,
+ 0x15, 0x40,
+ 0x16, 0x10,
+ 0x17, 0x87,
+ 0x18, 0x17,
+ 0x1a, 0x10,
+ 0x25, 0x04,
+ 0x2e, 0x00,
+ 0x39, 0x00,
+ 0x3a, 0x04,
+ 0x45, 0x08,
+ 0x46, 0x02,
+ 0x47, 0x05,
+};
+
+
+static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf [] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ ret = i2c_transfer (state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+ __FUNCTION__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static int cx22700_readreg (struct cx22700_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 } };
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ ret = i2c_transfer (state->i2c, msg, 2);
+
+ if (ret != 2) return -EIO;
+
+ return b1[0];
+}
+
+static int cx22700_set_inversion (struct cx22700_state* state, int inversion)
+{
+ u8 val;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ switch (inversion) {
+ case INVERSION_AUTO:
+ return -EOPNOTSUPP;
+ case INVERSION_ON:
+ val = cx22700_readreg (state, 0x09);
+ return cx22700_writereg (state, 0x09, val | 0x01);
+ case INVERSION_OFF:
+ val = cx22700_readreg (state, 0x09);
+ return cx22700_writereg (state, 0x09, val & 0xfe);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p)
+{
+ static const u8 qam_tab [4] = { 0, 1, 0, 2 };
+ static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
+ u8 val;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8)
+ return -EINVAL;
+
+ if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8)
+
+ if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5)
+ return -EINVAL;
+
+ if (p->guard_interval < GUARD_INTERVAL_1_32 ||
+ p->guard_interval > GUARD_INTERVAL_1_4)
+ return -EINVAL;
+
+ if (p->transmission_mode != TRANSMISSION_MODE_2K &&
+ p->transmission_mode != TRANSMISSION_MODE_8K)
+ return -EINVAL;
+
+ if (p->constellation != QPSK &&
+ p->constellation != QAM_16 &&
+ p->constellation != QAM_64)
+ return -EINVAL;
+
+ if (p->hierarchy_information < HIERARCHY_NONE ||
+ p->hierarchy_information > HIERARCHY_4)
+ return -EINVAL;
+
+ if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ)
+ return -EINVAL;
+
+ if (p->bandwidth == BANDWIDTH_7_MHZ)
+ cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10));
+ else
+ cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10));
+
+ val = qam_tab[p->constellation - QPSK];
+ val |= p->hierarchy_information - HIERARCHY_NONE;
+
+ cx22700_writereg (state, 0x04, val);
+
+ val = fec_tab[p->code_rate_HP - FEC_1_2] << 3;
+ val |= fec_tab[p->code_rate_LP - FEC_1_2];
+
+ cx22700_writereg (state, 0x05, val);
+
+ val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2;
+ val |= p->transmission_mode - TRANSMISSION_MODE_2K;
+
+ cx22700_writereg (state, 0x06, val);
+
+ cx22700_writereg (state, 0x08, 0x04 | 0x02); /* use user tps parameters */
+ cx22700_writereg (state, 0x08, 0x04); /* restart aquisition */
+
+ return 0;
+}
+
+static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p)
+{
+ static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
+ static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
+ FEC_5_6, FEC_7_8 };
+ u8 val;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (!(cx22700_readreg(state, 0x07) & 0x20)) /* tps valid? */
+ return -EAGAIN;
+
+ val = cx22700_readreg (state, 0x01);
+
+ if ((val & 0x7) > 4)
+ p->hierarchy_information = HIERARCHY_AUTO;
+ else
+ p->hierarchy_information = HIERARCHY_NONE + (val & 0x7);
+
+ if (((val >> 3) & 0x3) > 2)
+ p->constellation = QAM_AUTO;
+ else
+ p->constellation = qam_tab[(val >> 3) & 0x3];
+
+ val = cx22700_readreg (state, 0x02);
+
+ if (((val >> 3) & 0x07) > 4)
+ p->code_rate_HP = FEC_AUTO;
+ else
+ p->code_rate_HP = fec_tab[(val >> 3) & 0x07];
+
+ if ((val & 0x07) > 4)
+ p->code_rate_LP = FEC_AUTO;
+ else
+ p->code_rate_LP = fec_tab[val & 0x07];
+
+ val = cx22700_readreg (state, 0x03);
+
+ p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3);
+ p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+static int cx22700_init (struct dvb_frontend* fe)
+
+{ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+ int i;
+
+ dprintk("cx22700_init: init chip\n");
+
+ cx22700_writereg (state, 0x00, 0x02); /* soft reset */
+ cx22700_writereg (state, 0x00, 0x00);
+
+ msleep(10);
+
+ for (i=0; i<sizeof(init_tab); i+=2)
+ cx22700_writereg (state, init_tab[i], init_tab[i+1]);
+
+ cx22700_writereg (state, 0x00, 0x01);
+
+ if (state->config->pll_init) {
+ cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
+ state->config->pll_init(fe);
+ cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
+ }
+
+ return 0;
+}
+
+static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+ u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+ | (cx22700_readreg (state, 0x0e) << 1);
+ u8 sync = cx22700_readreg (state, 0x07);
+
+ *status = 0;
+
+ if (rs_ber < 0xff00)
+ *status |= FE_HAS_SIGNAL;
+
+ if (sync & 0x20)
+ *status |= FE_HAS_CARRIER;
+
+ if (sync & 0x10)
+ *status |= FE_HAS_VITERBI;
+
+ if (sync & 0x10)
+ *status |= FE_HAS_SYNC;
+
+ if (*status == 0x0f)
+ *status |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+ *ber = cx22700_readreg (state, 0x0c) & 0x7f;
+ cx22700_writereg (state, 0x0c, 0x00);
+
+ return 0;
+}
+
+static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+ u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+ | (cx22700_readreg (state, 0x0e) << 1);
+ *signal_strength = ~rs_ber;
+
+ return 0;
+}
+
+static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+ u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+ | (cx22700_readreg (state, 0x0e) << 1);
+ *snr = ~rs_ber;
+
+ return 0;
+}
+
+static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+ *ucblocks = cx22700_readreg (state, 0x0f);
+ cx22700_writereg (state, 0x0f, 0x00);
+
+ return 0;
+}
+
+static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+ cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
+ cx22700_writereg (state, 0x00, 0x00);
+
+ cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
+ state->config->pll_set(fe, p);
+ cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
+ cx22700_set_inversion (state, p->inversion);
+ cx22700_set_tps (state, &p->u.ofdm);
+ cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */
+ cx22700_writereg (state, 0x00, 0x01); /* restart acquire */
+
+ return 0;
+}
+
+static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+ u8 reg09 = cx22700_readreg (state, 0x09);
+
+ p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
+ return cx22700_get_tps (state, &p->u.ofdm);
+}
+
+static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+ fesettings->min_delay_ms = 150;
+ fesettings->step_size = 166667;
+ fesettings->max_drift = 166667*2;
+ return 0;
+}
+
+static void cx22700_release(struct dvb_frontend* fe)
+{
+ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops cx22700_ops;
+
+struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct cx22700_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct cx22700_state*) kmalloc(sizeof(struct cx22700_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
+
+ /* check if the demod is there */
+ if (cx22700_readreg(state, 0x07) < 0) goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops cx22700_ops = {
+
+ .info = {
+ .name = "Conexant CX22700 DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 470000000,
+ .frequency_max = 860000000,
+ .frequency_stepsize = 166667,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_RECOVER
+ },
+
+ .release = cx22700_release,
+
+ .init = cx22700_init,
+
+ .set_frontend = cx22700_set_frontend,
+ .get_frontend = cx22700_get_frontend,
+ .get_tune_settings = cx22700_get_tune_settings,
+
+ .read_status = cx22700_read_status,
+ .read_ber = cx22700_read_ber,
+ .read_signal_strength = cx22700_read_signal_strength,
+ .read_snr = cx22700_read_snr,
+ .read_ucblocks = cx22700_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver");
+MODULE_AUTHOR("Holger Waechtler");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx22700_attach);
diff --git a/linux/drivers/media/dvb/frontends/cx22700.h b/linux/drivers/media/dvb/frontends/cx22700.h
new file mode 100644
index 000000000..c9145b458
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/cx22700.h
@@ -0,0 +1,41 @@
+/*
+ Conexant CX22700 DVB OFDM demodulator driver
+
+ Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+ Holger Waechtler <holger@convergence.de>
+
+ 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 CX22700_H
+#define CX22700_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx22700_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // CX22700_H
diff --git a/linux/drivers/media/dvb/frontends/cx22702.c b/linux/drivers/media/dvb/frontends/cx22702.c
index e723a176a..6d8bdbc8b 100644
--- a/linux/drivers/media/dvb/frontends/cx22702.c
+++ b/linux/drivers/media/dvb/frontends/cx22702.c
@@ -1,8 +1,8 @@
/*
- Conexant 22702 DVB OFDM frontend driver
+ Conexant 22702 DVB OFDM demodulator driver
based on:
- Alps TDMB7 DVB OFDM frontend driver
+ Alps TDMB7 DVB OFDM demodulator driver
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
@@ -23,7 +23,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+*/
#include <linux/kernel.h>
#include <linux/init.h>
@@ -31,44 +31,28 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
-
#include "dvb_frontend.h"
+#include "cx22702.h"
-#define FRONTEND_NAME "dvbfe_cx22702"
-#define I2C_EEPROM_SLAVE_ADDR 0x50
+struct cx22702_state {
-#define PLLTYPE_DTT7592 1
-#define PLLTYPE_DTT7595 2
-#define PLLTYPE_DTT7579 3
+ struct i2c_adapter* i2c;
-static int debug = 0;
+ struct dvb_frontend_ops ops;
-#define dprintk if (debug) printk
+ /* configuration settings */
+ const struct cx22702_config* config;
-static struct dvb_frontend_info cx22702_info = {
- .name = "CX22702 Demod Thomson 759x/7579 PLL",
- .type = FE_OFDM,
- .frequency_min = 177000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 166666,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
-};
+ struct dvb_frontend frontend;
-struct cx22702_state {
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
- struct dvb_frontend_info cx22702_info;
- char pll_type;
- int pll_addr;
- int demod_addr;
+ /* previous uncorrected block counter */
u8 prevUCBlocks;
};
+static int debug = 0;
+#define dprintk if (debug) printk
+
/* Register values to initialise the demod */
static u8 init_tab [] = {
0x00, 0x00, /* Stop aquisition */
@@ -99,291 +83,178 @@ static u8 init_tab [] = {
0xfd, 0x00,
};
-static struct i2c_client client_template;
-
-static int cx22702_writereg (struct i2c_adapter *i2c, int demod_addr, u8 reg, u8 data)
+static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data)
{
int ret;
u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = demod_addr, .flags = 0, .buf = buf, .len = 2 };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
- ret = i2c_transfer(i2c, &msg, 1);
+ ret = i2c_transfer(state->i2c, &msg, 1);
- if (ret != 1)
+ if (ret != 1)
printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
__FUNCTION__, reg, data, ret);
return (ret != 1) ? -1 : 0;
}
-static u8 cx22702_readreg (struct i2c_adapter *i2c, int demod_addr, u8 reg)
+static u8 cx22702_readreg (struct cx22702_state* state, u8 reg)
{
int ret;
u8 b0 [] = { reg };
u8 b1 [] = { 0 };
struct i2c_msg msg [] = {
- { .addr = demod_addr, .flags = 0, .buf = b0, .len = 1 },
- { .addr = demod_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
- ret = i2c_transfer(i2c, msg, 2);
-
- if (ret != 2)
+ { .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("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
return b1[0];
}
-static int pll_readreg(struct i2c_adapter *i2c, int pll_addr, int demod_addr, u8 reg)
+static int cx22702_set_inversion (struct cx22702_state *state, int inversion)
{
- u8 b0 [] = { reg };
- u8 b1 [] = { 0 };
+ u8 val;
- struct i2c_msg msg [] = {
- { .addr = pll_addr, .flags = 0, .buf = b0, .len = 1 },
- { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
- };
-
- cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) &0xfe); // Enable PLL bus
- if (i2c_transfer(i2c, msg, 2) != 2) {
- printk ("%s i2c pll request failed\n", __FUNCTION__);
- cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus
- return -ENODEV;
- }
- cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus
+ switch (inversion) {
- return b1[0];
-}
+ case INVERSION_AUTO:
+ return -EOPNOTSUPP;
-static int pll_write (struct i2c_adapter *i2c, int pll_addr, int demod_addr, u8 data [4])
-{
- int ret=0;
- struct i2c_msg msg = { .addr = pll_addr, .flags = 0, .buf = data, .len = 4 };
+ case INVERSION_ON:
+ val = cx22702_readreg (state, 0x0C);
+ return cx22702_writereg (state, 0x0C, val | 0x01);
+
+ case INVERSION_OFF:
+ val = cx22702_readreg (state, 0x0C);
+ return cx22702_writereg (state, 0x0C, val & 0xfe);
- cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) &0xfe); // Enable PLL bus
- ret = i2c_transfer(i2c, &msg, 1);
- cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus
+ default:
+ return -EINVAL;
- if (ret != 1)
- printk("%s: i/o error (addr == 0x%02x, ret == %i)\n", __FUNCTION__, msg.addr, ret);
+ }
- return (ret != 1) ? -1 : 0;
}
-static int pll_dtt759x_set_tv_freq (struct i2c_adapter *i2c, struct cx22702_state *state, u32 freq, int bandwidth)
+/* Retrieve the demod settings */
+static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p)
{
- int ret;
-
- u32 div = (freq + 36166667) / 166666;
-
- /* dividerhigh, dividerlow, control, bandwidth switch tuner args */
- unsigned char buf [4] = {
- (div >> 8) & 0x7f,
- div & 0xff,
- 0x84,
- 0x00
- };
-
- if(freq < 470000000) {
- buf[3] = 0x02;
- } else {
- buf[3] = 0x08;
- }
+ u8 val;
- if(bandwidth == BANDWIDTH_7_MHZ) {
- buf[3] |= 0x10;
- }
+ /* Make sure the TPS regs are valid */
+ if (!(cx22702_readreg(state, 0x0A) & 0x20))
+ return -EAGAIN;
- // Now compensate for the charge pump osc
- if(freq <= 264000000) {
- buf[2] = buf[2] | 0x30;
- } else if (freq <= 735000000) {
- buf[2] = buf[2] | 0x38;
- } else if (freq <= 835000000) {
- buf[2] = buf[2] | 0x70;
- } else if (freq <= 896000000) {
- buf[2] = buf[2] | 0x78;
- }
-
- dprintk ("%s: freq == %i, div == 0x%04x\n", __FUNCTION__, (int) freq, (int) div);
-
- ret= pll_write (i2c, state->pll_addr, state->demod_addr, buf);
- if(ret<0) {
- dprintk ("%s: first pll_write failed\n",__FUNCTION__);
- return ret;
+ val = cx22702_readreg (state, 0x01);
+ switch( (val&0x18)>>3) {
+ case 0: p->constellation = QPSK; break;
+ case 1: p->constellation = QAM_16; break;
+ case 2: p->constellation = QAM_64; break;
}
-
- /* Set the AGC during search */
- buf[2]=(buf[2] & 0xc7) | 0x18;
- buf[3]=0xa0;
- ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf);
- if(ret<0) {
- dprintk ("%s: second pll_write failed\n",__FUNCTION__);
- return ret;
+ switch( val&0x07 ) {
+ case 0: p->hierarchy_information = HIERARCHY_NONE; break;
+ case 1: p->hierarchy_information = HIERARCHY_1; break;
+ case 2: p->hierarchy_information = HIERARCHY_2; break;
+ case 3: p->hierarchy_information = HIERARCHY_4; break;
}
- /* Tuner needs a small amount of time */
- msleep(100);
- /* Set the AGC post-search */
- buf[3]=0x20;
- ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf);
- if(ret<0) {
- dprintk ("%s: third pll_write failed\n",__FUNCTION__);
- return ret;
+ val = cx22702_readreg (state, 0x02);
+ switch( (val&0x38)>>3 ) {
+ case 0: p->code_rate_HP = FEC_1_2; break;
+ case 1: p->code_rate_HP = FEC_2_3; break;
+ case 2: p->code_rate_HP = FEC_3_4; break;
+ case 3: p->code_rate_HP = FEC_5_6; break;
+ case 4: p->code_rate_HP = FEC_7_8; break;
}
-
- return ret;
-
-}
-
-static int pll_dtt7579_set_tv_freq (struct i2c_adapter *i2c, struct cx22702_state *state, u32 freq, int bandwidth)
-{
- int ret;
-
- u32 div = (freq + 36166667) / 166666;
-
- /* dividerhigh, dividerlow */
- unsigned char buf [4] = {
- div >> 8,
- div & 0xff,
- 0x00,
- 0x00
- };
-
- // FIXME: bandwidth setting unknown
-
- // Now compensate for the charge pump osc
- if(freq <= 506000000) {
- buf[2] = 0xb4;
- buf[3] = 0x02;
- } else if (freq <= 735000000) {
- buf[2] = 0xbc;
- buf[3] = 0x08;
- } else if (freq <= 835000000) {
- buf[2] = 0xf4;
- buf[3] = 0x08;
- } else if (freq <= 896000000) {
- buf[2] = 0xfc;
- buf[3] = 0x08;
+ switch( val&0x07 ) {
+ case 0: p->code_rate_LP = FEC_1_2; break;
+ case 1: p->code_rate_LP = FEC_2_3; break;
+ case 2: p->code_rate_LP = FEC_3_4; break;
+ case 3: p->code_rate_LP = FEC_5_6; break;
+ case 4: p->code_rate_LP = FEC_7_8; break;
}
- dprintk ("%s: freq == %i, div == 0x%04x\n", __FUNCTION__, (int) freq, (int) div);
- ret= pll_write (i2c, state->pll_addr, state->demod_addr, buf);
- if(ret<0) {
- dprintk ("%s: first pll_write failed\n",__FUNCTION__);
- return ret;
+ val = cx22702_readreg (state, 0x03);
+ switch( (val&0x0c)>>2 ) {
+ case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
+ case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
+ case 2: p->guard_interval = GUARD_INTERVAL_1_8; break;
+ case 3: p->guard_interval = GUARD_INTERVAL_1_4; break;
}
-
- /* Set the AGC to search */
- buf[2]=(buf[2] & 0xdc) | 0x9c;
- buf[3]=0xa0;
- ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf);
- if(ret<0) {
- dprintk ("%s: second pll_write failed\n",__FUNCTION__);
- return ret;
+ switch( val&0x03 ) {
+ case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
+ case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
}
- return ret;
-
+ return 0;
}
-/* Reset the demod hardware and reset all of the configuration registers
- to a default state. */
-static int cx22702_init (struct i2c_adapter *i2c, struct cx22702_state *state)
-{
- int i;
- cx22702_writereg (i2c, state->demod_addr, 0x00, 0x02);
- msleep(10);
-
- for (i=0; i<sizeof(init_tab); i+=2)
- cx22702_writereg (i2c, state->demod_addr, init_tab[i], init_tab[i+1]);
- return 0;
-}
-static int cx22702_set_inversion (struct i2c_adapter *i2c, struct cx22702_state *state, int inversion)
-{
- u8 val;
- switch (inversion) {
- case INVERSION_AUTO:
- return -EOPNOTSUPP;
- case INVERSION_ON:
- val = cx22702_readreg (i2c, state->demod_addr, 0x0C);
- return cx22702_writereg (i2c, state->demod_addr, 0x0C, val | 0x01);
- case INVERSION_OFF:
- val = cx22702_readreg (i2c, state->demod_addr, 0x0C);
- return cx22702_writereg (i2c, state->demod_addr, 0x0C, val & 0xfe);
- default:
- return -EINVAL;
- }
-}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int cx22702_set_tps (struct i2c_adapter *i2c, struct cx22702_state *state,
- struct dvb_frontend_parameters *p)
+static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
u8 val;
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
/* set PLL */
- switch(state->pll_type) {
- case PLLTYPE_DTT7592:
- case PLLTYPE_DTT7595:
- pll_dtt759x_set_tv_freq (i2c, state, p->frequency, p->u.ofdm.bandwidth);
- break;
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+ state->config->pll_set(fe, p);
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
- case PLLTYPE_DTT7579:
- pll_dtt7579_set_tv_freq (i2c, state, p->frequency, p->u.ofdm.bandwidth);
- break;
- }
-
/* set inversion */
- cx22702_set_inversion (i2c, state, p->inversion);
+ cx22702_set_inversion (state, p->inversion);
/* set bandwidth */
switch(p->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
- cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xcf) | 0x20 );
+ cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 );
break;
case BANDWIDTH_7_MHZ:
- cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xcf) | 0x10 );
+ cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 );
break;
case BANDWIDTH_8_MHZ:
- cx22702_writereg(i2c, state->demod_addr, 0x0C, cx22702_readreg(i2c, state->demod_addr, 0x0C) &0xcf );
+ cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf );
break;
default:
dprintk ("%s: invalid bandwidth\n",__FUNCTION__);
return -EINVAL;
}
-
+
p->u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working
-
+
/* use auto configuration? */
- if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) ||
+ if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) ||
(p->u.ofdm.constellation==QAM_AUTO) ||
- (p->u.ofdm.code_rate_HP==FEC_AUTO) ||
- (p->u.ofdm.code_rate_LP==FEC_AUTO) ||
- (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) ||
+ (p->u.ofdm.code_rate_HP==FEC_AUTO) ||
+ (p->u.ofdm.code_rate_LP==FEC_AUTO) ||
+ (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) ||
(p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) {
/* TPS Source - use hardware driven values */
- cx22702_writereg(i2c, state->demod_addr, 0x06, 0x10);
- cx22702_writereg(i2c, state->demod_addr, 0x07, 0x9);
- cx22702_writereg(i2c, state->demod_addr, 0x08, 0xC1);
- cx22702_writereg(i2c, state->demod_addr, 0x0B, cx22702_readreg(i2c, state->demod_addr, 0x0B) & 0xfc );
- cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xBF) | 0x40 );
- cx22702_writereg(i2c, state->demod_addr, 0x00, 0x01); /* Begin aquisition */
+ cx22702_writereg(state, 0x06, 0x10);
+ cx22702_writereg(state, 0x07, 0x9);
+ cx22702_writereg(state, 0x08, 0xC1);
+ cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc );
+ cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
+ cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */
printk("%s: Autodetecting\n",__FUNCTION__);
return 0;
}
@@ -407,7 +278,7 @@ static int cx22702_set_tps (struct i2c_adapter *i2c, struct cx22702_state *state
dprintk ("%s: invalid hierarchy\n",__FUNCTION__);
return -EINVAL;
}
- cx22702_writereg (i2c, state->demod_addr, 0x06, val);
+ cx22702_writereg (state, 0x06, val);
val=0;
switch(p->u.ofdm.code_rate_HP) {
@@ -432,7 +303,7 @@ static int cx22702_set_tps (struct i2c_adapter *i2c, struct cx22702_state *state
dprintk ("%s: invalid code_rate_LP\n",__FUNCTION__);
return -EINVAL;
}
- cx22702_writereg (i2c, state->demod_addr, 0x07, val);
+ cx22702_writereg (state, 0x07, val);
val=0;
switch(p->u.ofdm.guard_interval) {
@@ -451,450 +322,211 @@ static int cx22702_set_tps (struct i2c_adapter *i2c, struct cx22702_state *state
dprintk ("%s: invalid transmission_mode\n",__FUNCTION__);
return -EINVAL;
}
- cx22702_writereg (i2c, state->demod_addr, 0x08, val);
- cx22702_writereg(i2c, state->demod_addr, 0x0B, (cx22702_readreg(i2c, state->demod_addr, 0x0B) & 0xfc) | 0x02 );
- cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xBF) | 0x40 );
+ cx22702_writereg(state, 0x08, val);
+ cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 );
+ cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
/* Begin channel aquisition */
- cx22702_writereg(i2c, state->demod_addr, 0x00, 0x01);
+ cx22702_writereg(state, 0x00, 0x01);
return 0;
}
-/* Retrieve the demod settings */
-static int cx22702_get_tps (struct i2c_adapter *i2c, struct cx22702_state *state,
- struct dvb_ofdm_parameters *p)
-{
- u8 val;
- /* Make sure the TPS regs are valid */
- if (!(cx22702_readreg(i2c, state->demod_addr, 0x0A) & 0x20))
- return -EAGAIN;
+/* Reset the demod hardware and reset all of the configuration registers
+ to a default state. */
+static int cx22702_init (struct dvb_frontend* fe)
+{
+ int i;
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
- val = cx22702_readreg (i2c, state->demod_addr, 0x01);
- switch( (val&0x18)>>3) {
- case 0: p->constellation = QPSK; break;
- case 1: p->constellation = QAM_16; break;
- case 2: p->constellation = QAM_64; break;
- }
- switch( val&0x07 ) {
- case 0: p->hierarchy_information = HIERARCHY_NONE; break;
- case 1: p->hierarchy_information = HIERARCHY_1; break;
- case 2: p->hierarchy_information = HIERARCHY_2; break;
- case 3: p->hierarchy_information = HIERARCHY_4; break;
- }
+ cx22702_writereg (state, 0x00, 0x02);
+ msleep(10);
- val = cx22702_readreg (i2c, state->demod_addr, 0x02);
- switch( (val&0x38)>>3 ) {
- case 0: p->code_rate_HP = FEC_1_2; break;
- case 1: p->code_rate_HP = FEC_2_3; break;
- case 2: p->code_rate_HP = FEC_3_4; break;
- case 3: p->code_rate_HP = FEC_5_6; break;
- case 4: p->code_rate_HP = FEC_7_8; break;
- }
- switch( val&0x07 ) {
- case 0: p->code_rate_LP = FEC_1_2; break;
- case 1: p->code_rate_LP = FEC_2_3; break;
- case 2: p->code_rate_LP = FEC_3_4; break;
- case 3: p->code_rate_LP = FEC_5_6; break;
- case 4: p->code_rate_LP = FEC_7_8; break;
- }
+ for (i=0; i<sizeof(init_tab); i+=2)
+ cx22702_writereg (state, init_tab[i], init_tab[i+1]);
- val = cx22702_readreg (i2c, state->demod_addr, 0x03);
- switch( (val&0x0c)>>2 ) {
- case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
- case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
- case 2: p->guard_interval = GUARD_INTERVAL_1_8; break;
- case 3: p->guard_interval = GUARD_INTERVAL_1_4; break;
- }
- switch( val&0x03 ) {
- case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
- case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+ /* init PLL */
+ if (state->config->pll_init) {
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+ state->config->pll_init(fe);
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
}
return 0;
}
-static int cx22702_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- struct cx22702_state *state = fe->data;
- struct i2c_adapter *i2c = state->i2c;
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
u8 reg0A;
u8 reg23;
- u8 ucblocks;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, &state->cx22702_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = (fe_status_t *) arg;
-
- *status = 0;
-
- reg0A = cx22702_readreg (i2c, state->demod_addr, 0x0A);
- reg23 = cx22702_readreg (i2c, state->demod_addr, 0x23);
-
- dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
- ,__FUNCTION__,reg0A,reg23);
-
- if(reg0A & 0x10) {
- *status |= FE_HAS_LOCK;
- *status |= FE_HAS_VITERBI;
- *status |= FE_HAS_SYNC;
- }
-
- if(reg0A & 0x20)
- *status |= FE_HAS_CARRIER;
-
- if(reg23 < 0xf0)
- *status |= FE_HAS_SIGNAL;
-
- break;
-
- }
-
- case FE_READ_BER:
- if(cx22702_readreg (i2c, state->demod_addr, 0xE4) & 0x02) {
- /* Realtime statistics */
- *((u32*) arg) = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7
- | (cx22702_readreg (i2c, state->demod_addr, 0xDF)&0x7F);
- } else {
- /* Averagtine statistics */
- *((u32*) arg) = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7
- | cx22702_readreg (i2c, state->demod_addr, 0xDF);
- }
- break;
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- u16 ss = cx22702_readreg (i2c, state->demod_addr, 0x23);
- *((u16*) arg) = ss;
- break;
- }
-
- /* We don't have an register for this */
- /* We'll take the inverse of the BER register */
- case FE_READ_SNR:
- {
- u16 rs_ber=0;
- if(cx22702_readreg (i2c, state->demod_addr, 0xE4) & 0x02) {
- /* Realtime statistics */
- rs_ber = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7
- | (cx22702_readreg (i2c, state->demod_addr, 0xDF)& 0x7F);
- } else {
- /* Averagine statistics */
- rs_ber = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 8
- | cx22702_readreg (i2c, state->demod_addr, 0xDF);
- }
- *((u16*) arg) = ~rs_ber;
- break;
- }
-
- case FE_READ_UNCORRECTED_BLOCKS:
- /* RS Uncorrectable Packet Count then reset */
- ucblocks = cx22702_readreg (i2c, state->demod_addr, 0xE3);
- if (state->prevUCBlocks < ucblocks) *((u32*) arg) = (ucblocks - state->prevUCBlocks);
- else *((u32*) arg) = state->prevUCBlocks - ucblocks;
- state->prevUCBlocks = ucblocks;
- break;
-
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- int ret;
-
- if((ret=cx22702_set_tps (i2c, state, p))<0) {
- dprintk ("%s: set_tps failed ret=%d\n",__FUNCTION__,ret);
- return ret;
- }
- break;
- }
-
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- u8 reg0C = cx22702_readreg (i2c, state->demod_addr, 0x0C);
-
- p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
- return cx22702_get_tps (i2c, state, &p->u.ofdm);
- }
-
- case FE_INIT:
- return cx22702_init (i2c, state);
- default:
- return -EOPNOTSUPP;
- };
+ *status = 0;
- return 0;
-}
+ reg0A = cx22702_readreg (state, 0x0A);
+ reg23 = cx22702_readreg (state, 0x23);
-/* Validate the eeprom contents, make sure content look ok.
- Get the eeprom data. */
-static int cx22702_validate_eeprom(struct i2c_adapter *i2c, int* minfreq, int* pll_type, int* pll_addr, int* demod_addr)
-{
- u8 b0 [] = { 0 };
- u8 b1 [128];
- u32 model=0;
- u8 tuner=0;
- int i,j;
-
- struct i2c_msg msg [] = {
- { .addr = I2C_EEPROM_SLAVE_ADDR, .flags = 0, .buf = b0, .len = 1 },
- { .addr = I2C_EEPROM_SLAVE_ADDR, .flags = I2C_M_RD, .buf = b1, .len = 128 }
- };
+ dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
+ ,__FUNCTION__,reg0A,reg23);
- if (i2c_transfer(i2c, msg, 2) != 2) {
- printk ("%s i2c eeprom request failed\n", __FUNCTION__);
- return -ENODEV;
+ if(reg0A & 0x10) {
+ *status |= FE_HAS_LOCK;
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
}
- if(debug) {
- dprintk ("i2c eeprom content:\n");
- j=0;
- for(i=0;i<128;i++) {
- dprintk("%02x ",b1[i]);
- if(j++==16) {
- dprintk("\n");
- j=0;
- }
- }
- dprintk("\n");
- }
+ if(reg0A & 0x20)
+ *status |= FE_HAS_CARRIER;
- if( (b1[8]!=0x84) || (b1[10]!=0x00) ) {
- printk ("%s eeprom content is not valid\n", __FUNCTION__);
- return -ENODEV;
- }
+ if(reg23 < 0xf0)
+ *status |= FE_HAS_SIGNAL;
- /* Make sure we support the board model */
- model = b1[0x1f] << 24 | b1[0x1e] << 16 | b1[0x1d] << 8 | b1[0x1c];
- switch(model) {
- case 90002:
- case 90500:
- case 90501:
- dprintk ("%s: Model #%d\n",__FUNCTION__,model);
- break;
- default:
- printk ("%s: Unknown model #%d not supported\n",__FUNCTION__,model);
- return -ENODEV;
- }
-
- /* Make sure we support the tuner */
- tuner = b1[0x2d];
- switch(tuner) {
- case 0x4B:
- dprintk ("%s: Tuner Thomson DTT 7595\n",__FUNCTION__);
- *minfreq = 177000000;
- *pll_type = PLLTYPE_DTT7595;
- break;
- case 0x4C:
- dprintk ("%s: Tuner Thomson DTT 7592\n",__FUNCTION__);
- *minfreq = 474000000;
- *pll_type = PLLTYPE_DTT7592;
- break;
- default:
- printk ("%s: Unknown tuner 0x%02x not supported\n",__FUNCTION__,tuner);
- return -ENODEV;
- }
- *pll_addr = 0x61;
- *demod_addr = 0x43;
return 0;
}
-
-/* Validate the demod, make sure we understand the hardware */
-static int cx22702_validate_demod(struct i2c_adapter *i2c, int demod_addr)
+static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber)
{
- u8 b0 [] = { 0x1f };
- u8 b1 [] = { 0 };
-
- struct i2c_msg msg [] = {
- { .addr = demod_addr, .flags = 0, .buf = b0, .len = 1 },
- { .addr = demod_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
- };
-
- if (i2c_transfer(i2c, msg, 2) != 2) {
- printk ("%s i2c demod request failed\n", __FUNCTION__);
- return -ENODEV;
- }
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
- if( (b1[0]!=0x3) ) {
- printk ("%s i2c demod type 0x(%02x) not known\n", __FUNCTION__,b1[0]);
- return -ENODEV;
+ if(cx22702_readreg (state, 0xE4) & 0x02) {
+ /* Realtime statistics */
+ *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
+ | (cx22702_readreg (state, 0xDF)&0x7F);
+ } else {
+ /* Averagtine statistics */
+ *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
+ | cx22702_readreg (state, 0xDF);
}
return 0;
}
-/* Validate the tuner PLL, make sure we understand the hardware */
-static int cx22702_validate_pll(struct i2c_adapter *i2c, int pll_addr, int demod_addr)
+static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
{
- int result=0;
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
- if( (result=pll_readreg(i2c,pll_addr,demod_addr,0xc2)) < 0)
- return result;
+ *signal_strength = cx22702_readreg (state, 0x23);
- if( (result >= 0) && (result&0x30) )
- return 0;
-
- return result;
+ return 0;
}
-/* Check we can see the I2c clients */
-static int cx22702_attach_adapter(struct i2c_adapter *adapter)
+static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr)
{
- struct cx22702_state *state;
- struct i2c_client *client;
- int ret;
- int minfreq;
- int pll_type;
- int pll_addr;
- int demod_addr;
-
- if (0 == (adapter->class & I2C_CLASS_TV_DIGITAL)) {
- dprintk("Ignoring adapter 0x%x:%s (no digital tv card).\n",
- adapter->id, adapter->name);
- return 0;
- }
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
- dprintk("Trying to attach to adapter 0x%x:%s.\n",
- adapter->id, adapter->name);
-
- if (!strcmp(adapter->name, "Conexant DVB-T reference design")) {
- printk("cx22702: Detected Conexant DVB-T card - PLL Thomson DTT7579\n");
- pll_type = PLLTYPE_DTT7579;
- pll_addr = 0x60;
- demod_addr = 0x43;
- minfreq = 177000000; // guess
+ u16 rs_ber=0;
+ if(cx22702_readreg (state, 0xE4) & 0x02) {
+ /* Realtime statistics */
+ rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
+ | (cx22702_readreg (state, 0xDF)& 0x7F);
} else {
- // default to Hauppauge Nova-T for the moment
- printk("cx22702: Detected Hauppauge Nova-T DVB-T - PLL Thomson DTT759x\n");
- ret=cx22702_validate_eeprom(adapter, &minfreq, &pll_type, &pll_addr, &demod_addr);
- if(ret < 0)
- return ret;
+ /* Averagine statistics */
+ rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8
+ | cx22702_readreg (state, 0xDF);
}
+ *snr = ~rs_ber;
- ret=cx22702_validate_demod(adapter, demod_addr);
- if(ret < 0)
- return ret;
-
- ret=cx22702_validate_pll(adapter, pll_addr, demod_addr);
- if(ret < 0)
- return ret;
+ return 0;
+}
- if ( !(state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL)) )
- return -ENOMEM;
+static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
- memset(state, 0, sizeof(struct cx22702_state));
- state->i2c = adapter;
- memcpy(&state->cx22702_info, &cx22702_info, sizeof(struct dvb_frontend_info));
- state->cx22702_info.frequency_min = minfreq;
- state->pll_type = pll_type;
- state->pll_addr = pll_addr;
- state->demod_addr = demod_addr;
+ u8 _ucblocks;
- if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
- kfree(state);
- return -ENOMEM;
- }
+ /* RS Uncorrectable Packet Count then reset */
+ _ucblocks = cx22702_readreg (state, 0xE3);
+ if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks);
+ else *ucblocks = state->prevUCBlocks - _ucblocks;
+ state->prevUCBlocks = _ucblocks;
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = state->demod_addr;
- i2c_set_clientdata(client, state);
-
- if ((ret = i2c_attach_client(client))) {
- printk("cx22702: attach failed %i\n", ret);
- kfree(client);
- kfree(state);
- return ret;
- }
- return 0;
+ return 0;
}
-static int cx22702_detach_client(struct i2c_client *client)
+static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
- struct cx22702_state *state = i2c_get_clientdata(client);
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
- if (NULL != state->dvb) {
- dvb_unregister_frontend (cx22702_ioctl, state->dvb);
- state->dvb = NULL;
- }
- i2c_detach_client(client);
- kfree(client);
- return 0;
+ u8 reg0C = cx22702_readreg (state, 0x0C);
+
+ p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
+ return cx22702_get_tps (state, &p->u.ofdm);
}
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static void cx22702_release(struct dvb_frontend* fe)
{
- struct cx22702_state *state = i2c_get_clientdata(client);
- int rc;
-
- switch(cmd) {
- case FE_REGISTER:
- if (NULL != state->dvb)
- break;
- state->dvb = arg;
- rc = dvb_register_frontend(cx22702_ioctl, state->dvb, state,
- &state->cx22702_info, THIS_MODULE);
- if (0 != rc) {
- printk("cx22702: dvb_register_frontend failed with rc=%d\n",rc);
- state->dvb = NULL;
- return rc;
- }
- break;
- case FE_UNREGISTER:
- if (NULL == state->dvb)
- break;
- dvb_unregister_frontend (cx22702_ioctl, state->dvb);
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
+ struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+ kfree(state);
}
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_CX22702,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = cx22702_attach_adapter,
- .detach_client = cx22702_detach_client,
- .command = command,
-};
-
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+static struct dvb_frontend_ops cx22702_ops;
-static int __init init_cx22702 (void)
+struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
+ struct i2c_adapter* i2c)
{
- return i2c_add_driver(&driver);
-}
+ struct cx22702_state* state = NULL;
-static void __exit exit_cx22702 (void)
-{
- if (i2c_del_driver(&driver))
- printk(KERN_ERR "cx22702: driver deregistration failed.\n");
+ /* allocate memory for the internal state */
+ state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
+ state->prevUCBlocks = 0;
+
+ /* check if the demod is there */
+ if (cx22702_readreg(state, 0x1f) != 0x3) goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init (init_cx22702);
-module_exit (exit_cx22702);
+static struct dvb_frontend_ops cx22702_ops = {
+
+ .info = {
+ .name = "Conexant CX22702 DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 177000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166666,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+ },
+
+ .release = cx22702_release,
+
+ .init = cx22702_init,
+
+ .set_frontend = cx22702_set_tps,
+ .get_frontend = cx22702_get_frontend,
+
+ .read_status = cx22702_read_status,
+ .read_ber = cx22702_read_ber,
+ .read_signal_strength = cx22702_read_signal_strength,
+ .read_snr = cx22702_read_snr,
+ .read_ucblocks = cx22702_read_ucblocks,
+};
MODULE_PARM(debug,"i");
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
-MODULE_DESCRIPTION("CX22702 / Thomson DTT 759x / Thomson DTT 7579 PLL DVB Frontend driver");
+
+MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(cx22702_attach);
diff --git a/linux/drivers/media/dvb/frontends/cx22702.h b/linux/drivers/media/dvb/frontends/cx22702.h
new file mode 100644
index 000000000..6e34f997a
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/cx22702.h
@@ -0,0 +1,46 @@
+/*
+ Conexant 22702 DVB OFDM demodulator driver
+
+ based on:
+ Alps TDMB7 DVB OFDM demodulator driver
+
+ Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+ Holger Waechtler <holger@convergence.de>
+
+ Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk>
+
+ 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 CX22702_H
+#define CX22702_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx22702_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // CX22702_H
diff --git a/linux/drivers/media/dvb/frontends/cx24110.c b/linux/drivers/media/dvb/frontends/cx24110.c
index ac4ac26bc..5121a8939 100644
--- a/linux/drivers/media/dvb/frontends/cx24110.c
+++ b/linux/drivers/media/dvb/frontends/cx24110.c
@@ -1,6 +1,5 @@
/*
cx24110 - Single Chip Satellite Channel Receiver driver module
- used on the the Pinnacle PCTV Sat cards
Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on
work
@@ -23,15 +22,6 @@
*/
-/* currently drives the Conexant cx24110 and cx24106 QPSK decoder chips,
- connected via i2c to a Conexant Fusion 878 (this uses the standard
- linux bttv driver). The tuner chip is supposed to be the Conexant
- cx24108 digital satellite tuner, driven through the tuner interface
- of the cx24110. SEC is also supplied by the cx24110.
-
- Oct-2002: Migrate to API V3 (formerly known as NEWSTRUCT)
-*/
-
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -39,44 +29,30 @@
#include <linux/init.h>
#include "dvb_frontend.h"
+#include "cx24110.h"
-#define FRONTEND_NAME "dvbfe_cx24110"
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
+struct cx24110_state {
-static int debug;
+ struct i2c_adapter* i2c;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+ struct dvb_frontend_ops ops;
+ const struct cx24110_config* config;
-static struct dvb_frontend_info cx24110_info = {
- .name = "Conexant CX24110 with CX24108 tuner, aka HM1221/HM1811",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = 1011, /* kHz for QPSK frontends, can be reduced
- to 253kHz on the cx24108 tuner */
- .frequency_tolerance = 29500,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
-/* .symbol_rate_tolerance = ???,*/
- .notifier_delay = 50, /* 1/20 s */
- .caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_RECOVER
-};
-/* fixme: are these values correct? especially ..._tolerance and caps */
+ struct dvb_frontend frontend;
-struct cx24110_state {
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
+ u32 lastber;
+ u32 lastbler;
+ u32 lastesn0;
};
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "cx24110: " args); \
+ } while (0)
+
static struct {u8 reg; u8 data;} cx24110_regdata[]=
/* Comments beginning with @ denote this value should
be the default */
@@ -140,15 +116,13 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]=
};
-static int cx24110_writereg (struct i2c_adapter *i2c, int reg, int data)
+static int cx24110_writereg (struct cx24110_state* state, int reg, int data)
{
u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = 0x55, .flags = 0, .buf = buf, .len = 2 };
-/* fixme (medium): HW allows any i2c address. 0x55 is the default, but the
- cx24110 might show up at any address */
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
int err;
- if ((err = i2c_transfer(i2c, &msg, 1)) != 1) {
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
dprintk ("%s: writereg error (err == %i, reg == 0x%02x,"
" data == 0x%02x)\n", __FUNCTION__, err, reg, data);
return -EREMOTEIO;
@@ -158,161 +132,46 @@ static int cx24110_writereg (struct i2c_adapter *i2c, int reg, int data)
}
-static u8 cx24110_readreg (struct i2c_adapter *i2c, u8 reg)
+static int cx24110_readreg (struct cx24110_state* state, u8 reg)
{
int ret;
u8 b0 [] = { reg };
u8 b1 [] = { 0 };
- struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
- { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-/* fixme (medium): address might be different from 0x55 */
- ret = i2c_transfer(i2c, msg, 2);
-
- if (ret != 2)
- dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
- return b1[0];
-}
-
-
-static int cx24108_write (struct i2c_adapter *i2c, u32 data)
-{
-/* tuner data is 21 bits long, must be left-aligned in data */
-/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
-/* FIXME (low): add error handling, avoid infinite loops if HW fails... */
-
-dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
-
- cx24110_writereg(i2c,0x6d,0x30); /* auto mode at 62kHz */
- cx24110_writereg(i2c,0x70,0x15); /* auto mode 21 bits */
- /* if the auto tuner writer is still busy, clear it out */
- while (cx24110_readreg(i2c,0x6d)&0x80)
- cx24110_writereg(i2c,0x72,0);
- /* write the topmost 8 bits */
- cx24110_writereg(i2c,0x72,(data>>24)&0xff);
- /* wait for the send to be completed */
- while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
- ;
- /* send another 8 bytes */
- cx24110_writereg(i2c,0x72,(data>>16)&0xff);
- while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
- ;
- /* and the topmost 5 bits of this byte */
- cx24110_writereg(i2c,0x72,(data>>8)&0xff);
- while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
- ;
- /* now strobe the enable line once */
- cx24110_writereg(i2c,0x6d,0x32);
- cx24110_writereg(i2c,0x6d,0x30);
-
- return 0;
-}
-
-
-static int cx24108_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
-{
-/* fixme (low): error handling */
- int i, a, n, pump;
- u32 band, pll;
-
-
- static const u32 osci[]={ 950000,1019000,1075000,1178000,
- 1296000,1432000,1576000,1718000,
- 1856000,2036000,2150000};
- static const u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,
- 0x00101000,0x00102000,0x00104000,
- 0x00108000,0x00110000,0x00120000,
- 0x00140000};
-
-#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
- dprintk("cx24110 debug: cx24108_set_tv_freq, freq=%d\n",freq);
-
- if (freq<950000)
- freq=950000; /* kHz */
- if (freq>2150000)
- freq=2150000; /* satellite IF is 950..2150MHz */
- /* decide which VCO to use for the input frequency */
- for (i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++)
- ;
- dprintk("cx24110 debug: select vco #%d (f=%d)\n",i,freq);
- band=bandsel[i];
- /* the gain values must be set by SetSymbolrate */
- /* compute the pll divider needed, from Conexant data sheet,
- resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
- depending on the divider bit. It is set to /4 on the 2 lowest
- bands */
- n=((i<=2?2:1)*freq*10L)/(XTAL/100);
- a=n%32; n/=32;
- if (a==0)
- n--;
- pump=(freq<(osci[i-1]+osci[i])/2);
- pll=0xf8000000|
- ((pump?1:2)<<(14+11))|
- ((n&0x1ff)<<(5+11))|
- ((a&0x1f)<<11);
- /* everything is shifted left 11 bits to left-align the bits in the
- 32bit word. Output to the tuner goes MSB-aligned, after all */
- dprintk("cx24110 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
- cx24108_write(i2c,band);
- /* set vga and vca to their widest-band settings, as a precaution.
- SetSymbolrate might not be called to set this up */
- cx24108_write(i2c,0x500c0000);
- cx24108_write(i2c,0x83f1f800);
- cx24108_write(i2c,pll);
- cx24110_writereg(i2c,0x56,0x7f);
-
- msleep(10); /* wait a moment for the tuner pll to lock */
-
- /* tuner pll lock can be monitored on GPIO pin 4 of cx24110 */
- while (!(cx24110_readreg(i2c,0x66)&0x20)&&i<1000)
- i++;
- dprintk("cx24110 debug: GPIO IN=%2.2x(loop=%d)\n",
- cx24110_readreg(i2c,0x66),i);
- return 0;
-
-}
-
-
-static int cx24110_initfe(struct i2c_adapter *i2c)
-{
-/* fixme (low): error handling */
- int i;
+ 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 } };
- dprintk("%s: init chip\n", __FUNCTION__);
+ ret = i2c_transfer(state->i2c, msg, 2);
- for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
- cx24110_writereg(i2c,cx24110_regdata[i].reg,cx24110_regdata[i].data);
- };
+ if (ret != 2) return ret;
- return 0;
+ return b1[0];
}
-
-static int cx24110_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion_t inversion)
+static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion)
{
/* fixme (low): error handling */
switch (inversion) {
case INVERSION_OFF:
- cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x1);
+ cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
/* AcqSpectrInvDis on. No idea why someone should want this */
- cx24110_writereg(i2c,0x5,cx24110_readreg(i2c,0x5)&0xf7);
+ cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7);
/* Initial value 0 at start of acq */
- cx24110_writereg(i2c,0x22,cx24110_readreg(i2c,0x22)&0xef);
+ cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef);
/* current value 0 */
/* The cx24110 manual tells us this reg is read-only.
But what the heck... set it ayways */
break;
case INVERSION_ON:
- cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x1);
+ cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1);
/* AcqSpectrInvDis on. No idea why someone should want this */
- cx24110_writereg(i2c,0x5,cx24110_readreg(i2c,0x5)|0x08);
+ cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08);
/* Initial value 1 at start of acq */
- cx24110_writereg(i2c,0x22,cx24110_readreg(i2c,0x22)|0x10);
+ cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10);
/* current value 1 */
break;
case INVERSION_AUTO:
- cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)&0xfe);
+ cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe);
/* AcqSpectrInvDis off. Leave initial & current states as is */
break;
default:
@@ -323,7 +182,7 @@ static int cx24110_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion
}
-static int cx24110_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec)
+static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec)
{
/* fixme (low): error handling */
@@ -339,27 +198,27 @@ static int cx24110_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec)
fec=FEC_AUTO;
if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
- cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)&0xdf);
+ cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf);
/* clear AcqVitDis bit */
- cx24110_writereg(i2c,0x18,0xae);
+ cx24110_writereg(state,0x18,0xae);
/* allow all DVB standard code rates */
- cx24110_writereg(i2c,0x05,(cx24110_readreg(i2c,0x05)&0xf0)|0x3);
+ cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3);
/* set nominal Viterbi rate 3/4 */
- cx24110_writereg(i2c,0x22,(cx24110_readreg(i2c,0x22)&0xf0)|0x3);
+ cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3);
/* set current Viterbi rate 3/4 */
- cx24110_writereg(i2c,0x1a,0x05); cx24110_writereg(i2c,0x1b,0x06);
+ cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06);
/* set the puncture registers for code rate 3/4 */
return 0;
} else {
- cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x20);
+ cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20);
/* set AcqVitDis bit */
if(rate[fec]>0) {
- cx24110_writereg(i2c,0x05,(cx24110_readreg(i2c,0x05)&0xf0)|rate[fec]);
+ cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]);
/* set nominal Viterbi rate */
- cx24110_writereg(i2c,0x22,(cx24110_readreg(i2c,0x22)&0xf0)|rate[fec]);
+ cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]);
/* set current Viterbi rate */
- cx24110_writereg(i2c,0x1a,g1[fec]);
- cx24110_writereg(i2c,0x1b,g2[fec]);
+ cx24110_writereg(state,0x1a,g1[fec]);
+ cx24110_writereg(state,0x1b,g2[fec]);
/* not sure if this is the right way: I always used AutoAcq mode */
} else
return -EOPNOTSUPP;
@@ -369,11 +228,11 @@ static int cx24110_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec)
}
-static fe_code_rate_t cx24110_get_fec (struct i2c_adapter *i2c)
+static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state)
{
int i;
- i=cx24110_readreg(i2c,0x22)&0x0f;
+ i=cx24110_readreg(state,0x22)&0x0f;
if(!(i&0x08)) {
return FEC_1_2 + i - 1;
} else {
@@ -386,16 +245,13 @@ static fe_code_rate_t cx24110_get_fec (struct i2c_adapter *i2c)
}
-static int cx24110_set_symbolrate (struct i2c_adapter *i2c, u32 srate)
+static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
{
/* fixme (low): add error handling */
u32 ratio;
u32 tmp, fclk, BDRI;
static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
- static const u32 vca[]={0x80f03800,0x81f0f800,0x83f1f800};
- static const u32 vga[]={0x5f8fc000,0x580f0000,0x500c0000};
- static const u8 filtune[]={0xa2,0xcc,0x66};
int i;
dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
@@ -409,22 +265,22 @@ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
/* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
R06[3:0] PLLphaseDetGain */
- tmp=cx24110_readreg(i2c,0x07)&0xfc;
+ tmp=cx24110_readreg(state,0x07)&0xfc;
if(srate<90999000UL/4) { /* sample rate 45MHz*/
- cx24110_writereg(i2c,0x07,tmp);
- cx24110_writereg(i2c,0x06,0x78);
+ cx24110_writereg(state,0x07,tmp);
+ cx24110_writereg(state,0x06,0x78);
fclk=90999000UL/2;
} else if(srate<60666000UL/2) { /* sample rate 60MHz */
- cx24110_writereg(i2c,0x07,tmp|0x1);
- cx24110_writereg(i2c,0x06,0xa5);
+ cx24110_writereg(state,0x07,tmp|0x1);
+ cx24110_writereg(state,0x06,0xa5);
fclk=60666000UL;
} else if(srate<80888000UL/2) { /* sample rate 80MHz */
- cx24110_writereg(i2c,0x07,tmp|0x2);
- cx24110_writereg(i2c,0x06,0x87);
+ cx24110_writereg(state,0x07,tmp|0x2);
+ cx24110_writereg(state,0x06,0x87);
fclk=80888000UL;
} else { /* sample rate 90MHz */
- cx24110_writereg(i2c,0x07,tmp|0x3);
- cx24110_writereg(i2c,0x06,0x78);
+ cx24110_writereg(state,0x07,tmp|0x3);
+ cx24110_writereg(state,0x06,0x78);
fclk=90999000UL;
};
dprintk("cx24110 debug: fclk %d Hz\n",fclk);
@@ -453,318 +309,339 @@ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
dprintk("fclk = %d\n", fclk);
dprintk("ratio= %08x\n", ratio);
- cx24110_writereg(i2c, 0x1, (ratio>>16)&0xff);
- cx24110_writereg(i2c, 0x2, (ratio>>8)&0xff);
- cx24110_writereg(i2c, 0x3, (ratio)&0xff);
+ cx24110_writereg(state, 0x1, (ratio>>16)&0xff);
+ cx24110_writereg(state, 0x2, (ratio>>8)&0xff);
+ cx24110_writereg(state, 0x3, (ratio)&0xff);
+
+ return 0;
+
+}
+
- /* please see the cx24108 data sheet, this controls tuner gain
- and bandwidth settings depending on the symbol rate */
- cx24108_write(i2c,vga[i]);
- cx24108_write(i2c,vca[i]); /* gain is set on tuner chip */
- cx24110_writereg(i2c,0x56,filtune[i]); /* bw is contolled by filtune voltage */
+
+
+
+
+
+
+
+
+
+
+int cx24110_pll_write (struct dvb_frontend* fe, u32 data)
+{
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
+/* tuner data is 21 bits long, must be left-aligned in data */
+/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
+/* FIXME (low): add error handling, avoid infinite loops if HW fails... */
+
+ dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
+
+ cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
+ cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
+
+ /* if the auto tuner writer is still busy, clear it out */
+ while (cx24110_readreg(state,0x6d)&0x80)
+ cx24110_writereg(state,0x72,0);
+
+ /* write the topmost 8 bits */
+ cx24110_writereg(state,0x72,(data>>24)&0xff);
+
+ /* wait for the send to be completed */
+ while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+ ;
+
+ /* send another 8 bytes */
+ cx24110_writereg(state,0x72,(data>>16)&0xff);
+ while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+ ;
+
+ /* and the topmost 5 bits of this byte */
+ cx24110_writereg(state,0x72,(data>>8)&0xff);
+ while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
+ ;
+
+ /* now strobe the enable line once */
+ cx24110_writereg(state,0x6d,0x32);
+ cx24110_writereg(state,0x6d,0x30);
return 0;
+}
+
+
+static int cx24110_initfe(struct dvb_frontend* fe)
+{
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+/* fixme (low): error handling */
+ int i;
+
+ dprintk("%s: init chip\n", __FUNCTION__);
+
+ for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
+ cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
+ };
+
+ if (state->config->pll_init) state->config->pll_init(fe);
+
+ return 0;
}
-static int cx24110_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage)
+static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
switch (voltage) {
case SEC_VOLTAGE_13:
- return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0xc0);
+ return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0);
case SEC_VOLTAGE_18:
- return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0x40);
+ return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40);
default:
return -EINVAL;
};
}
-static void cx24110_send_diseqc_msg(struct i2c_adapter *i2c,
- struct dvb_diseqc_master_cmd *cmd)
+static int cx24110_send_diseqc_msg(struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *cmd)
{
int i, rv;
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
for (i = 0; i < cmd->msg_len; i++)
- cx24110_writereg(i2c, 0x79 + i, cmd->msg[i]);
+ cx24110_writereg(state, 0x79 + i, cmd->msg[i]);
- rv = cx24110_readreg(i2c, 0x76);
+ rv = cx24110_readreg(state, 0x76);
- cx24110_writereg(i2c, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
- for (i=500; i-- > 0 && !(cx24110_readreg(i2c,0x76)&0x40);)
+ cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3));
+ for (i=500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40);)
; /* wait for LNB ready */
-}
+ return 0;
+}
-static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- struct cx24110_state *state = fe->data;
- struct i2c_adapter *i2c = state->i2c;
- static int lastber=0, lastbyer=0,lastbler=0, lastesn0=0, sum_bler=0;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, &cx24110_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = arg;
- int sync = cx24110_readreg (i2c, 0x55);
-
- *status = 0;
-
- if (sync & 0x10)
- *status |= FE_HAS_SIGNAL;
-
- if (sync & 0x08)
- *status |= FE_HAS_CARRIER;
-
- sync = cx24110_readreg (i2c, 0x08);
-
- if (sync & 0x40)
- *status |= FE_HAS_VITERBI;
-
- if (sync & 0x20)
- *status |= FE_HAS_SYNC;
-
- if ((sync & 0x60) == 0x60)
- *status |= FE_HAS_LOCK;
-
- if(cx24110_readreg(i2c,0x10)&0x40) {
- /* the RS error counter has finished one counting window */
- cx24110_writereg(i2c,0x10,0x60); /* select the byer reg */
- lastbyer=cx24110_readreg(i2c,0x12)|
- (cx24110_readreg(i2c,0x13)<<8)|
- (cx24110_readreg(i2c,0x14)<<16);
- cx24110_writereg(i2c,0x10,0x70); /* select the bler reg */
- lastbler=cx24110_readreg(i2c,0x12)|
- (cx24110_readreg(i2c,0x13)<<8)|
- (cx24110_readreg(i2c,0x14)<<16);
- cx24110_writereg(i2c,0x10,0x20); /* start new count window */
- sum_bler += lastbler;
- }
- if(cx24110_readreg(i2c,0x24)&0x10) {
- /* the Viterbi error counter has finished one counting window */
- cx24110_writereg(i2c,0x24,0x04); /* select the ber reg */
- lastber=cx24110_readreg(i2c,0x25)|
- (cx24110_readreg(i2c,0x26)<<8);
- cx24110_writereg(i2c,0x24,0x04); /* start new count window */
- cx24110_writereg(i2c,0x24,0x14);
- }
- if(cx24110_readreg(i2c,0x6a)&0x80) {
- /* the Es/N0 error counter has finished one counting window */
- lastesn0=cx24110_readreg(i2c,0x69)|
- (cx24110_readreg(i2c,0x68)<<8);
- cx24110_writereg(i2c,0x6a,0x84); /* start new count window */
- }
- break;
- }
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
- case FE_READ_BER:
- {
- u32 *ber = (u32 *) arg;
+ int sync = cx24110_readreg (state, 0x55);
- *ber = lastber;
-/* fixme (maybe): value range is 16 bit. Scale? */
- break;
- }
+ *status = 0;
- case FE_READ_SIGNAL_STRENGTH:
- {
-/* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
- u8 signal = cx24110_readreg (i2c, 0x27)+128;
- *((u16*) arg) = (signal << 8) | signal;
- break;
- }
+ if (sync & 0x10)
+ *status |= FE_HAS_SIGNAL;
- case FE_READ_SNR:
- {
-/* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
- *(u16*) arg = lastesn0;
- break;
- }
+ if (sync & 0x08)
+ *status |= FE_HAS_CARRIER;
- case FE_READ_UNCORRECTED_BLOCKS:
- {
- *(u16*) arg = sum_bler&0xffff;
- sum_bler=0;
- break;
- }
+ sync = cx24110_readreg (state, 0x08);
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
+ if (sync & 0x40)
+ *status |= FE_HAS_VITERBI;
- cx24108_set_tv_freq (i2c, p->frequency);
- cx24110_set_inversion (i2c, p->inversion);
- cx24110_set_fec (i2c, p->u.qpsk.fec_inner);
- cx24110_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
- cx24110_writereg(i2c,0x04,0x05); /* start aquisition */
- break;
- }
+ if (sync & 0x20)
+ *status |= FE_HAS_SYNC;
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- s32 afc; unsigned sclk;
+ if ((sync & 0x60) == 0x60)
+ *status |= FE_HAS_LOCK;
-/* cannot read back tuner settings (freq). Need to have some private storage */
+ return 0;
+}
- sclk = cx24110_readreg (i2c, 0x07) & 0x03;
-/* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
- * Need 64 bit arithmetic. Is thiss possible in the kernel? */
- if (sclk==0) sclk=90999000L/2L;
- else if (sclk==1) sclk=60666000L;
- else if (sclk==2) sclk=80888000L;
- else sclk=90999000L;
- sclk>>=8;
- afc = sclk*(cx24110_readreg (i2c, 0x44)&0x1f)+
- ((sclk*cx24110_readreg (i2c, 0x45))>>8)+
- ((sclk*cx24110_readreg (i2c, 0x46))>>16);
-
- p->frequency += afc;
- p->inversion = (cx24110_readreg (i2c, 0x22) & 0x10) ?
- INVERSION_ON : INVERSION_OFF;
- p->u.qpsk.fec_inner = cx24110_get_fec (i2c);
- break;
+static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
+ /* fixme (maybe): value range is 16 bit. Scale? */
+ if(cx24110_readreg(state,0x24)&0x10) {
+ /* the Viterbi error counter has finished one counting window */
+ cx24110_writereg(state,0x24,0x04); /* select the ber reg */
+ state->lastber=cx24110_readreg(state,0x25)|
+ (cx24110_readreg(state,0x26)<<8);
+ cx24110_writereg(state,0x24,0x04); /* start new count window */
+ cx24110_writereg(state,0x24,0x14);
}
+ *ber = state->lastber;
- case FE_SLEEP:
-/* cannot do this from the FE end. How to communicate this to the place where it can be done? */
- break;
- case FE_INIT:
- return cx24110_initfe(i2c);
-
- case FE_SET_TONE:
- return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&~0x10)|((((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?0x10:0));
- case FE_SET_VOLTAGE:
- return cx24110_set_voltage (i2c, (fe_sec_voltage_t) arg);
-
- case FE_DISEQC_SEND_MASTER_CMD:
- // FIXME Status?
- cx24110_send_diseqc_msg(i2c, (struct dvb_diseqc_master_cmd*) arg);
- return 0;
-
- default:
- return -EOPNOTSUPP;
- };
-
- return 0;
+ return 0;
}
-static struct i2c_client client_template;
-
-static int attach_adapter (struct i2c_adapter *adapter)
+static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
{
- struct cx24110_state *state;
- struct i2c_client *client;
- int ret = 0;
- u8 sig;
-
- dprintk("Trying to attach to adapter 0x%x:%s.\n",
- adapter->id, adapter->name);
-
- sig = cx24110_readreg (adapter, 0x00);
- if ( sig != 0x5a && sig != 0x69 )
- return -ENODEV;
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
- if ( !(state = kmalloc(sizeof(struct cx24110_state), GFP_KERNEL)) )
- return -ENOMEM;
-
- memset(state, 0, sizeof(struct cx24110_state));
- state->i2c = adapter;
-
- if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
- kfree(state);
- return -ENOMEM;
- }
+/* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
+ u8 signal = cx24110_readreg (state, 0x27)+128;
+ *signal_strength = (signal << 8) | signal;
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = 0x55;
- i2c_set_clientdata(client, state);
+ return 0;
+}
- if ((ret = i2c_attach_client(client))) {
- kfree(client);
- kfree(state);
- return ret;
+static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
+ /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
+ if(cx24110_readreg(state,0x6a)&0x80) {
+ /* the Es/N0 error counter has finished one counting window */
+ state->lastesn0=cx24110_readreg(state,0x69)|
+ (cx24110_readreg(state,0x68)<<8);
+ cx24110_writereg(state,0x6a,0x84); /* start new count window */
}
+ *snr = state->lastesn0;
- BUG_ON(!state->dvb);
+ return 0;
+}
- if ((ret = dvb_register_frontend(cx24110_ioctl, state->dvb, state,
- &cx24110_info, THIS_MODULE))) {
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return ret;
+static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+ u32 lastbyer;
+
+ if(cx24110_readreg(state,0x10)&0x40) {
+ /* the RS error counter has finished one counting window */
+ cx24110_writereg(state,0x10,0x60); /* select the byer reg */
+ lastbyer=cx24110_readreg(state,0x12)|
+ (cx24110_readreg(state,0x13)<<8)|
+ (cx24110_readreg(state,0x14)<<16);
+ cx24110_writereg(state,0x10,0x70); /* select the bler reg */
+ state->lastbler=cx24110_readreg(state,0x12)|
+ (cx24110_readreg(state,0x13)<<8)|
+ (cx24110_readreg(state,0x14)<<16);
+ cx24110_writereg(state,0x10,0x20); /* start new count window */
}
+ *ucblocks = state->lastbler;
return 0;
}
-static int detach_client (struct i2c_client *client)
+static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
- struct cx24110_state *state = i2c_get_clientdata(client);
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+
+ state->config->pll_set(fe, p);
+ cx24110_set_inversion (state, p->inversion);
+ cx24110_set_fec (state, p->u.qpsk.fec_inner);
+ cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
+ cx24110_writereg(state,0x04,0x05); /* start aquisition */
- dvb_unregister_frontend(cx24110_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
return 0;
}
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
- struct cx24110_state *state = i2c_get_clientdata(client);
-
- switch(cmd) {
- case FE_REGISTER:
- state->dvb = arg;
- break;
- case FE_UNREGISTER:
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
+ s32 afc; unsigned sclk;
+
+/* cannot read back tuner settings (freq). Need to have some private storage */
+
+ sclk = cx24110_readreg (state, 0x07) & 0x03;
+/* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
+ * Need 64 bit arithmetic. Is thiss possible in the kernel? */
+ if (sclk==0) sclk=90999000L/2L;
+ else if (sclk==1) sclk=60666000L;
+ else if (sclk==2) sclk=80888000L;
+ else sclk=90999000L;
+ sclk>>=8;
+ afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+
+ ((sclk*cx24110_readreg (state, 0x45))>>8)+
+ ((sclk*cx24110_readreg (state, 0x46))>>16);
+
+ p->frequency += afc;
+ p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
+ INVERSION_ON : INVERSION_OFF;
+ p->u.qpsk.fec_inner = cx24110_get_fec (state);
return 0;
}
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_CX24110,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
+static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv;
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+ return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0));
+}
-static int __init cx24110_init(void)
+static void cx24110_release(struct dvb_frontend* fe)
{
- return i2c_add_driver(&driver);
+ struct cx24110_state* state = (struct cx24110_state*) fe->demodulator_priv;
+ kfree(state);
}
-static void __exit cx24110_exit(void)
+static struct dvb_frontend_ops cx24110_ops;
+
+struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+ struct i2c_adapter* i2c)
{
- if (i2c_del_driver(&driver))
- printk(KERN_ERR "cx24110: driver deregistration failed.\n");
+ struct cx24110_state* state = NULL;
+ int ret;
+
+ /* allocate memory for the internal state */
+ state = (struct cx24110_state*) kmalloc(sizeof(struct cx24110_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
+ state->lastber = 0;
+ state->lastbler = 0;
+ state->lastesn0 = 0;
+
+ /* check if the demod is there */
+ ret = cx24110_readreg(state, 0x00);
+ if ((ret != 0x5a) && (ret != 0x69)) goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init(cx24110_init);
-module_exit(cx24110_exit);
+static struct dvb_frontend_ops cx24110_ops = {
+
+ .info = {
+ .name = "Conexant CX24110 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 1011, /* kHz for QPSK frontends */
+ .frequency_tolerance = 29500,
+ .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_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_RECOVER
+ },
+
+ .release = cx24110_release,
+
+ .init = cx24110_initfe,
+ .set_frontend = cx24110_set_frontend,
+ .get_frontend = cx24110_get_frontend,
+ .read_status = cx24110_read_status,
+ .read_ber = cx24110_read_ber,
+ .read_signal_strength = cx24110_read_signal_strength,
+ .read_snr = cx24110_read_snr,
+ .read_ucblocks = cx24110_read_ucblocks,
+
+ .diseqc_send_master_cmd = cx24110_send_diseqc_msg,
+ .set_tone = cx24110_set_tone,
+ .set_voltage = cx24110_set_voltage,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("DVB Frontend driver module for the Conexant cx24108/cx24110 chipset");
+MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver");
MODULE_AUTHOR("Peter Hettkamp");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(cx24110_attach);
+EXPORT_SYMBOL(cx24110_pll_write);
diff --git a/linux/drivers/media/dvb/frontends/cx24110.h b/linux/drivers/media/dvb/frontends/cx24110.h
new file mode 100644
index 000000000..6b663f474
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/cx24110.h
@@ -0,0 +1,45 @@
+/*
+ cx24110 - Single Chip Satellite Channel Receiver driver module
+
+ Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on
+ work
+ Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+
+ 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 CX24110_H
+#define CX24110_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24110_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+ struct i2c_adapter* i2c);
+
+extern int cx24110_pll_write(struct dvb_frontend* fe, u32 data);
+
+#endif // CX24110_H
diff --git a/linux/drivers/media/dvb/frontends/dib3000mb.c b/linux/drivers/media/dvb/frontends/dib3000mb.c
index 315784ae7..79d4a11e7 100644
--- a/linux/drivers/media/dvb/frontends/dib3000mb.c
+++ b/linux/drivers/media/dvb/frontends/dib3000mb.c
@@ -1,9 +1,9 @@
/*
- * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB
* DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
- *
+ *
* based on GPL code from DibCom, which has
*
* Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
@@ -13,12 +13,14 @@
* published by the Free Software Foundation, version 2.
*
* Acknowledgements
- *
+ *
* Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
* sources, on which this driver (and the dvb-dibusb) are based.
*
+ * $Id: dib3000mb.c,v 1.13 2004/10/28 17:37:07 quincy Exp $$
+ *
* see Documentation/dvb/README.dibusb for more information
- *
+ *
*/
#include <linux/config.h>
@@ -30,9 +32,23 @@
#include <linux/delay.h>
#include "dvb_frontend.h"
-
+#include "dib3000mb_priv.h"
#include "dib3000mb.h"
+
+struct dib3000mb_state {
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct dib3000mb_config* config;
+
+ struct dvb_frontend frontend;
+};
+
+
/* debug */
#ifdef CONFIG_DVB_DIBCOM_DEBUG
@@ -54,34 +70,11 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=setfe,1
/* Version information */
#define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000-MB DVB-T frontend"
+#define DRIVER_DESC "DiBcom 3000-MB DVB-T Demodulator driver"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-struct dib3000mb_state {
- struct i2c_client *i2c;
- struct dvb_adapter *dvb;
- u16 manufactor_id;
- u16 device_id;
-};
-
-static struct dvb_frontend_info dib3000mb_info = {
- .name = "DiBcom 3000-MB DVB-T",
- .type = FE_OFDM,
- .frequency_min = 44250000,
- .frequency_max = 867250000,
- .frequency_stepsize = 62500,
- .caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_HIERARCHY_AUTO,
-};
-
-
-#define rd(reg) dib3000mb_read_reg(state->i2c,reg)
-#define wr(reg,val) if (dib3000mb_write_reg(state->i2c,reg,val)) \
+#define rd(reg) dib3000mb_read_reg(state,reg)
+#define wr(reg,val) if (dib3000mb_write_reg(state,reg,val)) \
{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
#define wr_foreach(a,v) { int i; \
deb_alot("sizeof: %d %d\n",sizeof(a),sizeof(v));\
@@ -89,228 +82,53 @@ static struct dvb_frontend_info dib3000mb_info = {
wr(a[i],v[i]); \
}
-static u16 dib3000mb_read_reg(struct i2c_client *i2c, u16 reg)
+static u16 dib3000mb_read_reg(struct dib3000mb_state *state, u16 reg)
{
u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
- u8 rb[2];
+ u8 rb[2];
struct i2c_msg msg[] = {
- { .addr = i2c->addr, .flags = 0, .buf = wb, .len = 2 },
- { .addr = i2c->addr, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+ { .addr = state->config->demod_address, .flags = 0, .buf = wb, .len = 2 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
};
deb_alot("reading from i2c bus (reg: %d)\n",reg);
- if (i2c_transfer(i2c->adapter,msg,2) != 2)
+ if (i2c_transfer(state->i2c, msg, 2) != 2)
deb_alot("i2c read error\n");
return (rb[0] << 8) | rb[1];
}
-static int dib3000mb_write_reg(struct i2c_client *i2c,u16 reg, u16 val)
+static int dib3000mb_write_reg(struct dib3000mb_state *state, u16 reg, u16 val)
{
- u8 b[] = {
- (reg >> 8) & 0xff, reg & 0xff,
+ u8 b[] = {
+ (reg >> 8) & 0xff, reg & 0xff,
(val >> 8) & 0xff, val & 0xff,
};
- struct i2c_msg msg[] = { { .addr = i2c->addr, .flags = 0, .buf = b, .len = 4 } };
+ struct i2c_msg msg[] = { { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 4 } };
deb_alot("writing to i2c bus (reg: %d, val: %d)\n",reg,val);
- return i2c_transfer(i2c->adapter,msg,1) != 1 ? -EREMOTEIO : 0 ;
+ return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
}
-static int dib3000mb_tuner_thomson_cable_eu(struct dib3000mb_state *state,
- u32 freq)
-{
- u32 tfreq = (freq + 36125000) / 62500;
- unsigned int addr;
- int vu,p0,p1,p2;
-
- if (freq > 403250000)
- vu = 1, p2 = 1, p1 = 0, p0 = 1;
- else if (freq > 115750000)
- vu = 0, p2 = 1, p1 = 1, p0 = 0;
- else if (freq > 44250000)
- vu = 0, p2 = 0, p1 = 1, p0 = 1;
- else
- return -EINVAL;
- /* TODO better solution for i2c->addr handling */
- addr = state->i2c->addr;
- state->i2c->addr = DIB3000MB_TUNER_ADDR_DEFAULT;
- wr(tfreq & 0x7fff,(0x8e << 8) + ((vu << 7) | (p2 << 2) | (p1 << 1) | p0) );
- state->i2c->addr = addr;
-
- return 0;
-}
-
-static int dib3000mb_get_frontend(struct dib3000mb_state *state,
- struct dvb_frontend_parameters *fep)
-{
- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
- fe_code_rate_t *cr;
- u16 tps_val;
- int inv_test1,inv_test2;
- u32 dds_val, threshold = 0x800000;
-
- if (!rd(DIB3000MB_REG_TPS_LOCK))
- return 0;
-
- dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
- if (dds_val & threshold)
- inv_test1 = 0;
- else if (dds_val == threshold)
- inv_test1 = 1;
- else
- inv_test1 = 2;
-
- dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
- if (dds_val & threshold)
- inv_test2 = 0;
- else if (dds_val == threshold)
- inv_test2 = 1;
- else
- inv_test2 = 2;
-
- fep->inversion =
- ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0))
- ||
- ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2));
-
- deb_getf("inversion %d %d, %d\n",inv_test2,inv_test1, fep->inversion);
-
- switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
- case DIB3000MB_QAM_QPSK:
- deb_getf("QPSK ");
- ofdm->constellation = QPSK;
- break;
- case DIB3000MB_QAM_QAM16:
- deb_getf("QAM16 ");
- ofdm->constellation = QAM_16;
- break;
- case DIB3000MB_QAM_QAM64:
- deb_getf("QAM64 ");
- ofdm->constellation = QAM_64;
- break;
- default:
- err("Unexpected constellation returned by TPS (%d)",tps_val);
- break;
- }
- deb_getf("TPS: %d\n",tps_val);
-
- if (rd(DIB3000MB_REG_TPS_HRCH)) {
- deb_getf("HRCH ON\n");
- tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
- cr = &ofdm->code_rate_LP;
- ofdm->code_rate_HP = FEC_NONE;
-
- switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
- case DIB3000MB_VIT_ALPHA_OFF:
- deb_getf("HIERARCHY_NONE ");
- ofdm->hierarchy_information = HIERARCHY_NONE;
- break;
- case DIB3000MB_VIT_ALPHA_1:
- deb_getf("HIERARCHY_1 ");
- ofdm->hierarchy_information = HIERARCHY_1;
- break;
- case DIB3000MB_VIT_ALPHA_2:
- deb_getf("HIERARCHY_2 ");
- ofdm->hierarchy_information = HIERARCHY_2;
- break;
- case DIB3000MB_VIT_ALPHA_4:
- deb_getf("HIERARCHY_4 ");
- ofdm->hierarchy_information = HIERARCHY_4;
- break;
- default:
- err("Unexpected ALPHA value returned by TPS (%d)",tps_val);
- }
- deb_getf("TPS: %d\n",tps_val);
- } else {
- deb_getf("HRCH OFF\n");
- tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
- cr = &ofdm->code_rate_HP;
- ofdm->code_rate_LP = FEC_NONE;
- ofdm->hierarchy_information = HIERARCHY_NONE;
- }
-
- switch (tps_val) {
- case DIB3000MB_FEC_1_2:
- deb_getf("FEC_1_2 ");
- *cr = FEC_1_2;
- break;
- case DIB3000MB_FEC_2_3:
- deb_getf("FEC_2_3 ");
- *cr = FEC_2_3;
- break;
- case DIB3000MB_FEC_3_4:
- deb_getf("FEC_3_4 ");
- *cr = FEC_3_4;
- break;
- case DIB3000MB_FEC_5_6:
- deb_getf("FEC_5_6 ");
- *cr = FEC_4_5;
- break;
- case DIB3000MB_FEC_7_8:
- deb_getf("FEC_7_8 ");
- *cr = FEC_7_8;
- break;
- default:
- err("Unexpected FEC returned by TPS (%d)",tps_val);
- break;
- }
- deb_getf("TPS: %d\n",tps_val);
-
- switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
- case DIB3000MB_GUARD_TIME_1_32:
- deb_getf("GUARD_INTERVAL_1_32 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_32;
- break;
- case DIB3000MB_GUARD_TIME_1_16:
- deb_getf("GUARD_INTERVAL_1_16 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_16;
- break;
- case DIB3000MB_GUARD_TIME_1_8:
- deb_getf("GUARD_INTERVAL_1_8 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_8;
- break;
- case DIB3000MB_GUARD_TIME_1_4:
- deb_getf("GUARD_INTERVAL_1_4 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_4;
- break;
- default:
- err("Unexpected Guard Time returned by TPS (%d)",tps_val);
- break;
- }
- deb_getf("TPS: %d\n",tps_val);
-
- switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
- case DIB3000MB_FFT_2K:
- deb_getf("TRANSMISSION_MODE_2K ");
- ofdm->transmission_mode = TRANSMISSION_MODE_2K;
- break;
- case DIB3000MB_FFT_8K:
- deb_getf("TRANSMISSION_MODE_8K ");
- ofdm->transmission_mode = TRANSMISSION_MODE_8K;
- break;
- default:
- err("unexpected transmission mode return by TPS (%d)",tps_val);
- }
- deb_getf("TPS: %d\n",tps_val);
- return 0;
-}
+static int dib3000mb_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep, int tuner);
-static int dib3000mb_set_frontend(struct dib3000mb_state *state,
- struct dvb_frontend_parameters *fep, int tuner);
+static int dib3000mb_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep);
-static int dib3000mb_fe_read_search_status(struct dib3000mb_state *state)
+static int dib3000mb_fe_read_search_status(struct dvb_frontend* fe)
{
u16 irq;
struct dvb_frontend_parameters fep;
-
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+
irq = rd(DIB3000MB_REG_AS_IRQ_PENDING);
if (irq & 0x02) {
if (rd(DIB3000MB_REG_LOCK2_VALUE) & 0x01) {
- if (dib3000mb_get_frontend(state,&fep) == 0) {
+ if (dib3000mb_get_frontend(fe, &fep) == 0) {
deb_setf("reading tuning data from frontend succeeded.\n");
- return dib3000mb_set_frontend(state,&fep,0) == 0;
+ return dib3000mb_set_frontend(fe, &fep, 0) == 0;
} else {
deb_setf("reading tuning data failed -> tuning failed.\n");
return 0;
@@ -327,39 +145,37 @@ static int dib3000mb_fe_read_search_status(struct dib3000mb_state *state)
return -1;
}
-static int dib3000mb_set_frontend(struct dib3000mb_state *state,
- struct dvb_frontend_parameters *fep, int tuner)
+static int dib3000mb_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep, int tuner)
{
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
fe_code_rate_t fe_cr = FEC_NONE;
- int search_state,seq;
-
+ int search_state, seq;
+
if (tuner) {
wr(DIB3000MB_REG_TUNER,
- DIB3000MB_ACTIVATE_TUNER_XFER( DIB3000MB_TUNER_ADDR_DEFAULT ) );
- dib3000mb_tuner_thomson_cable_eu(state,fep->frequency);
-
- /* wait for tuner */
- msleep(1);
- wr(DIB3000MB_REG_TUNER,
- DIB3000MB_DEACTIVATE_TUNER_XFER( DIB3000MB_TUNER_ADDR_DEFAULT ) );
+ DIB3000MB_ACTIVATE_TUNER_XFER(state->config->pll_addr << 1));
+ state->config->pll_set(fe, fep);
+ wr(DIB3000MB_REG_TUNER,
+ DIB3000MB_DEACTIVATE_TUNER_XFER(state->config->pll_addr << 1));
deb_setf("bandwidth: ");
switch (ofdm->bandwidth) {
case BANDWIDTH_8_MHZ:
deb_setf("8 MHz\n");
- wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
- wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
+ wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
+ wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
break;
case BANDWIDTH_7_MHZ:
deb_setf("7 MHz\n");
- wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[1]);
- wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_7mhz);
+ wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]);
+ wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz);
break;
case BANDWIDTH_6_MHZ:
deb_setf("6 MHz\n");
- wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[0]);
- wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_6mhz);
+ wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]);
+ wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz);
break;
case BANDWIDTH_AUTO:
return -EOPNOTSUPP;
@@ -367,301 +183,491 @@ static int dib3000mb_set_frontend(struct dib3000mb_state *state,
err("unkown bandwidth value.");
return -EINVAL;
}
- }
- wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
+ }
+ wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
deb_setf("transmission mode: ");
switch (ofdm->transmission_mode) {
case TRANSMISSION_MODE_2K:
deb_setf("2k\n");
- wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_2K);
+ wr(DIB3000MB_REG_FFT, DIB3000MB_FFT_2K);
break;
case TRANSMISSION_MODE_8K:
deb_setf("8k\n");
- wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_8K);
+ wr(DIB3000MB_REG_FFT, DIB3000MB_FFT_8K);
break;
case TRANSMISSION_MODE_AUTO:
deb_setf("auto\n");
- wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_AUTO);
+ wr(DIB3000MB_REG_FFT, DIB3000MB_FFT_AUTO);
break;
default:
return -EINVAL;
}
-
+
deb_setf("guard: ");
switch (ofdm->guard_interval) {
case GUARD_INTERVAL_1_32:
deb_setf("1_32\n");
- wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_32);
+ wr(DIB3000MB_REG_GUARD_TIME, DIB3000MB_GUARD_TIME_1_32);
break;
case GUARD_INTERVAL_1_16:
deb_setf("1_16\n");
- wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_16);
+ wr(DIB3000MB_REG_GUARD_TIME, DIB3000MB_GUARD_TIME_1_16);
break;
case GUARD_INTERVAL_1_8:
deb_setf("1_8\n");
- wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_8);
+ wr(DIB3000MB_REG_GUARD_TIME, DIB3000MB_GUARD_TIME_1_8);
break;
case GUARD_INTERVAL_1_4:
deb_setf("1_4\n");
- wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_4);
+ wr(DIB3000MB_REG_GUARD_TIME, DIB3000MB_GUARD_TIME_1_4);
break;
case GUARD_INTERVAL_AUTO:
deb_setf("auto\n");
- wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_AUTO);
+ wr(DIB3000MB_REG_GUARD_TIME, DIB3000MB_GUARD_TIME_AUTO);
break;
default:
return -EINVAL;
}
- deb_setf("invsersion: ");
+ deb_setf("inversion: ");
switch (fep->inversion) {
- case INVERSION_AUTO:
- deb_setf("auto\n");
- break;
case INVERSION_OFF:
- deb_setf("on\n");
- wr(DIB3000MB_REG_DDS_INV,DIB3000MB_DDS_INV_OFF);
+ deb_setf("off\n");
+ wr(DIB3000MB_REG_DDS_INV, DIB3000MB_DDS_INV_OFF);
+ break;
+ case INVERSION_AUTO:
+ deb_setf("auto ");
break;
case INVERSION_ON:
deb_setf("on\n");
- wr(DIB3000MB_REG_DDS_INV,DIB3000MB_DDS_INV_ON);
+ wr(DIB3000MB_REG_DDS_INV, DIB3000MB_DDS_INV_ON);
break;
default:
return -EINVAL;
}
-
+
deb_setf("constellation: ");
switch (ofdm->constellation) {
case QPSK:
deb_setf("qpsk\n");
- wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QPSK);
+ wr(DIB3000MB_REG_QAM, DIB3000MB_QAM_QPSK);
break;
case QAM_16:
deb_setf("qam16\n");
- wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QAM16);
+ wr(DIB3000MB_REG_QAM, DIB3000MB_QAM_QAM16);
break;
case QAM_64:
deb_setf("qam64\n");
- wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QAM64);
+ wr(DIB3000MB_REG_QAM, DIB3000MB_QAM_QAM64);
break;
case QAM_AUTO:
break;
default:
return -EINVAL;
}
- deb_setf("hierachy: ");
+ deb_setf("hierachy: ");
switch (ofdm->hierarchy_information) {
case HIERARCHY_NONE:
deb_setf("none ");
- /* fall through alpha is 1, even when HIERARCHY is NONE */
+ /* fall through */
case HIERARCHY_1:
- deb_setf("alpha=1\n");
- wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_1);
+ deb_setf("alpha=1\n");
+ wr(DIB3000MB_REG_VIT_ALPHA, DIB3000MB_VIT_ALPHA_1);
break;
case HIERARCHY_2:
- deb_setf("alpha=2\n");
- wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_2);
+ deb_setf("alpha=2\n");
+ wr(DIB3000MB_REG_VIT_ALPHA, DIB3000MB_VIT_ALPHA_2);
break;
case HIERARCHY_4:
- deb_setf("alpha=4\n");
- wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_4);
- break;
+ deb_setf("alpha=4\n");
+ wr(DIB3000MB_REG_VIT_ALPHA, DIB3000MB_VIT_ALPHA_4);
+ break;
case HIERARCHY_AUTO:
- deb_setf("alpha=auto\n");
- wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_AUTO);
+ deb_setf("alpha=auto\n");
+ wr(DIB3000MB_REG_VIT_ALPHA, DIB3000MB_VIT_ALPHA_AUTO);
break;
default:
return -EINVAL;
}
-
+
deb_setf("hierarchy: ");
if (ofdm->hierarchy_information == HIERARCHY_NONE) {
deb_setf("none\n");
- wr(DIB3000MB_REG_VIT_HRCH,DIB3000MB_VIT_HRCH_OFF);
- wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_HP);
+ wr(DIB3000MB_REG_VIT_HRCH, DIB3000MB_VIT_HRCH_OFF);
+ wr(DIB3000MB_REG_VIT_HP, DIB3000MB_VIT_HP);
fe_cr = ofdm->code_rate_HP;
} else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
deb_setf("on\n");
- wr(DIB3000MB_REG_VIT_HRCH,DIB3000MB_VIT_HRCH_ON);
- wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_LP);
+ wr(DIB3000MB_REG_VIT_HRCH, DIB3000MB_VIT_HRCH_ON);
+ wr(DIB3000MB_REG_VIT_HP, DIB3000MB_VIT_LP);
fe_cr = ofdm->code_rate_LP;
}
deb_setf("fec: ");
switch (fe_cr) {
case FEC_1_2:
deb_setf("1_2\n");
- wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_1_2);
+ wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000MB_FEC_1_2);
break;
case FEC_2_3:
deb_setf("2_3\n");
- wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_2_3);
+ wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000MB_FEC_2_3);
break;
case FEC_3_4:
deb_setf("3_4\n");
- wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_3_4);
+ wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000MB_FEC_3_4);
break;
case FEC_5_6:
deb_setf("5_6\n");
- wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_5_6);
+ wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000MB_FEC_5_6);
break;
case FEC_7_8:
deb_setf("7_8\n");
- wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_7_8);
+ wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000MB_FEC_7_8);
break;
case FEC_NONE:
deb_setf("none ");
+ /* fall through */
case FEC_AUTO:
deb_setf("auto\n");
break;
default:
return -EINVAL;
- }
-
+ }
+
seq = dib3000mb_seq
[ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
[ofdm->guard_interval == GUARD_INTERVAL_AUTO]
[fep->inversion == INVERSION_AUTO];
- deb_setf("seq? %d\n",seq);
-
- wr(DIB3000MB_REG_SEQ,seq);
-
- wr(DIB3000MB_REG_ISI,seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
+ deb_setf("seq? %d\n", seq);
+
+ wr(DIB3000MB_REG_SEQ, seq);
+
+ wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) {
if (ofdm->guard_interval == GUARD_INTERVAL_1_8) {
- wr(DIB3000MB_REG_SYNC_IMPROVEMENT,DIB3000MB_SYNC_IMPROVE_2K_1_8);
+ wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8);
} else {
- wr(DIB3000MB_REG_SYNC_IMPROVEMENT,DIB3000MB_SYNC_IMPROVE_DEFAULT);
+ wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT);
}
-
- wr(DIB3000MB_REG_UNK_121,DIB3000MB_UNK_121_2K);
+
+ wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_2K);
} else {
- wr(DIB3000MB_REG_UNK_121,DIB3000MB_UNK_121_DEFAULT);
+ wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_DEFAULT);
}
- wr(DIB3000MB_REG_MOBILE_ALGO,DIB3000MB_MOBILE_ALGO_OFF);
- wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF);
- wr(DIB3000MB_REG_MOBILE_MODE,DIB3000MB_MOBILE_MODE_OFF);
-
- wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_high);
-
- wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_ACTIVATE);
-
- wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AGC+DIB3000MB_RESTART_CTRL);
- wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
-
+ wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_OFF);
+ wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF);
+ wr(DIB3000MB_REG_MOBILE_MODE, DIB3000MB_MOBILE_MODE_OFF);
+
+ wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_high);
+
+ wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_ACTIVATE);
+
+ wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC + DIB3000MB_RESTART_CTRL);
+ wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
+
/* wait for AGC lock */
msleep(70);
- wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_low);
-
- /* something has to be auto searched */
+ wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
+
+ /* something has to be auto searched */
if (ofdm->constellation == QAM_AUTO ||
ofdm->hierarchy_information == HIERARCHY_AUTO ||
- fe_cr == FEC_AUTO ||
+ fe_cr == FEC_AUTO ||
fep->inversion == INVERSION_AUTO) {
-
- deb_setf("autosearch enabled.\n");
-
- wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
-
- wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AUTO_SEARCH);
- wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
-
- while ((search_state = dib3000mb_fe_read_search_status(state)) < 0);
+
+ deb_setf("autosearch enabled.\n");
+
+ wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT);
+
+ wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AUTO_SEARCH);
+ wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
+
+ while ((search_state = dib3000mb_fe_read_search_status(fe)) < 0);
deb_info("search_state after autosearch %d\n",search_state);
- return search_state ? 0 : -EINVAL;
} else {
- wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_CTRL);
- wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
- msleep(70);
+ wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_CTRL);
+ wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF);
}
+
return 0;
}
-static int dib3000mb_fe_init(struct dib3000mb_state *state,int mobile_mode)
+static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
{
- wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_UP);
-
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+
+ wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP);
+
wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC);
-
- wr(DIB3000MB_REG_RESET_DEVICE,DIB3000MB_RESET_DEVICE);
- wr(DIB3000MB_REG_RESET_DEVICE,DIB3000MB_RESET_DEVICE_RST);
-
- wr(DIB3000MB_REG_CLOCK,DIB3000MB_CLOCK_DEFAULT);
-
- wr(DIB3000MB_REG_ELECT_OUT_MODE,DIB3000MB_ELECT_OUT_MODE_ON);
-
- wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_RESERVED);
- wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_AUTO);
-
- wr(DIB3000MB_REG_DDS_FREQ_MSB,DIB3000MB_DDS_FREQ_MSB);
- wr(DIB3000MB_REG_DDS_FREQ_LSB,DIB3000MB_DDS_FREQ_LSB);
-
- wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
+
+ wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE);
+ wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE_RST);
+
+ wr(DIB3000MB_REG_CLOCK, DIB3000MB_CLOCK_DEFAULT);
+
+ wr(DIB3000MB_REG_ELECT_OUT_MODE, DIB3000MB_ELECT_OUT_MODE_ON);
+
+ wr(DIB3000MB_REG_QAM, DIB3000MB_QAM_RESERVED);
+ wr(DIB3000MB_REG_VIT_ALPHA, DIB3000MB_VIT_ALPHA_AUTO);
+
+ wr(DIB3000MB_REG_DDS_FREQ_MSB, DIB3000MB_DDS_FREQ_MSB);
+ wr(DIB3000MB_REG_DDS_FREQ_LSB, DIB3000MB_DDS_FREQ_LSB);
+
+ wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
wr_foreach(dib3000mb_reg_impulse_noise,
dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]);
-
- wr_foreach(dib3000mb_reg_agc_gain,dib3000mb_default_agc_gain);
- wr(DIB3000MB_REG_PHASE_NOISE,DIB3000MB_PHASE_NOISE_DEFAULT);
+ wr_foreach(dib3000mb_reg_agc_gain, dib3000mb_default_agc_gain);
+
+ wr(DIB3000MB_REG_PHASE_NOISE, DIB3000MB_PHASE_NOISE_DEFAULT);
wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase);
-
- wr_foreach(dib3000mb_reg_lock_duration,dib3000mb_default_lock_duration);
-
- wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_low);
-
- wr(DIB3000MB_REG_LOCK0_MASK,DIB3000MB_LOCK0_DEFAULT);
- wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
- wr(DIB3000MB_REG_LOCK2_MASK,DIB3000MB_LOCK2_DEFAULT);
- wr(DIB3000MB_REG_SEQ,dib3000mb_seq[1][1][1]);
-
- wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
-
- wr(DIB3000MB_REG_UNK_68,DIB3000MB_UNK_68);
- wr(DIB3000MB_REG_UNK_69,DIB3000MB_UNK_69);
- wr(DIB3000MB_REG_UNK_71,DIB3000MB_UNK_71);
- wr(DIB3000MB_REG_UNK_77,DIB3000MB_UNK_77);
- wr(DIB3000MB_REG_UNK_78,DIB3000MB_UNK_78);
- wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
- wr(DIB3000MB_REG_UNK_92,DIB3000MB_UNK_92);
- wr(DIB3000MB_REG_UNK_96,DIB3000MB_UNK_96);
- wr(DIB3000MB_REG_UNK_97,DIB3000MB_UNK_97);
- wr(DIB3000MB_REG_UNK_106,DIB3000MB_UNK_106);
- wr(DIB3000MB_REG_UNK_107,DIB3000MB_UNK_107);
- wr(DIB3000MB_REG_UNK_108,DIB3000MB_UNK_108);
- wr(DIB3000MB_REG_UNK_122,DIB3000MB_UNK_122);
- wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF);
- wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_1_2);
- wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_HP);
- wr(DIB3000MB_REG_BERLEN,DIB3000MB_BERLEN_DEFAULT);
-
- wr_foreach(dib3000mb_reg_filter_coeffs,dib3000mb_filter_coeffs);
-
- wr(DIB3000MB_REG_MOBILE_ALGO,DIB3000MB_MOBILE_ALGO_ON);
- wr(DIB3000MB_REG_MULTI_DEMOD_MSB,DIB3000MB_MULTI_DEMOD_MSB);
- wr(DIB3000MB_REG_MULTI_DEMOD_LSB,DIB3000MB_MULTI_DEMOD_LSB);
-
- wr(DIB3000MB_REG_OUTPUT_MODE,DIB3000MB_OUTPUT_MODE_SLAVE);
-
- wr(DIB3000MB_REG_FIFO_142,DIB3000MB_FIFO_142);
- wr(DIB3000MB_REG_MPEG2_OUT_MODE,DIB3000MB_MPEG2_OUT_MODE_188);
- wr(DIB3000MB_REG_FIFO_144,DIB3000MB_FIFO_144);
- wr(DIB3000MB_REG_FIFO,DIB3000MB_FIFO_INHIBIT);
- wr(DIB3000MB_REG_FIFO_146,DIB3000MB_FIFO_146);
- wr(DIB3000MB_REG_FIFO_147,DIB3000MB_FIFO_147);
-
- wr(DIB3000MB_REG_DATA_IN_DIVERSITY,DIB3000MB_DATA_DIVERSITY_IN_OFF);
+
+ wr_foreach(dib3000mb_reg_lock_duration, dib3000mb_default_lock_duration);
+
+ wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
+
+ wr(DIB3000MB_REG_LOCK0_MASK, DIB3000MB_LOCK0_DEFAULT);
+ wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
+ wr(DIB3000MB_REG_LOCK2_MASK, DIB3000MB_LOCK2_DEFAULT);
+ wr(DIB3000MB_REG_SEQ, dib3000mb_seq[1][1][1]);
+
+ wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
+
+ wr(DIB3000MB_REG_UNK_68, DIB3000MB_UNK_68);
+ wr(DIB3000MB_REG_UNK_69, DIB3000MB_UNK_69);
+ wr(DIB3000MB_REG_UNK_71, DIB3000MB_UNK_71);
+ wr(DIB3000MB_REG_UNK_77, DIB3000MB_UNK_77);
+ wr(DIB3000MB_REG_UNK_78, DIB3000MB_UNK_78);
+ wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT);
+ wr(DIB3000MB_REG_UNK_92, DIB3000MB_UNK_92);
+ wr(DIB3000MB_REG_UNK_96, DIB3000MB_UNK_96);
+ wr(DIB3000MB_REG_UNK_97, DIB3000MB_UNK_97);
+ wr(DIB3000MB_REG_UNK_106, DIB3000MB_UNK_106);
+ wr(DIB3000MB_REG_UNK_107, DIB3000MB_UNK_107);
+ wr(DIB3000MB_REG_UNK_108, DIB3000MB_UNK_108);
+ wr(DIB3000MB_REG_UNK_122, DIB3000MB_UNK_122);
+ wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF);
+ wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000MB_FEC_1_2);
+ wr(DIB3000MB_REG_VIT_HP, DIB3000MB_VIT_HP);
+ wr(DIB3000MB_REG_BERLEN, DIB3000MB_BERLEN_DEFAULT);
+
+ wr_foreach(dib3000mb_reg_filter_coeffs, dib3000mb_filter_coeffs);
+
+ wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_ON);
+ wr(DIB3000MB_REG_MULTI_DEMOD_MSB, DIB3000MB_MULTI_DEMOD_MSB);
+ wr(DIB3000MB_REG_MULTI_DEMOD_LSB, DIB3000MB_MULTI_DEMOD_LSB);
+
+ wr(DIB3000MB_REG_OUTPUT_MODE, DIB3000MB_OUTPUT_MODE_SLAVE);
+
+ wr(DIB3000MB_REG_FIFO_142, DIB3000MB_FIFO_142);
+ wr(DIB3000MB_REG_MPEG2_OUT_MODE, DIB3000MB_MPEG2_OUT_MODE_188);
+ wr(DIB3000MB_REG_FIFO_144, DIB3000MB_FIFO_144);
+ wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT);
+ wr(DIB3000MB_REG_FIFO_146, DIB3000MB_FIFO_146);
+ wr(DIB3000MB_REG_FIFO_147, DIB3000MB_FIFO_147);
+
+ wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
+
+ if (state->config->pll_init) {
+ wr(DIB3000MB_REG_TUNER,
+ DIB3000MB_ACTIVATE_TUNER_XFER(state->config->pll_addr << 1));
+ state->config->pll_init(fe);
+ wr(DIB3000MB_REG_TUNER,
+ DIB3000MB_DEACTIVATE_TUNER_XFER(state->config->pll_addr << 1));
+ }
+
return 0;
}
-static int dib3000mb_read_status(struct dib3000mb_state *state,fe_status_t *stat)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int dib3000mb_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
{
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+ struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+ fe_code_rate_t *cr;
+ u16 tps_val;
+ int inv_test1,inv_test2;
+ u32 dds_val, threshold = 0x800000;
+
+ if (!rd(DIB3000MB_REG_TPS_LOCK))
+ return 0;
+
+ dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
+ if (dds_val & threshold)
+ inv_test1 = 0;
+ else if (dds_val == threshold)
+ inv_test1 = 1;
+ else
+ inv_test1 = 2;
+
+ dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
+ if (dds_val & threshold)
+ inv_test2 = 0;
+ else if (dds_val == threshold)
+ inv_test2 = 1;
+ else
+ inv_test2 = 2;
+
+ fep->inversion =
+ ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
+ ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2));
+
+ deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
+
+ switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
+ case DIB3000MB_QAM_QPSK:
+ deb_getf("QPSK ");
+ ofdm->constellation = QPSK;
+ break;
+ case DIB3000MB_QAM_QAM16:
+ deb_getf("QAM16 ");
+ ofdm->constellation = QAM_16;
+ break;
+ case DIB3000MB_QAM_QAM64:
+ deb_getf("QAM64 ");
+ ofdm->constellation = QAM_64;
+ break;
+ default:
+ err("Unexpected constellation returned by TPS (%d)", tps_val);
+ break;
+ }
+ deb_getf("TPS: %d\n", tps_val);
+
+ if (rd(DIB3000MB_REG_TPS_HRCH)) {
+ deb_getf("HRCH ON\n");
+ tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
+ cr = &ofdm->code_rate_LP;
+ ofdm->code_rate_HP = FEC_NONE;
+
+ switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
+ case DIB3000MB_VIT_ALPHA_OFF:
+ deb_getf("HIERARCHY_NONE ");
+ ofdm->hierarchy_information = HIERARCHY_NONE;
+ break;
+ case DIB3000MB_VIT_ALPHA_1:
+ deb_getf("HIERARCHY_1 ");
+ ofdm->hierarchy_information = HIERARCHY_1;
+ break;
+ case DIB3000MB_VIT_ALPHA_2:
+ deb_getf("HIERARCHY_2 ");
+ ofdm->hierarchy_information = HIERARCHY_2;
+ break;
+ case DIB3000MB_VIT_ALPHA_4:
+ deb_getf("HIERARCHY_4 ");
+ ofdm->hierarchy_information = HIERARCHY_4;
+ break;
+ default:
+ err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
+ break;
+ }
+ deb_getf("TPS: %d\n", tps_val);
+ } else {
+ deb_getf("HRCH OFF\n");
+ tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
+ cr = &ofdm->code_rate_HP;
+ ofdm->code_rate_LP = FEC_NONE;
+ ofdm->hierarchy_information = HIERARCHY_NONE;
+ }
+
+ switch (tps_val) {
+ case DIB3000MB_FEC_1_2:
+ deb_getf("FEC_1_2 ");
+ *cr = FEC_1_2;
+ break;
+ case DIB3000MB_FEC_2_3:
+ deb_getf("FEC_2_3 ");
+ *cr = FEC_2_3;
+ break;
+ case DIB3000MB_FEC_3_4:
+ deb_getf("FEC_3_4 ");
+ *cr = FEC_3_4;
+ break;
+ case DIB3000MB_FEC_5_6:
+ deb_getf("FEC_5_6 ");
+ *cr = FEC_4_5;
+ break;
+ case DIB3000MB_FEC_7_8:
+ deb_getf("FEC_7_8 ");
+ *cr = FEC_7_8;
+ break;
+ default:
+ err("Unexpected FEC returned by TPS (%d)", tps_val);
+ break;
+ }
+ deb_getf("TPS: %d\n",tps_val);
+
+ switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
+ case DIB3000MB_GUARD_TIME_1_32:
+ deb_getf("GUARD_INTERVAL_1_32 ");
+ ofdm->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case DIB3000MB_GUARD_TIME_1_16:
+ deb_getf("GUARD_INTERVAL_1_16 ");
+ ofdm->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case DIB3000MB_GUARD_TIME_1_8:
+ deb_getf("GUARD_INTERVAL_1_8 ");
+ ofdm->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case DIB3000MB_GUARD_TIME_1_4:
+ deb_getf("GUARD_INTERVAL_1_4 ");
+ ofdm->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ default:
+ err("Unexpected Guard Time returned by TPS (%d)", tps_val);
+ break;
+ }
+ deb_getf("TPS: %d\n", tps_val);
+
+ switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
+ case DIB3000MB_FFT_2K:
+ deb_getf("TRANSMISSION_MODE_2K ");
+ ofdm->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case DIB3000MB_FFT_8K:
+ deb_getf("TRANSMISSION_MODE_8K ");
+ ofdm->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ default:
+ err("unexpected transmission mode return by TPS (%d)", tps_val);
+ break;
+ }
+ deb_getf("TPS: %d\n", tps_val);
+
+ return 0;
+}
+
+static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+{
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+
*stat = 0;
if (rd(DIB3000MB_REG_AGC_LOCK))
@@ -674,21 +680,21 @@ static int dib3000mb_read_status(struct dib3000mb_state *state,fe_status_t *stat
*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
deb_info("actual status is %2x\n",*stat);
-
+
deb_getf("tps %x %x %x %x %x\n",
rd(DIB3000MB_REG_TPS_1),
rd(DIB3000MB_REG_TPS_2),
rd(DIB3000MB_REG_TPS_3),
rd(DIB3000MB_REG_TPS_4),
rd(DIB3000MB_REG_TPS_5));
-
+
deb_info("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
rd(DIB3000MB_REG_TPS_LOCK),
- rd(DIB3000MB_REG_TPS_QAM),
+ rd(DIB3000MB_REG_TPS_QAM),
rd(DIB3000MB_REG_TPS_HRCH),
rd(DIB3000MB_REG_TPS_VIT_ALPHA),
rd(DIB3000MB_REG_TPS_CODE_RATE_HP),
- rd(DIB3000MB_REG_TPS_CODE_RATE_LP),
+ rd(DIB3000MB_REG_TPS_CODE_RATE_LP),
rd(DIB3000MB_REG_TPS_GUARD_TIME),
rd(DIB3000MB_REG_TPS_FFT),
rd(DIB3000MB_REG_TPS_CELL_ID));
@@ -697,9 +703,11 @@ static int dib3000mb_read_status(struct dib3000mb_state *state,fe_status_t *stat
return 0;
}
-static int dib3000mb_read_ber(struct dib3000mb_state *state,u32 *ber)
+static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
{
- *ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB) );
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+
+ *ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB));
return 0;
}
/*
@@ -712,22 +720,24 @@ static int dib3000mb_read_ber(struct dib3000mb_state *state,u32 *ber)
#define DIB3000MB_AGC_REF_dBm -14
#define DIB3000MB_GAIN_SLOPE_dBm 100
#define DIB3000MB_GAIN_DELTA_dBm -2
-static int dib3000mb_read_signal_strength(struct dib3000mb_state *state, u16 *strength)
+static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
-/* TODO log10
- u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER),
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+
+/* TODO log10
+ u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER),
n_agc_power = rd(DIB3000MB_REG_AGC_POWER),
rf_power = rd(DIB3000MB_REG_RF_POWER);
double rf_power_dBm, ad_power_dBm, minar_power_dBm;
-
+
if (n_agc_power == 0 )
n_agc_power = 1 ;
ad_power_dBm = 10 * log10 ( (float)n_agc_power / (float)(1<<16) );
minor_power_dBm = ad_power_dBm - DIB3000MB_AGC_REF_dBm;
- rf_power_dBm = (-DIB3000MB_GAIN_SLOPE_dBm * (float)rf_power / (float)(1<<16) +
+ rf_power_dBm = (-DIB3000MB_GAIN_SLOPE_dBm * (float)rf_power / (float)(1<<16) +
DIB3000MB_GAIN_DELTA_dBm) + minor_power_dBm;
- // relative rf_power
+ // relative rf_power
*strength = (u16) ((rf_power_dBm + 100) / 100 * 0xffff);
*/
*strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170;
@@ -735,7 +745,7 @@ static int dib3000mb_read_signal_strength(struct dib3000mb_state *state, u16 *st
}
/*
- * Amaury:
+ * Amaury:
* snr is the signal quality measured in dB.
* snr = 10*log10(signal power / noise power)
* the best quality is near 35dB (cable transmission & good modulator)
@@ -746,8 +756,9 @@ static int dib3000mb_read_signal_strength(struct dib3000mb_state *state, u16 *st
* If SNR is above 20dB, BER should be always 0.
* choose 0dB as the minimum
*/
-static int dib3000mb_read_snr(struct dib3000mb_state *state,u16 *snr)
+static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
{
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER);
int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) |
rd(DIB3000MB_REG_NOISE_POWER_LSB);
@@ -758,233 +769,123 @@ static int dib3000mb_read_snr(struct dib3000mb_state *state,u16 *snr)
snr_dBm = 10.0 * log10( (float) (sigpow<<8) / (float)icipow ) ;
else if (sigpow > 0)
snr_dBm = 35;
-
+
*snr = (u16) ((snr_dBm / 35) * 0xffff);
*/
- *snr = (sigpow<<8) / (icipow > 0 ? icipow : 1);
+ *snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1);
return 0;
}
-static int dib3000mb_read_unc_blocks(struct dib3000mb_state *state,u32 *unc)
+static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+
*unc = rd(DIB3000MB_REG_UNC);
return 0;
}
-static int dib3000mb_sleep(struct dib3000mb_state *state)
+static int dib3000mb_sleep(struct dvb_frontend* fe)
{
- wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_DOWN);
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
+
+ wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN);
return 0;
}
-static int dib3000mb_fe_get_tune_settings(struct dib3000mb_state *state,
- struct dvb_frontend_tune_settings *tune)
+static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 800;
tune->step_size = 166667;
- tune->max_drift = 166667*2;
-
+ tune->max_drift = 166667 * 2;
+
return 0;
}
-static int dib3000mb_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe)
{
- struct dib3000mb_state *state = fe->data;
- switch (cmd) {
- case FE_GET_INFO:
- deb_info("FE_GET_INFO\n");
- memcpy(arg, &dib3000mb_info, sizeof(struct dvb_frontend_info));
- return 0;
- break;
-
- case FE_READ_STATUS:
- deb_info("FE_READ_STATUS\n");
- return dib3000mb_read_status(state,(fe_status_t *)arg);
- break;
-
- case FE_READ_BER:
- deb_info("FE_READ_BER\n");
- return dib3000mb_read_ber(state,(u32 *)arg);
- break;
-
- case FE_READ_SIGNAL_STRENGTH:
- deb_info("FE_READ_SIG_STRENGTH\n");
- return dib3000mb_read_signal_strength(state,(u16 *) arg);
- break;
-
- case FE_READ_SNR:
- deb_info("FE_READ_SNR\n");
- return dib3000mb_read_snr(state,(u16 *) arg);
- break;
-
- case FE_READ_UNCORRECTED_BLOCKS:
- deb_info("FE_READ_UNCORRECTED_BLOCKS\n");
- return dib3000mb_read_unc_blocks(state,(u32 *) arg);
- break;
-
- case FE_SET_FRONTEND:
- deb_info("FE_SET_FRONTEND\n");
- return dib3000mb_set_frontend(state,(struct dvb_frontend_parameters *) arg,1);
- break;
-
- case FE_GET_FRONTEND:
- deb_info("FE_GET_FRONTEND\n");
- return dib3000mb_get_frontend(state,(struct dvb_frontend_parameters *) arg);
- break;
-
- case FE_SLEEP:
- deb_info("FE_SLEEP\n");
- return dib3000mb_sleep(state);
- break;
-
- case FE_INIT:
- deb_info("FE_INIT\n");
- return dib3000mb_fe_init(state,0);
- break;
-
- case FE_GET_TUNE_SETTINGS:
- deb_info("GET_TUNE_SETTINGS");
- return dib3000mb_fe_get_tune_settings(state, (struct
- dvb_frontend_tune_settings *) arg);
-
- break;
- case FE_SET_TONE:
- case FE_SET_VOLTAGE:
- default:
- return -EOPNOTSUPP;
- break;
- }
- return 0;
-}
-
-static struct i2c_client client_template;
+ return dib3000mb_fe_init(fe, 0);
+}
-static int dib3000mb_attach_adapter(struct i2c_adapter *adapter)
+static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
{
- struct i2c_client *client;
- struct dib3000mb_state *state;
- int ret = -ENOMEM;
-
- deb_info("i2c probe with adapter '%s'.\n",adapter->name);
-
- if ((state = kmalloc(sizeof(struct dib3000mb_state),GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
-
- if ((client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL)
- goto i2c_kmalloc_err;
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
-
- client->adapter = adapter;
- client->addr = 0x10;
- state->i2c = client;
-
- i2c_set_clientdata(client,state);
-
- state->manufactor_id = dib3000mb_read_reg(client, DIB3000MB_REG_MANUFACTOR_ID);
- if (state->manufactor_id != 0x01b3) {
- ret = -ENODEV;
- goto probe_err;
- }
-
- state->device_id = dib3000mb_read_reg(client,DIB3000MB_REG_DEVICE_ID);
- if (state->device_id != 0x3000) {
- ret = -ENODEV;
- goto probe_err;
- }
-
- info("found a DiBCom (0x%04x) 3000-MB DVB-T frontend (ver: %x).",
- state->manufactor_id, state->device_id);
-
- if ((ret = i2c_attach_client(client)))
- goto i2c_attach_err;
-
- if (state->dvb == NULL)
- goto i2c_attach_err;
-
- if ((ret = dvb_register_frontend(dib3000mb_ioctl, state->dvb, state,
- &dib3000mb_info, THIS_MODULE)))
- goto dvb_fe_err;
-
- goto success;
-dvb_fe_err:
- i2c_detach_client(client);
-i2c_attach_err:
-probe_err:
- kfree(client);
-i2c_kmalloc_err:
- kfree(state);
- return ret;
-success:
- return 0;
+ return dib3000mb_set_frontend(fe, fep, 1);
}
-
-static int dib3000mb_detach_client(struct i2c_client *client)
+static void dib3000mb_release(struct dvb_frontend* fe)
{
- struct dib3000mb_state *state = i2c_get_clientdata(client);
-
- deb_info("i2c detach\n");
-
- dvb_unregister_frontend(dib3000mb_ioctl, state->dvb);
- i2c_detach_client(client);
- kfree(client);
+ struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
kfree(state);
-
- return 0;
}
-static int dib3000mb_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static struct dvb_frontend_ops dib3000mb_ops;
+
+struct dvb_frontend* dib3000mb_attach(const struct dib3000mb_config* config,
+ struct i2c_adapter* i2c)
{
- struct dib3000mb_state *state = i2c_get_clientdata(client);
- deb_info("i2c command.\n");
- switch(cmd) {
- case FE_REGISTER:
- state->dvb = arg;
- break;
- case FE_UNREGISTER:
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
+ struct dib3000mb_state* state = NULL;
+ u16 manfid, devid;
- return 0;
-}
+ /* allocate memory for the internal state */
+ state = (struct dib3000mb_state*) kmalloc(sizeof(struct dib3000mb_state), GFP_KERNEL);
+ if (state == NULL) goto error;
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = "dib3000mb",
- .id = I2C_DRIVERID_DVBFE_DIB3000MB,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = dib3000mb_attach_adapter,
- .detach_client = dib3000mb_detach_client,
- .command = dib3000mb_command,
-};
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
-static struct i2c_client client_template = {
- .name = "dib3000mb",
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+ /* check if the demod is there */
+ manfid = dib3000mb_read_reg(state, DIB3000MB_REG_MANUFACTOR_ID);
+ if (manfid != 0x01b3) goto error;
-/* module stuff */
-static int __init dib3000mb_init(void)
-{
- deb_info("debugging level: %d\n",debug);
- return i2c_add_driver(&driver);
-}
+ devid = dib3000mb_read_reg(state, DIB3000MB_REG_DEVICE_ID);
+ if (devid != 0x3000) goto error;
-static void __exit dib3000mb_exit(void)
-{
- i2c_del_driver(&driver);
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init (dib3000mb_init);
-module_exit (dib3000mb_exit);
+static struct dvb_frontend_ops dib3000mb_ops = {
+
+ .info = {
+ .name = "DiBcom 3000-MB DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = dib3000mb_release,
+
+ .init = dib3000mb_fe_init_nonmobile,
+ .sleep = dib3000mb_sleep,
+
+ .set_frontend = dib3000mb_set_frontend_and_tuner,
+ .get_frontend = dib3000mb_get_frontend,
+ .get_tune_settings = dib3000mb_fe_get_tune_settings,
+
+ .read_status = dib3000mb_read_status,
+ .read_ber = dib3000mb_read_ber,
+ .read_signal_strength = dib3000mb_read_signal_strength,
+ .read_snr = dib3000mb_read_snr,
+ .read_ucblocks = dib3000mb_read_unc_blocks,
+};
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dib3000mb_attach);
diff --git a/linux/drivers/media/dvb/frontends/dib3000mb.h b/linux/drivers/media/dvb/frontends/dib3000mb.h
index ef07984d7..7f72451fc 100644
--- a/linux/drivers/media/dvb/frontends/dib3000mb.h
+++ b/linux/drivers/media/dvb/frontends/dib3000mb.h
@@ -1,655 +1,48 @@
/*
- * dib3000mb.h
- *
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB
+ * DiBcom (http://www.dibcom.fr/)
+ *
* Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
- *
+ *
+ * based on GPL code from DibCom, which has
+ *
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
* 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, version 2.
*
- * for more information see dib3000mb.c .
- */
-
-#ifndef __DIB3000MB_H_INCLUDED__
-#define __DIB3000MB_H_INCLUDED__
-
-/* info and err, taken from usb.h, if there is anything available like by default,
- * please change !
- */
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
-
-/* register addresses and some of their default values */
-
-/* restart subsystems */
-#define DIB3000MB_REG_RESTART ( 0)
-
-#define DIB3000MB_RESTART_OFF ( 0)
-#define DIB3000MB_RESTART_AUTO_SEARCH (1 << 1)
-#define DIB3000MB_RESTART_CTRL (1 << 2)
-#define DIB3000MB_RESTART_AGC (1 << 3)
-
-/* FFT size */
-#define DIB3000MB_REG_FFT ( 1)
-#define DIB3000MB_FFT_2K ( 0)
-#define DIB3000MB_FFT_8K ( 1)
-#define DIB3000MB_FFT_AUTO ( 1)
-
-/* Guard time */
-#define DIB3000MB_REG_GUARD_TIME ( 2)
-#define DIB3000MB_GUARD_TIME_1_32 ( 0)
-#define DIB3000MB_GUARD_TIME_1_16 ( 1)
-#define DIB3000MB_GUARD_TIME_1_8 ( 2)
-#define DIB3000MB_GUARD_TIME_1_4 ( 3)
-#define DIB3000MB_GUARD_TIME_AUTO ( 0)
-
-/* QAM */
-#define DIB3000MB_REG_QAM ( 3)
-#define DIB3000MB_QAM_QPSK ( 0)
-#define DIB3000MB_QAM_QAM16 ( 1)
-#define DIB3000MB_QAM_QAM64 ( 2)
-#define DIB3000MB_QAM_RESERVED ( 3)
-
-/* Alpha coefficient high priority Viterbi algorithm */
-#define DIB3000MB_REG_VIT_ALPHA ( 4)
-#define DIB3000MB_VIT_ALPHA_OFF ( 0)
-#define DIB3000MB_VIT_ALPHA_1 ( 1)
-#define DIB3000MB_VIT_ALPHA_2 ( 2)
-#define DIB3000MB_VIT_ALPHA_4 ( 4)
-#define DIB3000MB_VIT_ALPHA_AUTO ( 7)
-
-/* spectrum inversion */
-#define DIB3000MB_REG_DDS_INV ( 5)
-#define DIB3000MB_DDS_INV_OFF ( 0)
-#define DIB3000MB_DDS_INV_ON ( 1)
-
-/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */
-#define DIB3000MB_REG_DDS_FREQ_MSB ( 6)
-#define DIB3000MB_REG_DDS_FREQ_LSB ( 7)
-#define DIB3000MB_DDS_FREQ_MSB ( 178)
-#define DIB3000MB_DDS_FREQ_LSB ( 8990)
-
-/* timing frequency (carrier spacing) */
-#define DIB3000MB_REG_TIMING_FREQ_MSB ( 8)
-#define DIB3000MB_REG_TIMING_FREQ_LSB ( 9)
-
-static u16 dib3000mb_reg_timing_freq[] = {
- DIB3000MB_REG_TIMING_FREQ_MSB, DIB3000MB_REG_TIMING_FREQ_LSB
-};
-static u16 dib3000mb_timing_freq[][2] = {
- { 126 , 48873 }, /* 6 MHz */
- { 147 , 57019 }, /* 7 MHz */
- { 168 , 65164 }, /* 8 MHz */
-};
-
-/* impulse noise parameter */
-#define DIB3000MB_REG_IMPNOISE_10 ( 10)
-#define DIB3000MB_REG_IMPNOISE_11 ( 11)
-#define DIB3000MB_REG_IMPNOISE_12 ( 12)
-#define DIB3000MB_REG_IMPNOISE_13 ( 13)
-#define DIB3000MB_REG_IMPNOISE_14 ( 14)
-#define DIB3000MB_REG_IMPNOISE_15 ( 15)
-/* 36 ??? */
-#define DIB3000MB_REG_IMPNOISE_36 ( 36)
-
-enum dib3000mb_impulse_noise_type {
- DIB3000MB_IMPNOISE_OFF,
- DIB3000MB_IMPNOISE_MOBILE,
- DIB3000MB_IMPNOISE_FIXED,
- DIB3000MB_IMPNOISE_DEFAULT
-};
-
-static u16 dib3000mb_reg_impulse_noise[] = {
- DIB3000MB_REG_IMPNOISE_10, DIB3000MB_REG_IMPNOISE_11,
- DIB3000MB_REG_IMPNOISE_12, DIB3000MB_REG_IMPNOISE_15,
- DIB3000MB_REG_IMPNOISE_36
-};
-
-static u16 dib3000mb_impulse_noise_values[][5] = {
- { 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */
- { 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */
- { 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */
- { 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */
-};
-
-/*
- * Dual Automatic-Gain-Control
- * - gains RF in tuner (AGC1)
- * - gains IF after filtering (AGC2)
- */
-
-/* also from 16 to 18 */
-#define DIB3000MB_REG_AGC_GAIN_19 ( 19)
-#define DIB3000MB_REG_AGC_GAIN_20 ( 20)
-#define DIB3000MB_REG_AGC_GAIN_21 ( 21)
-#define DIB3000MB_REG_AGC_GAIN_22 ( 22)
-#define DIB3000MB_REG_AGC_GAIN_23 ( 23)
-#define DIB3000MB_REG_AGC_GAIN_24 ( 24)
-#define DIB3000MB_REG_AGC_GAIN_25 ( 25)
-#define DIB3000MB_REG_AGC_GAIN_26 ( 26)
-#define DIB3000MB_REG_AGC_GAIN_27 ( 27)
-#define DIB3000MB_REG_AGC_GAIN_28 ( 28)
-#define DIB3000MB_REG_AGC_GAIN_29 ( 29)
-#define DIB3000MB_REG_AGC_GAIN_30 ( 30)
-#define DIB3000MB_REG_AGC_GAIN_31 ( 31)
-#define DIB3000MB_REG_AGC_GAIN_32 ( 32)
-
-static u16 dib3000mb_reg_agc_gain[] = {
- DIB3000MB_REG_AGC_GAIN_19, DIB3000MB_REG_AGC_GAIN_20, DIB3000MB_REG_AGC_GAIN_21,
- DIB3000MB_REG_AGC_GAIN_22, DIB3000MB_REG_AGC_GAIN_23, DIB3000MB_REG_AGC_GAIN_24,
- DIB3000MB_REG_AGC_GAIN_25, DIB3000MB_REG_AGC_GAIN_26, DIB3000MB_REG_AGC_GAIN_27,
- DIB3000MB_REG_AGC_GAIN_28, DIB3000MB_REG_AGC_GAIN_29, DIB3000MB_REG_AGC_GAIN_30,
- DIB3000MB_REG_AGC_GAIN_31, DIB3000MB_REG_AGC_GAIN_32 };
-
-static u16 dib3000mb_default_agc_gain[] =
- { 0x0001, 52429, 623, 128, 166, 195, 61, /* RF ??? */
- 0x0001, 53766, 38011, 0, 90, 33, 23 }; /* IF ??? */
-
-/* phase noise */
-#define DIB3000MB_REG_PHASE_NOISE_33 ( 33)
-#define DIB3000MB_REG_PHASE_NOISE_34 ( 34)
-#define DIB3000MB_REG_PHASE_NOISE_35 ( 35)
-#define DIB3000MB_REG_PHASE_NOISE_36 ( 36)
-#define DIB3000MB_REG_PHASE_NOISE_37 ( 37)
-#define DIB3000MB_REG_PHASE_NOISE_38 ( 38)
-
-/* DIB3000MB_REG_PHASE_NOISE_36 is set when setting the impulse noise */
-static u16 dib3000mb_reg_phase_noise[] = {
- DIB3000MB_REG_PHASE_NOISE_33, DIB3000MB_REG_PHASE_NOISE_34, DIB3000MB_REG_PHASE_NOISE_35,
- DIB3000MB_REG_PHASE_NOISE_37, DIB3000MB_REG_PHASE_NOISE_38
-};
-
-static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 };
-
-/* lock duration */
-#define DIB3000MB_REG_LOCK_DURATION_39 ( 39)
-#define DIB3000MB_REG_LOCK_DURATION_40 ( 40)
-
-static u16 dib3000mb_reg_lock_duration[] = {
- DIB3000MB_REG_LOCK_DURATION_39, DIB3000MB_REG_LOCK_DURATION_40
-};
-
-static u16 dib3000mb_default_lock_duration[] = { 135, 135 };
-
-/* AGC loop bandwidth */
-
-#define DIB3000MB_REG_AGC_BW_43 ( 43)
-#define DIB3000MB_REG_AGC_BW_44 ( 44)
-#define DIB3000MB_REG_AGC_BW_45 ( 45)
-#define DIB3000MB_REG_AGC_BW_46 ( 46)
-#define DIB3000MB_REG_AGC_BW_47 ( 47)
-#define DIB3000MB_REG_AGC_BW_48 ( 48)
-#define DIB3000MB_REG_AGC_BW_49 ( 49)
-#define DIB3000MB_REG_AGC_BW_50 ( 50)
-
-static u16 dib3000mb_reg_agc_bandwidth[] = {
- DIB3000MB_REG_AGC_BW_43, DIB3000MB_REG_AGC_BW_44, DIB3000MB_REG_AGC_BW_45,
- DIB3000MB_REG_AGC_BW_46, DIB3000MB_REG_AGC_BW_47, DIB3000MB_REG_AGC_BW_48,
- DIB3000MB_REG_AGC_BW_49, DIB3000MB_REG_AGC_BW_50
-};
-
-static u16 dib3000mb_agc_bandwidth_low[] =
- { 2088, 10, 2088, 10, 3448, 5, 3448, 5 };
-static u16 dib3000mb_agc_bandwidth_high[] =
- { 2349, 5, 2349, 5, 2586, 2, 2586, 2 };
-
-/*
- * lock0 definition (coff_lock)
- */
-#define DIB3000MB_REG_LOCK0_MASK ( 51)
-#define DIB3000MB_LOCK0_DEFAULT ( 4)
-
-/*
- * lock1 definition (cpil_lock)
- * for auto search
- * which values hide behind the lock masks
- */
-#define DIB3000MB_REG_LOCK1_MASK ( 52)
-#define DIB3000MB_LOCK1_SEARCH_4 (0x0004)
-#define DIB3000MB_LOCK1_SEARCH_2048 (0x0800)
-#define DIB3000MB_LOCK1_DEFAULT (0x0001)
-
-/*
- * lock2 definition (fec_lock) */
-#define DIB3000MB_REG_LOCK2_MASK ( 53)
-#define DIB3000MB_LOCK2_DEFAULT (0x0080)
-
-/*
- * SEQ ? what was that again ... :)
- * changes when, inversion, guard time and fft is
- * either automatically detected or not
- */
-#define DIB3000MB_REG_SEQ ( 54)
-
-/* all values have been set manually */
-static u16 dib3000mb_seq[2][2][2] = /* fft,gua, inv */
- { /* fft */
- { /* gua */
- { 0, 1 }, /* 0 0 { 0,1 } */
- { 3, 9 }, /* 0 1 { 0,1 } */
- },
- {
- { 2, 5 }, /* 1 0 { 0,1 } */
- { 6, 11 }, /* 1 1 { 0,1 } */
- }
- };
-
-/* bandwidth */
-#define DIB3000MB_REG_BW_55 ( 55)
-#define DIB3000MB_REG_BW_56 ( 56)
-#define DIB3000MB_REG_BW_57 ( 57)
-#define DIB3000MB_REG_BW_58 ( 58)
-#define DIB3000MB_REG_BW_59 ( 59)
-#define DIB3000MB_REG_BW_60 ( 60)
-#define DIB3000MB_REG_BW_61 ( 61)
-#define DIB3000MB_REG_BW_62 ( 62)
-#define DIB3000MB_REG_BW_63 ( 63)
-#define DIB3000MB_REG_BW_64 ( 64)
-#define DIB3000MB_REG_BW_65 ( 65)
-#define DIB3000MB_REG_BW_66 ( 66)
-#define DIB3000MB_REG_BW_67 ( 67)
-
-static u16 dib3000mb_reg_bandwidth[] = {
- DIB3000MB_REG_BW_55, DIB3000MB_REG_BW_56, DIB3000MB_REG_BW_57,
- DIB3000MB_REG_BW_58, DIB3000MB_REG_BW_59, DIB3000MB_REG_BW_60,
- DIB3000MB_REG_BW_61, DIB3000MB_REG_BW_62, DIB3000MB_REG_BW_63,
- DIB3000MB_REG_BW_64, DIB3000MB_REG_BW_65, DIB3000MB_REG_BW_66,
- DIB3000MB_REG_BW_67
-};
-
-static u16 dib3000mb_bandwidth_6mhz[] =
- { 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 };
-
-static u16 dib3000mb_bandwidth_7mhz[] =
- { 0, 28, 64421, 96, 39973, 483, 3255, 0, 1000, 0, 1010, 1, 45264 };
-
-static u16 dib3000mb_bandwidth_8mhz[] =
- { 0, 25, 23600, 84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 };
-
-#define DIB3000MB_REG_UNK_68 ( 68)
-#define DIB3000MB_UNK_68 ( 0)
-
-#define DIB3000MB_REG_UNK_69 ( 69)
-#define DIB3000MB_UNK_69 ( 0)
-
-#define DIB3000MB_REG_UNK_71 ( 71)
-#define DIB3000MB_UNK_71 ( 0)
-
-#define DIB3000MB_REG_UNK_77 ( 77)
-#define DIB3000MB_UNK_77 ( 6)
-
-#define DIB3000MB_REG_UNK_78 ( 78)
-#define DIB3000MB_UNK_78 (0x0080)
-
-/* isi */
-#define DIB3000MB_REG_ISI ( 79)
-#define DIB3000MB_ISI_ACTIVATE ( 0)
-#define DIB3000MB_ISI_INHIBIT ( 1)
-
-/* sync impovement */
-#define DIB3000MB_REG_SYNC_IMPROVEMENT ( 84)
-#define DIB3000MB_SYNC_IMPROVE_2K_1_8 ( 3)
-#define DIB3000MB_SYNC_IMPROVE_DEFAULT ( 0)
-
-/* phase noise compensation inhibition */
-#define DIB3000MB_REG_PHASE_NOISE ( 87)
-#define DIB3000MB_PHASE_NOISE_DEFAULT ( 0)
-
-#define DIB3000MB_REG_UNK_92 ( 92)
-#define DIB3000MB_UNK_92 (0x0080)
-
-#define DIB3000MB_REG_UNK_96 ( 96)
-#define DIB3000MB_UNK_96 (0x0010)
-
-#define DIB3000MB_REG_UNK_97 ( 97)
-#define DIB3000MB_UNK_97 (0x0009)
-
-/* mobile mode ??? */
-#define DIB3000MB_REG_MOBILE_MODE ( 101)
-#define DIB3000MB_MOBILE_MODE_ON ( 1)
-#define DIB3000MB_MOBILE_MODE_OFF ( 0)
-
-#define DIB3000MB_REG_UNK_106 ( 106)
-#define DIB3000MB_UNK_106 (0x0080)
-
-#define DIB3000MB_REG_UNK_107 ( 107)
-#define DIB3000MB_UNK_107 (0x0080)
-
-#define DIB3000MB_REG_UNK_108 ( 108)
-#define DIB3000MB_UNK_108 (0x0080)
-
-/* fft */
-#define DIB3000MB_REG_UNK_121 ( 121)
-#define DIB3000MB_UNK_121_2K ( 7)
-#define DIB3000MB_UNK_121_DEFAULT ( 5)
-
-#define DIB3000MB_REG_UNK_122 ( 122)
-#define DIB3000MB_UNK_122 ( 2867)
-
-/* QAM for mobile mode */
-#define DIB3000MB_REG_MOBILE_MODE_QAM ( 126)
-#define DIB3000MB_MOBILE_MODE_QAM_64 ( 3)
-#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16 ( 1)
-#define DIB3000MB_MOBILE_MODE_QAM_OFF ( 0)
-
-/*
- * data diversity when having more than one chip on-board
- * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY
- */
-#define DIB3000MB_REG_DATA_IN_DIVERSITY ( 127)
-#define DIB3000MB_DATA_DIVERSITY_IN_OFF ( 0)
-#define DIB3000MB_DATA_DIVERSITY_IN_ON ( 2)
-
-/* vit hrch */
-#define DIB3000MB_REG_VIT_HRCH ( 128)
-#define DIB3000MB_VIT_HRCH_ON ( 1)
-#define DIB3000MB_VIT_HRCH_OFF ( 0)
-
-/* vit code rate */
-#define DIB3000MB_REG_VIT_CODE_RATE ( 129)
-
-/* forward error correction code rates */
-#define DIB3000MB_FEC_1_2 ( 1)
-#define DIB3000MB_FEC_2_3 ( 2)
-#define DIB3000MB_FEC_3_4 ( 3)
-#define DIB3000MB_FEC_5_6 ( 5)
-#define DIB3000MB_FEC_7_8 ( 7)
-
-/* vit select hp */
-#define DIB3000MB_REG_VIT_HP ( 130)
-#define DIB3000MB_VIT_LP ( 0)
-#define DIB3000MB_VIT_HP ( 1)
-
-/* time frame for Bit-Error-Rate calculation */
-#define DIB3000MB_REG_BERLEN ( 135)
-#define DIB3000MB_BERLEN_LONG ( 0)
-#define DIB3000MB_BERLEN_DEFAULT ( 1)
-#define DIB3000MB_BERLEN_MEDIUM ( 2)
-#define DIB3000MB_BERLEN_SHORT ( 3)
-
-/* 142 - 152 FIFO parameters
- * which is what ?
- */
-
-#define DIB3000MB_REG_FIFO_142 ( 142)
-#define DIB3000MB_FIFO_142 ( 0)
-
-/* MPEG2 TS output mode */
-#define DIB3000MB_REG_MPEG2_OUT_MODE ( 143)
-#define DIB3000MB_MPEG2_OUT_MODE_204 ( 0)
-#define DIB3000MB_MPEG2_OUT_MODE_188 ( 1)
-
-#define DIB3000MB_REG_FIFO_144 ( 144)
-#define DIB3000MB_FIFO_144 ( 1)
-
-#define DIB3000MB_REG_FIFO ( 145)
-#define DIB3000MB_FIFO_INHIBIT ( 1)
-#define DIB3000MB_FIFO_ACTIVATE ( 0)
-
-#define DIB3000MB_REG_FIFO_146 ( 146)
-#define DIB3000MB_FIFO_146 ( 3)
-
-#define DIB3000MB_REG_FIFO_147 ( 147)
-#define DIB3000MB_FIFO_147 (0x0100)
-
-/*
- * pidfilter
- * it is not a hardware pidfilter but a filter which drops all pids
- * except the ones set. Necessary because of the limited USB1.1 bandwidth.
+ * Acknowledgements
+ *
+ * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ * sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * $Id $Id: dib3000mb.h,v 1.9 2004/10/28 17:37:07 quincy Exp $$
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ *
*/
-#define DIB3000MB_REG_FILTER_PID_0 ( 153)
-#define DIB3000MB_REG_FILTER_PID_1 ( 154)
-#define DIB3000MB_REG_FILTER_PID_2 ( 155)
-#define DIB3000MB_REG_FILTER_PID_3 ( 156)
-#define DIB3000MB_REG_FILTER_PID_4 ( 157)
-#define DIB3000MB_REG_FILTER_PID_5 ( 158)
-#define DIB3000MB_REG_FILTER_PID_6 ( 159)
-#define DIB3000MB_REG_FILTER_PID_7 ( 160)
-#define DIB3000MB_REG_FILTER_PID_8 ( 161)
-#define DIB3000MB_REG_FILTER_PID_9 ( 162)
-#define DIB3000MB_REG_FILTER_PID_10 ( 163)
-#define DIB3000MB_REG_FILTER_PID_11 ( 164)
-#define DIB3000MB_REG_FILTER_PID_12 ( 165)
-#define DIB3000MB_REG_FILTER_PID_13 ( 166)
-#define DIB3000MB_REG_FILTER_PID_14 ( 167)
-#define DIB3000MB_REG_FILTER_PID_15 ( 168)
-
-#define DIB3000MB_ACTIVATE_FILTERING (0x2000)
-/*
- * output mode
- * USB devices have to use 'slave'-mode
- * see also DIB3000MB_REG_ELECT_OUT_MODE
- */
-#define DIB3000MB_REG_OUTPUT_MODE ( 169)
-#define DIB3000MB_OUTPUT_MODE_GATED_CLK ( 0)
-#define DIB3000MB_OUTPUT_MODE_CONT_CLK ( 1)
-#define DIB3000MB_OUTPUT_MODE_SERIAL ( 2)
-#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY ( 5)
-#define DIB3000MB_OUTPUT_MODE_SLAVE ( 6)
+#ifndef DIB3000MB_H
+#define DIB3000MB_H
-/* irq event mask */
-#define DIB3000MB_REG_IRQ_EVENT_MASK ( 170)
-#define DIB3000MB_IRQ_EVENT_MASK ( 0)
+#include <linux/dvb/frontend.h>
-/* filter coefficients */
-#define DIB3000MB_REG_FILTER_COEF_171 ( 171)
-#define DIB3000MB_REG_FILTER_COEF_172 ( 172)
-#define DIB3000MB_REG_FILTER_COEF_173 ( 173)
-#define DIB3000MB_REG_FILTER_COEF_174 ( 174)
-#define DIB3000MB_REG_FILTER_COEF_175 ( 175)
-#define DIB3000MB_REG_FILTER_COEF_176 ( 176)
-#define DIB3000MB_REG_FILTER_COEF_177 ( 177)
-#define DIB3000MB_REG_FILTER_COEF_178 ( 178)
-#define DIB3000MB_REG_FILTER_COEF_179 ( 179)
-#define DIB3000MB_REG_FILTER_COEF_180 ( 180)
-#define DIB3000MB_REG_FILTER_COEF_181 ( 181)
-#define DIB3000MB_REG_FILTER_COEF_182 ( 182)
-#define DIB3000MB_REG_FILTER_COEF_183 ( 183)
-#define DIB3000MB_REG_FILTER_COEF_184 ( 184)
-#define DIB3000MB_REG_FILTER_COEF_185 ( 185)
-#define DIB3000MB_REG_FILTER_COEF_186 ( 186)
-#define DIB3000MB_REG_FILTER_COEF_187 ( 187)
-#define DIB3000MB_REG_FILTER_COEF_188 ( 188)
-#define DIB3000MB_REG_FILTER_COEF_189 ( 189)
-#define DIB3000MB_REG_FILTER_COEF_190 ( 190)
-#define DIB3000MB_REG_FILTER_COEF_191 ( 191)
-#define DIB3000MB_REG_FILTER_COEF_192 ( 192)
-#define DIB3000MB_REG_FILTER_COEF_193 ( 193)
-#define DIB3000MB_REG_FILTER_COEF_194 ( 194)
+struct dib3000mb_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
-static u16 dib3000mb_reg_filter_coeffs[] = {
- DIB3000MB_REG_FILTER_COEF_171, DIB3000MB_REG_FILTER_COEF_172, DIB3000MB_REG_FILTER_COEF_173,
- DIB3000MB_REG_FILTER_COEF_174, DIB3000MB_REG_FILTER_COEF_175, DIB3000MB_REG_FILTER_COEF_176,
- DIB3000MB_REG_FILTER_COEF_177, DIB3000MB_REG_FILTER_COEF_178, DIB3000MB_REG_FILTER_COEF_179,
- DIB3000MB_REG_FILTER_COEF_180, DIB3000MB_REG_FILTER_COEF_181, DIB3000MB_REG_FILTER_COEF_182,
- DIB3000MB_REG_FILTER_COEF_183, DIB3000MB_REG_FILTER_COEF_184, DIB3000MB_REG_FILTER_COEF_185,
- DIB3000MB_REG_FILTER_COEF_186, DIB3000MB_REG_FILTER_COEF_188,
- DIB3000MB_REG_FILTER_COEF_189, DIB3000MB_REG_FILTER_COEF_190, DIB3000MB_REG_FILTER_COEF_191,
- DIB3000MB_REG_FILTER_COEF_192, DIB3000MB_REG_FILTER_COEF_194
-};
+ /* The i2c address of the PLL */
+ u8 pll_addr;
-static u16 dib3000mb_filter_coeffs[] = {
- 226, 160, 29,
- 979, 998, 19,
- 22, 1019, 1006,
- 1022, 12, 6,
- 1017, 1017, 3,
- 6, 1019,
- 1021, 2, 3,
- 1, 0,
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
-/*
- * mobile algorithm (when you are moving with your device)
- * but not faster than 90 km/h
- */
-#define DIB3000MB_REG_MOBILE_ALGO ( 195)
-#define DIB3000MB_MOBILE_ALGO_ON ( 0)
-#define DIB3000MB_MOBILE_ALGO_OFF ( 1)
-
-/* multiple demodulators algorithm */
-#define DIB3000MB_REG_MULTI_DEMOD_MSB ( 206)
-#define DIB3000MB_REG_MULTI_DEMOD_LSB ( 207)
-
-/* terminator, no more demods */
-#define DIB3000MB_MULTI_DEMOD_MSB ( 32767)
-#define DIB3000MB_MULTI_DEMOD_LSB ( 4095)
-
-/* bring the device into a known */
-#define DIB3000MB_REG_RESET_DEVICE ( 1024)
-#define DIB3000MB_RESET_DEVICE (0x812c)
-#define DIB3000MB_RESET_DEVICE_RST ( 0)
-
-/* identification registers, manufactor an the device */
-#define DIB3000MB_REG_MANUFACTOR_ID ( 1025)
-#define DIB3000MB_MANUFACTOR_ID_DIBCOM (0x01B3)
-
-#define DIB3000MB_REG_DEVICE_ID ( 1026)
-#define DIB3000MB_DEVICE_ID (0x3000)
-
-/* hardware clock configuration */
-#define DIB3000MB_REG_CLOCK ( 1027)
-#define DIB3000MB_CLOCK_DEFAULT (0x9000)
-#define DIB3000MB_CLOCK_DIVERSITY (0x92b0)
-
-/* power down config */
-#define DIB3000MB_REG_POWER_CONTROL ( 1028)
-#define DIB3000MB_POWER_DOWN ( 1)
-#define DIB3000MB_POWER_UP ( 0)
-
-/* electrical output mode */
-#define DIB3000MB_REG_ELECT_OUT_MODE ( 1029)
-#define DIB3000MB_ELECT_OUT_MODE_OFF ( 0)
-#define DIB3000MB_ELECT_OUT_MODE_ON ( 1)
-
-/* set the tuner i2c address */
-#define DIB3000MB_REG_TUNER ( 1089)
-#define DIB3000MB_TUNER_ADDR_DEFAULT ( 194)
-#define DIB3000MB_ACTIVATE_TUNER_XFER(a) (0xffff & (a << 7))
-#define DIB3000MB_DEACTIVATE_TUNER_XFER(a) (0xffff & ((a << 7) + 0x80))
-
-/* monitoring registers (read only) */
-
-/* agc loop locked (size: 1) */
-#define DIB3000MB_REG_AGC_LOCK ( 324)
-
-/* agc power (size: 16) */
-#define DIB3000MB_REG_AGC_POWER ( 325)
-
-/* agc1 value (16) */
-#define DIB3000MB_REG_AGC1_VALUE ( 326)
-
-/* agc2 value (16) */
-#define DIB3000MB_REG_AGC2_VALUE ( 327)
-
-/* total RF power (16), can be used for signal strength */
-#define DIB3000MB_REG_RF_POWER ( 328)
-
-/* dds_frequency with offset (24) */
-#define DIB3000MB_REG_DDS_VALUE_MSB ( 339)
-#define DIB3000MB_REG_DDS_VALUE_LSB ( 340)
-
-/* timing offset signed (24) */
-#define DIB3000MB_REG_TIMING_OFFSET_MSB ( 341)
-#define DIB3000MB_REG_TIMING_OFFSET_LSB ( 342)
-
-/* fft start position (13) */
-#define DIB3000MB_REG_FFT_WINDOW_POS ( 353)
-
-/* carriers locked (1) */
-#define DIB3000MB_REG_CARRIER_LOCK ( 355)
-
-/* noise power (24) */
-#define DIB3000MB_REG_NOISE_POWER_MSB ( 372)
-#define DIB3000MB_REG_NOISE_POWER_LSB ( 373)
-
-#define DIB3000MB_REG_MOBILE_NOISE_MSB ( 374)
-#define DIB3000MB_REG_MOBILE_NOISE_LSB ( 375)
-
-/*
- * signal power (16), this and the above can be
- * used to calculate the signal/noise - ratio
- */
-#define DIB3000MB_REG_SIGNAL_POWER ( 380)
-
-/* mer (24) */
-#define DIB3000MB_REG_MER_MSB ( 381)
-#define DIB3000MB_REG_MER_LSB ( 382)
-
-/*
- * Transmission Parameter Signalling (TPS)
- * the following registers can be used to get TPS-information.
- * The values are according to the DVB-T standard.
- */
-
-/* TPS locked (1) */
-#define DIB3000MB_REG_TPS_LOCK ( 394)
-
-/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */
-#define DIB3000MB_REG_TPS_QAM ( 398)
-
-/* hierarchy from TPS (1) */
-#define DIB3000MB_REG_TPS_HRCH ( 399)
-
-/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */
-#define DIB3000MB_REG_TPS_VIT_ALPHA ( 400)
-
-/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */
-#define DIB3000MB_REG_TPS_CODE_RATE_HP ( 401)
-
-/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */
-#define DIB3000MB_REG_TPS_CODE_RATE_LP ( 402)
-
-/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */
-#define DIB3000MB_REG_TPS_GUARD_TIME ( 403)
-
-/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */
-#define DIB3000MB_REG_TPS_FFT ( 404)
-
-/* cell id from TPS (16) */
-#define DIB3000MB_REG_TPS_CELL_ID ( 406)
-
-/* TPS (68) */
-#define DIB3000MB_REG_TPS_1 ( 408)
-#define DIB3000MB_REG_TPS_2 ( 409)
-#define DIB3000MB_REG_TPS_3 ( 410)
-#define DIB3000MB_REG_TPS_4 ( 411)
-#define DIB3000MB_REG_TPS_5 ( 412)
-
-/* bit error rate (before RS correction) (21) */
-#define DIB3000MB_REG_BER_MSB ( 414)
-#define DIB3000MB_REG_BER_LSB ( 415)
-
-/* packet error rate (uncorrected TS packets) (16) */
-#define DIB3000MB_REG_PACKET_ERROR_RATE ( 417)
-
-/* uncorrected packet count (16) */
-#define DIB3000MB_REG_UNC ( 420)
-
-/* viterbi locked (1) */
-#define DIB3000MB_REG_VIT_LCK ( 421)
-
-/* viterbi inidcator (16) */
-#define DIB3000MB_REG_VIT_INDICATOR ( 422)
-
-/* transport stream sync lock (1) */
-#define DIB3000MB_REG_TS_SYNC_LOCK ( 423)
-
-/* transport stream RS lock (1) */
-#define DIB3000MB_REG_TS_RS_LOCK ( 424)
-
-/* lock mask 0 value (1) */
-#define DIB3000MB_REG_LOCK0_VALUE ( 425)
-
-/* lock mask 1 value (1) */
-#define DIB3000MB_REG_LOCK1_VALUE ( 426)
-
-/* lock mask 2 value (1) */
-#define DIB3000MB_REG_LOCK2_VALUE ( 427)
-/* interrupt pending for auto search */
-#define DIB3000MB_REG_AS_IRQ_PENDING ( 434)
+extern struct dvb_frontend* dib3000mb_attach(const struct dib3000mb_config* config,
+ struct i2c_adapter* i2c);
-#endif
+#endif // DIB3000MB_H
diff --git a/linux/drivers/media/dvb/frontends/dib3000mb_priv.h b/linux/drivers/media/dvb/frontends/dib3000mb_priv.h
new file mode 100644
index 000000000..9875403ab
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/dib3000mb_priv.h
@@ -0,0 +1,656 @@
+/*
+ * dib3000mb.h
+ *
+ * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * 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, version 2.
+ *
+ * $Id: dib3000mb_priv.h,v 1.2 2004/10/28 17:37:07 quincy Exp $
+ *
+ * for more information see dib3000mb.c .
+ */
+
+#ifndef __DIB3000MB_PRIV_H_INCLUDED__
+#define __DIB3000MB_PRIV_H_INCLUDED__
+
+/* info and err, taken from usb.h, if there is anything available like by default,
+ * please change !
+ */
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
+
+/* register addresses and some of their default values */
+
+/* restart subsystems */
+#define DIB3000MB_REG_RESTART ( 0)
+
+#define DIB3000MB_RESTART_OFF ( 0)
+#define DIB3000MB_RESTART_AUTO_SEARCH (1 << 1)
+#define DIB3000MB_RESTART_CTRL (1 << 2)
+#define DIB3000MB_RESTART_AGC (1 << 3)
+
+/* FFT size */
+#define DIB3000MB_REG_FFT ( 1)
+#define DIB3000MB_FFT_2K ( 0)
+#define DIB3000MB_FFT_8K ( 1)
+#define DIB3000MB_FFT_AUTO ( 1)
+
+/* Guard time */
+#define DIB3000MB_REG_GUARD_TIME ( 2)
+#define DIB3000MB_GUARD_TIME_1_32 ( 0)
+#define DIB3000MB_GUARD_TIME_1_16 ( 1)
+#define DIB3000MB_GUARD_TIME_1_8 ( 2)
+#define DIB3000MB_GUARD_TIME_1_4 ( 3)
+#define DIB3000MB_GUARD_TIME_AUTO ( 0)
+
+/* QAM */
+#define DIB3000MB_REG_QAM ( 3)
+#define DIB3000MB_QAM_QPSK ( 0)
+#define DIB3000MB_QAM_QAM16 ( 1)
+#define DIB3000MB_QAM_QAM64 ( 2)
+#define DIB3000MB_QAM_RESERVED ( 3)
+
+/* Alpha coefficient high priority Viterbi algorithm */
+#define DIB3000MB_REG_VIT_ALPHA ( 4)
+#define DIB3000MB_VIT_ALPHA_OFF ( 0)
+#define DIB3000MB_VIT_ALPHA_1 ( 1)
+#define DIB3000MB_VIT_ALPHA_2 ( 2)
+#define DIB3000MB_VIT_ALPHA_4 ( 4)
+#define DIB3000MB_VIT_ALPHA_AUTO ( 7)
+
+/* spectrum inversion */
+#define DIB3000MB_REG_DDS_INV ( 5)
+#define DIB3000MB_DDS_INV_OFF ( 0)
+#define DIB3000MB_DDS_INV_ON ( 1)
+
+/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */
+#define DIB3000MB_REG_DDS_FREQ_MSB ( 6)
+#define DIB3000MB_REG_DDS_FREQ_LSB ( 7)
+#define DIB3000MB_DDS_FREQ_MSB ( 178)
+#define DIB3000MB_DDS_FREQ_LSB ( 8990)
+
+/* timing frequency (carrier spacing) */
+#define DIB3000MB_REG_TIMING_FREQ_MSB ( 8)
+#define DIB3000MB_REG_TIMING_FREQ_LSB ( 9)
+
+static u16 dib3000mb_reg_timing_freq[] = {
+ DIB3000MB_REG_TIMING_FREQ_MSB, DIB3000MB_REG_TIMING_FREQ_LSB
+};
+static u16 dib3000mb_timing_freq[][2] = {
+ { 126 , 48873 }, /* 6 MHz */
+ { 147 , 57019 }, /* 7 MHz */
+ { 168 , 65164 }, /* 8 MHz */
+};
+
+/* impulse noise parameter */
+#define DIB3000MB_REG_IMPNOISE_10 ( 10)
+#define DIB3000MB_REG_IMPNOISE_11 ( 11)
+#define DIB3000MB_REG_IMPNOISE_12 ( 12)
+#define DIB3000MB_REG_IMPNOISE_13 ( 13)
+#define DIB3000MB_REG_IMPNOISE_14 ( 14)
+#define DIB3000MB_REG_IMPNOISE_15 ( 15)
+/* 36 ??? */
+#define DIB3000MB_REG_IMPNOISE_36 ( 36)
+
+enum dib3000mb_impulse_noise_type {
+ DIB3000MB_IMPNOISE_OFF,
+ DIB3000MB_IMPNOISE_MOBILE,
+ DIB3000MB_IMPNOISE_FIXED,
+ DIB3000MB_IMPNOISE_DEFAULT
+};
+
+static u16 dib3000mb_reg_impulse_noise[] = {
+ DIB3000MB_REG_IMPNOISE_10, DIB3000MB_REG_IMPNOISE_11,
+ DIB3000MB_REG_IMPNOISE_12, DIB3000MB_REG_IMPNOISE_15,
+ DIB3000MB_REG_IMPNOISE_36
+};
+
+static u16 dib3000mb_impulse_noise_values[][5] = {
+ { 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */
+ { 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */
+ { 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */
+ { 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */
+};
+
+/*
+ * Dual Automatic-Gain-Control
+ * - gains RF in tuner (AGC1)
+ * - gains IF after filtering (AGC2)
+ */
+
+/* also from 16 to 18 */
+#define DIB3000MB_REG_AGC_GAIN_19 ( 19)
+#define DIB3000MB_REG_AGC_GAIN_20 ( 20)
+#define DIB3000MB_REG_AGC_GAIN_21 ( 21)
+#define DIB3000MB_REG_AGC_GAIN_22 ( 22)
+#define DIB3000MB_REG_AGC_GAIN_23 ( 23)
+#define DIB3000MB_REG_AGC_GAIN_24 ( 24)
+#define DIB3000MB_REG_AGC_GAIN_25 ( 25)
+#define DIB3000MB_REG_AGC_GAIN_26 ( 26)
+#define DIB3000MB_REG_AGC_GAIN_27 ( 27)
+#define DIB3000MB_REG_AGC_GAIN_28 ( 28)
+#define DIB3000MB_REG_AGC_GAIN_29 ( 29)
+#define DIB3000MB_REG_AGC_GAIN_30 ( 30)
+#define DIB3000MB_REG_AGC_GAIN_31 ( 31)
+#define DIB3000MB_REG_AGC_GAIN_32 ( 32)
+
+static u16 dib3000mb_reg_agc_gain[] = {
+ DIB3000MB_REG_AGC_GAIN_19, DIB3000MB_REG_AGC_GAIN_20, DIB3000MB_REG_AGC_GAIN_21,
+ DIB3000MB_REG_AGC_GAIN_22, DIB3000MB_REG_AGC_GAIN_23, DIB3000MB_REG_AGC_GAIN_24,
+ DIB3000MB_REG_AGC_GAIN_25, DIB3000MB_REG_AGC_GAIN_26, DIB3000MB_REG_AGC_GAIN_27,
+ DIB3000MB_REG_AGC_GAIN_28, DIB3000MB_REG_AGC_GAIN_29, DIB3000MB_REG_AGC_GAIN_30,
+ DIB3000MB_REG_AGC_GAIN_31, DIB3000MB_REG_AGC_GAIN_32 };
+
+static u16 dib3000mb_default_agc_gain[] =
+ { 0x0001, 52429, 623, 128, 166, 195, 61, /* RF ??? */
+ 0x0001, 53766, 38011, 0, 90, 33, 23 }; /* IF ??? */
+
+/* phase noise */
+#define DIB3000MB_REG_PHASE_NOISE_33 ( 33)
+#define DIB3000MB_REG_PHASE_NOISE_34 ( 34)
+#define DIB3000MB_REG_PHASE_NOISE_35 ( 35)
+#define DIB3000MB_REG_PHASE_NOISE_36 ( 36)
+#define DIB3000MB_REG_PHASE_NOISE_37 ( 37)
+#define DIB3000MB_REG_PHASE_NOISE_38 ( 38)
+
+/* DIB3000MB_REG_PHASE_NOISE_36 is set when setting the impulse noise */
+static u16 dib3000mb_reg_phase_noise[] = {
+ DIB3000MB_REG_PHASE_NOISE_33, DIB3000MB_REG_PHASE_NOISE_34, DIB3000MB_REG_PHASE_NOISE_35,
+ DIB3000MB_REG_PHASE_NOISE_37, DIB3000MB_REG_PHASE_NOISE_38
+};
+
+static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 };
+
+/* lock duration */
+#define DIB3000MB_REG_LOCK_DURATION_39 ( 39)
+#define DIB3000MB_REG_LOCK_DURATION_40 ( 40)
+
+static u16 dib3000mb_reg_lock_duration[] = {
+ DIB3000MB_REG_LOCK_DURATION_39, DIB3000MB_REG_LOCK_DURATION_40
+};
+
+static u16 dib3000mb_default_lock_duration[] = { 135, 135 };
+
+/* AGC loop bandwidth */
+
+#define DIB3000MB_REG_AGC_BW_43 ( 43)
+#define DIB3000MB_REG_AGC_BW_44 ( 44)
+#define DIB3000MB_REG_AGC_BW_45 ( 45)
+#define DIB3000MB_REG_AGC_BW_46 ( 46)
+#define DIB3000MB_REG_AGC_BW_47 ( 47)
+#define DIB3000MB_REG_AGC_BW_48 ( 48)
+#define DIB3000MB_REG_AGC_BW_49 ( 49)
+#define DIB3000MB_REG_AGC_BW_50 ( 50)
+
+static u16 dib3000mb_reg_agc_bandwidth[] = {
+ DIB3000MB_REG_AGC_BW_43, DIB3000MB_REG_AGC_BW_44, DIB3000MB_REG_AGC_BW_45,
+ DIB3000MB_REG_AGC_BW_46, DIB3000MB_REG_AGC_BW_47, DIB3000MB_REG_AGC_BW_48,
+ DIB3000MB_REG_AGC_BW_49, DIB3000MB_REG_AGC_BW_50
+};
+
+static u16 dib3000mb_agc_bandwidth_low[] =
+ { 2088, 10, 2088, 10, 3448, 5, 3448, 5 };
+static u16 dib3000mb_agc_bandwidth_high[] =
+ { 2349, 5, 2349, 5, 2586, 2, 2586, 2 };
+
+/*
+ * lock0 definition (coff_lock)
+ */
+#define DIB3000MB_REG_LOCK0_MASK ( 51)
+#define DIB3000MB_LOCK0_DEFAULT ( 4)
+
+/*
+ * lock1 definition (cpil_lock)
+ * for auto search
+ * which values hide behind the lock masks
+ */
+#define DIB3000MB_REG_LOCK1_MASK ( 52)
+#define DIB3000MB_LOCK1_SEARCH_4 (0x0004)
+#define DIB3000MB_LOCK1_SEARCH_2048 (0x0800)
+#define DIB3000MB_LOCK1_DEFAULT (0x0001)
+
+/*
+ * lock2 definition (fec_lock) */
+#define DIB3000MB_REG_LOCK2_MASK ( 53)
+#define DIB3000MB_LOCK2_DEFAULT (0x0080)
+
+/*
+ * SEQ ? what was that again ... :)
+ * changes when, inversion, guard time and fft is
+ * either automatically detected or not
+ */
+#define DIB3000MB_REG_SEQ ( 54)
+
+/* all values have been set manually */
+static u16 dib3000mb_seq[2][2][2] = /* fft,gua, inv */
+ { /* fft */
+ { /* gua */
+ { 0, 1 }, /* 0 0 { 0,1 } */
+ { 3, 9 }, /* 0 1 { 0,1 } */
+ },
+ {
+ { 2, 5 }, /* 1 0 { 0,1 } */
+ { 6, 11 }, /* 1 1 { 0,1 } */
+ }
+ };
+
+/* bandwidth */
+#define DIB3000MB_REG_BW_55 ( 55)
+#define DIB3000MB_REG_BW_56 ( 56)
+#define DIB3000MB_REG_BW_57 ( 57)
+#define DIB3000MB_REG_BW_58 ( 58)
+#define DIB3000MB_REG_BW_59 ( 59)
+#define DIB3000MB_REG_BW_60 ( 60)
+#define DIB3000MB_REG_BW_61 ( 61)
+#define DIB3000MB_REG_BW_62 ( 62)
+#define DIB3000MB_REG_BW_63 ( 63)
+#define DIB3000MB_REG_BW_64 ( 64)
+#define DIB3000MB_REG_BW_65 ( 65)
+#define DIB3000MB_REG_BW_66 ( 66)
+#define DIB3000MB_REG_BW_67 ( 67)
+
+static u16 dib3000mb_reg_bandwidth[] = {
+ DIB3000MB_REG_BW_55, DIB3000MB_REG_BW_56, DIB3000MB_REG_BW_57,
+ DIB3000MB_REG_BW_58, DIB3000MB_REG_BW_59, DIB3000MB_REG_BW_60,
+ DIB3000MB_REG_BW_61, DIB3000MB_REG_BW_62, DIB3000MB_REG_BW_63,
+ DIB3000MB_REG_BW_64, DIB3000MB_REG_BW_65, DIB3000MB_REG_BW_66,
+ DIB3000MB_REG_BW_67
+};
+
+static u16 dib3000mb_bandwidth_6mhz[] =
+ { 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 };
+
+static u16 dib3000mb_bandwidth_7mhz[] =
+ { 0, 28, 64421, 96, 39973, 483, 3255, 0, 1000, 0, 1010, 1, 45264 };
+
+static u16 dib3000mb_bandwidth_8mhz[] =
+ { 0, 25, 23600, 84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 };
+
+#define DIB3000MB_REG_UNK_68 ( 68)
+#define DIB3000MB_UNK_68 ( 0)
+
+#define DIB3000MB_REG_UNK_69 ( 69)
+#define DIB3000MB_UNK_69 ( 0)
+
+#define DIB3000MB_REG_UNK_71 ( 71)
+#define DIB3000MB_UNK_71 ( 0)
+
+#define DIB3000MB_REG_UNK_77 ( 77)
+#define DIB3000MB_UNK_77 ( 6)
+
+#define DIB3000MB_REG_UNK_78 ( 78)
+#define DIB3000MB_UNK_78 (0x0080)
+
+/* isi */
+#define DIB3000MB_REG_ISI ( 79)
+#define DIB3000MB_ISI_ACTIVATE ( 0)
+#define DIB3000MB_ISI_INHIBIT ( 1)
+
+/* sync impovement */
+#define DIB3000MB_REG_SYNC_IMPROVEMENT ( 84)
+#define DIB3000MB_SYNC_IMPROVE_2K_1_8 ( 3)
+#define DIB3000MB_SYNC_IMPROVE_DEFAULT ( 0)
+
+/* phase noise compensation inhibition */
+#define DIB3000MB_REG_PHASE_NOISE ( 87)
+#define DIB3000MB_PHASE_NOISE_DEFAULT ( 0)
+
+#define DIB3000MB_REG_UNK_92 ( 92)
+#define DIB3000MB_UNK_92 (0x0080)
+
+#define DIB3000MB_REG_UNK_96 ( 96)
+#define DIB3000MB_UNK_96 (0x0010)
+
+#define DIB3000MB_REG_UNK_97 ( 97)
+#define DIB3000MB_UNK_97 (0x0009)
+
+/* mobile mode ??? */
+#define DIB3000MB_REG_MOBILE_MODE ( 101)
+#define DIB3000MB_MOBILE_MODE_ON ( 1)
+#define DIB3000MB_MOBILE_MODE_OFF ( 0)
+
+#define DIB3000MB_REG_UNK_106 ( 106)
+#define DIB3000MB_UNK_106 (0x0080)
+
+#define DIB3000MB_REG_UNK_107 ( 107)
+#define DIB3000MB_UNK_107 (0x0080)
+
+#define DIB3000MB_REG_UNK_108 ( 108)
+#define DIB3000MB_UNK_108 (0x0080)
+
+/* fft */
+#define DIB3000MB_REG_UNK_121 ( 121)
+#define DIB3000MB_UNK_121_2K ( 7)
+#define DIB3000MB_UNK_121_DEFAULT ( 5)
+
+#define DIB3000MB_REG_UNK_122 ( 122)
+#define DIB3000MB_UNK_122 ( 2867)
+
+/* QAM for mobile mode */
+#define DIB3000MB_REG_MOBILE_MODE_QAM ( 126)
+#define DIB3000MB_MOBILE_MODE_QAM_64 ( 3)
+#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16 ( 1)
+#define DIB3000MB_MOBILE_MODE_QAM_OFF ( 0)
+
+/*
+ * data diversity when having more than one chip on-board
+ * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY
+ */
+#define DIB3000MB_REG_DATA_IN_DIVERSITY ( 127)
+#define DIB3000MB_DATA_DIVERSITY_IN_OFF ( 0)
+#define DIB3000MB_DATA_DIVERSITY_IN_ON ( 2)
+
+/* vit hrch */
+#define DIB3000MB_REG_VIT_HRCH ( 128)
+#define DIB3000MB_VIT_HRCH_ON ( 1)
+#define DIB3000MB_VIT_HRCH_OFF ( 0)
+
+/* vit code rate */
+#define DIB3000MB_REG_VIT_CODE_RATE ( 129)
+
+/* forward error correction code rates */
+#define DIB3000MB_FEC_1_2 ( 1)
+#define DIB3000MB_FEC_2_3 ( 2)
+#define DIB3000MB_FEC_3_4 ( 3)
+#define DIB3000MB_FEC_5_6 ( 5)
+#define DIB3000MB_FEC_7_8 ( 7)
+
+/* vit select hp */
+#define DIB3000MB_REG_VIT_HP ( 130)
+#define DIB3000MB_VIT_LP ( 0)
+#define DIB3000MB_VIT_HP ( 1)
+
+/* time frame for Bit-Error-Rate calculation */
+#define DIB3000MB_REG_BERLEN ( 135)
+#define DIB3000MB_BERLEN_LONG ( 0)
+#define DIB3000MB_BERLEN_DEFAULT ( 1)
+#define DIB3000MB_BERLEN_MEDIUM ( 2)
+#define DIB3000MB_BERLEN_SHORT ( 3)
+
+/* 142 - 152 FIFO parameters
+ * which is what ?
+ */
+
+#define DIB3000MB_REG_FIFO_142 ( 142)
+#define DIB3000MB_FIFO_142 ( 0)
+
+/* MPEG2 TS output mode */
+#define DIB3000MB_REG_MPEG2_OUT_MODE ( 143)
+#define DIB3000MB_MPEG2_OUT_MODE_204 ( 0)
+#define DIB3000MB_MPEG2_OUT_MODE_188 ( 1)
+
+#define DIB3000MB_REG_FIFO_144 ( 144)
+#define DIB3000MB_FIFO_144 ( 1)
+
+#define DIB3000MB_REG_FIFO ( 145)
+#define DIB3000MB_FIFO_INHIBIT ( 1)
+#define DIB3000MB_FIFO_ACTIVATE ( 0)
+
+#define DIB3000MB_REG_FIFO_146 ( 146)
+#define DIB3000MB_FIFO_146 ( 3)
+
+#define DIB3000MB_REG_FIFO_147 ( 147)
+#define DIB3000MB_FIFO_147 (0x0100)
+
+/*
+ * pidfilter
+ * it is not a hardware pidfilter but a filter which drops all pids
+ * except the ones set. Necessary because of the limited USB1.1 bandwidth.
+ */
+#define DIB3000MB_REG_FILTER_PID_0 ( 153)
+#define DIB3000MB_REG_FILTER_PID_1 ( 154)
+#define DIB3000MB_REG_FILTER_PID_2 ( 155)
+#define DIB3000MB_REG_FILTER_PID_3 ( 156)
+#define DIB3000MB_REG_FILTER_PID_4 ( 157)
+#define DIB3000MB_REG_FILTER_PID_5 ( 158)
+#define DIB3000MB_REG_FILTER_PID_6 ( 159)
+#define DIB3000MB_REG_FILTER_PID_7 ( 160)
+#define DIB3000MB_REG_FILTER_PID_8 ( 161)
+#define DIB3000MB_REG_FILTER_PID_9 ( 162)
+#define DIB3000MB_REG_FILTER_PID_10 ( 163)
+#define DIB3000MB_REG_FILTER_PID_11 ( 164)
+#define DIB3000MB_REG_FILTER_PID_12 ( 165)
+#define DIB3000MB_REG_FILTER_PID_13 ( 166)
+#define DIB3000MB_REG_FILTER_PID_14 ( 167)
+#define DIB3000MB_REG_FILTER_PID_15 ( 168)
+
+#define DIB3000MB_ACTIVATE_FILTERING (0x2000)
+
+/*
+ * output mode
+ * USB devices have to use 'slave'-mode
+ * see also DIB3000MB_REG_ELECT_OUT_MODE
+ */
+#define DIB3000MB_REG_OUTPUT_MODE ( 169)
+#define DIB3000MB_OUTPUT_MODE_GATED_CLK ( 0)
+#define DIB3000MB_OUTPUT_MODE_CONT_CLK ( 1)
+#define DIB3000MB_OUTPUT_MODE_SERIAL ( 2)
+#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY ( 5)
+#define DIB3000MB_OUTPUT_MODE_SLAVE ( 6)
+
+/* irq event mask */
+#define DIB3000MB_REG_IRQ_EVENT_MASK ( 170)
+#define DIB3000MB_IRQ_EVENT_MASK ( 0)
+
+/* filter coefficients */
+#define DIB3000MB_REG_FILTER_COEF_171 ( 171)
+#define DIB3000MB_REG_FILTER_COEF_172 ( 172)
+#define DIB3000MB_REG_FILTER_COEF_173 ( 173)
+#define DIB3000MB_REG_FILTER_COEF_174 ( 174)
+#define DIB3000MB_REG_FILTER_COEF_175 ( 175)
+#define DIB3000MB_REG_FILTER_COEF_176 ( 176)
+#define DIB3000MB_REG_FILTER_COEF_177 ( 177)
+#define DIB3000MB_REG_FILTER_COEF_178 ( 178)
+#define DIB3000MB_REG_FILTER_COEF_179 ( 179)
+#define DIB3000MB_REG_FILTER_COEF_180 ( 180)
+#define DIB3000MB_REG_FILTER_COEF_181 ( 181)
+#define DIB3000MB_REG_FILTER_COEF_182 ( 182)
+#define DIB3000MB_REG_FILTER_COEF_183 ( 183)
+#define DIB3000MB_REG_FILTER_COEF_184 ( 184)
+#define DIB3000MB_REG_FILTER_COEF_185 ( 185)
+#define DIB3000MB_REG_FILTER_COEF_186 ( 186)
+#define DIB3000MB_REG_FILTER_COEF_187 ( 187)
+#define DIB3000MB_REG_FILTER_COEF_188 ( 188)
+#define DIB3000MB_REG_FILTER_COEF_189 ( 189)
+#define DIB3000MB_REG_FILTER_COEF_190 ( 190)
+#define DIB3000MB_REG_FILTER_COEF_191 ( 191)
+#define DIB3000MB_REG_FILTER_COEF_192 ( 192)
+#define DIB3000MB_REG_FILTER_COEF_193 ( 193)
+#define DIB3000MB_REG_FILTER_COEF_194 ( 194)
+
+static u16 dib3000mb_reg_filter_coeffs[] = {
+ DIB3000MB_REG_FILTER_COEF_171, DIB3000MB_REG_FILTER_COEF_172, DIB3000MB_REG_FILTER_COEF_173,
+ DIB3000MB_REG_FILTER_COEF_174, DIB3000MB_REG_FILTER_COEF_175, DIB3000MB_REG_FILTER_COEF_176,
+ DIB3000MB_REG_FILTER_COEF_177, DIB3000MB_REG_FILTER_COEF_178, DIB3000MB_REG_FILTER_COEF_179,
+ DIB3000MB_REG_FILTER_COEF_180, DIB3000MB_REG_FILTER_COEF_181, DIB3000MB_REG_FILTER_COEF_182,
+ DIB3000MB_REG_FILTER_COEF_183, DIB3000MB_REG_FILTER_COEF_184, DIB3000MB_REG_FILTER_COEF_185,
+ DIB3000MB_REG_FILTER_COEF_186, DIB3000MB_REG_FILTER_COEF_188,
+ DIB3000MB_REG_FILTER_COEF_189, DIB3000MB_REG_FILTER_COEF_190, DIB3000MB_REG_FILTER_COEF_191,
+ DIB3000MB_REG_FILTER_COEF_192, DIB3000MB_REG_FILTER_COEF_194
+};
+
+static u16 dib3000mb_filter_coeffs[] = {
+ 226, 160, 29,
+ 979, 998, 19,
+ 22, 1019, 1006,
+ 1022, 12, 6,
+ 1017, 1017, 3,
+ 6, 1019,
+ 1021, 2, 3,
+ 1, 0,
+};
+
+/*
+ * mobile algorithm (when you are moving with your device)
+ * but not faster than 90 km/h
+ */
+#define DIB3000MB_REG_MOBILE_ALGO ( 195)
+#define DIB3000MB_MOBILE_ALGO_ON ( 0)
+#define DIB3000MB_MOBILE_ALGO_OFF ( 1)
+
+/* multiple demodulators algorithm */
+#define DIB3000MB_REG_MULTI_DEMOD_MSB ( 206)
+#define DIB3000MB_REG_MULTI_DEMOD_LSB ( 207)
+
+/* terminator, no more demods */
+#define DIB3000MB_MULTI_DEMOD_MSB ( 32767)
+#define DIB3000MB_MULTI_DEMOD_LSB ( 4095)
+
+/* bring the device into a known */
+#define DIB3000MB_REG_RESET_DEVICE ( 1024)
+#define DIB3000MB_RESET_DEVICE (0x812c)
+#define DIB3000MB_RESET_DEVICE_RST ( 0)
+
+/* identification registers, manufactor an the device */
+#define DIB3000MB_REG_MANUFACTOR_ID ( 1025)
+#define DIB3000MB_MANUFACTOR_ID_DIBCOM (0x01B3)
+
+#define DIB3000MB_REG_DEVICE_ID ( 1026)
+#define DIB3000MB_DEVICE_ID (0x3000)
+
+/* hardware clock configuration */
+#define DIB3000MB_REG_CLOCK ( 1027)
+#define DIB3000MB_CLOCK_DEFAULT (0x9000)
+#define DIB3000MB_CLOCK_DIVERSITY (0x92b0)
+
+/* power down config */
+#define DIB3000MB_REG_POWER_CONTROL ( 1028)
+#define DIB3000MB_POWER_DOWN ( 1)
+#define DIB3000MB_POWER_UP ( 0)
+
+/* electrical output mode */
+#define DIB3000MB_REG_ELECT_OUT_MODE ( 1029)
+#define DIB3000MB_ELECT_OUT_MODE_OFF ( 0)
+#define DIB3000MB_ELECT_OUT_MODE_ON ( 1)
+
+/* set the tuner i2c address */
+#define DIB3000MB_REG_TUNER ( 1089)
+#define DIB3000MB_ACTIVATE_TUNER_XFER(a) (0xffff & (a << 7))
+#define DIB3000MB_DEACTIVATE_TUNER_XFER(a) (0xffff & ((a << 7) + 0x80))
+
+/* monitoring registers (read only) */
+
+/* agc loop locked (size: 1) */
+#define DIB3000MB_REG_AGC_LOCK ( 324)
+
+/* agc power (size: 16) */
+#define DIB3000MB_REG_AGC_POWER ( 325)
+
+/* agc1 value (16) */
+#define DIB3000MB_REG_AGC1_VALUE ( 326)
+
+/* agc2 value (16) */
+#define DIB3000MB_REG_AGC2_VALUE ( 327)
+
+/* total RF power (16), can be used for signal strength */
+#define DIB3000MB_REG_RF_POWER ( 328)
+
+/* dds_frequency with offset (24) */
+#define DIB3000MB_REG_DDS_VALUE_MSB ( 339)
+#define DIB3000MB_REG_DDS_VALUE_LSB ( 340)
+
+/* timing offset signed (24) */
+#define DIB3000MB_REG_TIMING_OFFSET_MSB ( 341)
+#define DIB3000MB_REG_TIMING_OFFSET_LSB ( 342)
+
+/* fft start position (13) */
+#define DIB3000MB_REG_FFT_WINDOW_POS ( 353)
+
+/* carriers locked (1) */
+#define DIB3000MB_REG_CARRIER_LOCK ( 355)
+
+/* noise power (24) */
+#define DIB3000MB_REG_NOISE_POWER_MSB ( 372)
+#define DIB3000MB_REG_NOISE_POWER_LSB ( 373)
+
+#define DIB3000MB_REG_MOBILE_NOISE_MSB ( 374)
+#define DIB3000MB_REG_MOBILE_NOISE_LSB ( 375)
+
+/*
+ * signal power (16), this and the above can be
+ * used to calculate the signal/noise - ratio
+ */
+#define DIB3000MB_REG_SIGNAL_POWER ( 380)
+
+/* mer (24) */
+#define DIB3000MB_REG_MER_MSB ( 381)
+#define DIB3000MB_REG_MER_LSB ( 382)
+
+/*
+ * Transmission Parameter Signalling (TPS)
+ * the following registers can be used to get TPS-information.
+ * The values are according to the DVB-T standard.
+ */
+
+/* TPS locked (1) */
+#define DIB3000MB_REG_TPS_LOCK ( 394)
+
+/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */
+#define DIB3000MB_REG_TPS_QAM ( 398)
+
+/* hierarchy from TPS (1) */
+#define DIB3000MB_REG_TPS_HRCH ( 399)
+
+/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */
+#define DIB3000MB_REG_TPS_VIT_ALPHA ( 400)
+
+/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */
+#define DIB3000MB_REG_TPS_CODE_RATE_HP ( 401)
+
+/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */
+#define DIB3000MB_REG_TPS_CODE_RATE_LP ( 402)
+
+/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */
+#define DIB3000MB_REG_TPS_GUARD_TIME ( 403)
+
+/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */
+#define DIB3000MB_REG_TPS_FFT ( 404)
+
+/* cell id from TPS (16) */
+#define DIB3000MB_REG_TPS_CELL_ID ( 406)
+
+/* TPS (68) */
+#define DIB3000MB_REG_TPS_1 ( 408)
+#define DIB3000MB_REG_TPS_2 ( 409)
+#define DIB3000MB_REG_TPS_3 ( 410)
+#define DIB3000MB_REG_TPS_4 ( 411)
+#define DIB3000MB_REG_TPS_5 ( 412)
+
+/* bit error rate (before RS correction) (21) */
+#define DIB3000MB_REG_BER_MSB ( 414)
+#define DIB3000MB_REG_BER_LSB ( 415)
+
+/* packet error rate (uncorrected TS packets) (16) */
+#define DIB3000MB_REG_PACKET_ERROR_RATE ( 417)
+
+/* uncorrected packet count (16) */
+#define DIB3000MB_REG_UNC ( 420)
+
+/* viterbi locked (1) */
+#define DIB3000MB_REG_VIT_LCK ( 421)
+
+/* viterbi inidcator (16) */
+#define DIB3000MB_REG_VIT_INDICATOR ( 422)
+
+/* transport stream sync lock (1) */
+#define DIB3000MB_REG_TS_SYNC_LOCK ( 423)
+
+/* transport stream RS lock (1) */
+#define DIB3000MB_REG_TS_RS_LOCK ( 424)
+
+/* lock mask 0 value (1) */
+#define DIB3000MB_REG_LOCK0_VALUE ( 425)
+
+/* lock mask 1 value (1) */
+#define DIB3000MB_REG_LOCK1_VALUE ( 426)
+
+/* lock mask 2 value (1) */
+#define DIB3000MB_REG_LOCK2_VALUE ( 427)
+
+/* interrupt pending for auto search */
+#define DIB3000MB_REG_AS_IRQ_PENDING ( 434)
+
+#endif
diff --git a/linux/drivers/media/dvb/frontends/dst.c b/linux/drivers/media/dvb/frontends/dst.c
deleted file mode 100644
index 42d1ad28b..000000000
--- a/linux/drivers/media/dvb/frontends/dst.c
+++ /dev/null
@@ -1,1256 +0,0 @@
-/*
- Frontend-driver for TwinHan DST Frontend
-
- Copyright (C) 2003 Jamie Honan
-
- 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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "dst-bt878.h"
-
-unsigned int dst_verbose = 0;
-MODULE_PARM(dst_verbose, "i");
-MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
-unsigned int dst_debug = 0;
-MODULE_PARM(dst_debug, "i");
-MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
-
-#define dprintk if (dst_debug) printk
-
-#define DST_I2C_ADDR 0x55
-
-#define DST_TYPE_IS_SAT 0
-#define DST_TYPE_IS_TERR 1
-#define DST_TYPE_IS_CABLE 2
-
-#define DST_TYPE_HAS_NEWTUNE 1
-#define DST_TYPE_HAS_TS204 2
-#define DST_TYPE_HAS_SYMDIV 4
-
-#define HAS_LOCK 1
-#define ATTEMPT_TUNE 2
-#define HAS_POWER 4
-
-struct dst_data {
- u8 tx_tuna[10];
- u8 rx_tuna[10];
- u8 rxbuffer[10];
- u8 diseq_flags;
- u8 dst_type;
- u32 type_flags;
- u32 frequency; /* intermediate frequency in kHz for QPSK */
- fe_spectral_inversion_t inversion;
- u32 symbol_rate; /* symbol rate in Symbols per second */
- fe_code_rate_t fec;
- fe_sec_voltage_t voltage;
- fe_sec_tone_mode_t tone;
- u32 decode_freq;
- u8 decode_lock;
- u16 decode_strength;
- u16 decode_snr;
- unsigned long cur_jiff;
- u8 k22;
- fe_bandwidth_t bandwidth;
-
- struct bt878 *bt;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
-};
-
-static struct dvb_frontend_info dst_info_sat = {
- .name = "DST SAT",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = 1000, /* kHz for QPSK frontends */
- .frequency_tolerance = 29500,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
-/* . symbol_rate_tolerance = ???,*/
- .notifier_delay = 50, /* 1/20 s */
- .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
-};
-
-static struct dvb_frontend_info dst_info_cable = {
- .name = "DST CABLE",
- .type = FE_QAM,
- .frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
-/* . symbol_rate_tolerance = ???,*/
- .notifier_delay = 50, /* 1/20 s */
- .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
-};
-
-static struct dvb_frontend_info dst_info_terr = {
- .name = "DST TERR",
- .type = FE_OFDM,
- .frequency_min = 137000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 166667,
- .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
-};
-
-static void dst_packsize(struct dst_data *dst, int psize)
-{
- union dst_gpio_packet bits;
-
- bits.psize = psize;
- bt878_device_control(dst->bt, DST_IG_TS, &bits);
-}
-
-static int dst_gpio_outb(struct dst_data *dst, u32 mask, u32 enbb, u32 outhigh)
-{
- union dst_gpio_packet enb;
- union dst_gpio_packet bits;
- int err;
-
- enb.enb.mask = mask;
- enb.enb.enable = enbb;
- if ((err = bt878_device_control(dst->bt, DST_IG_ENABLE, &enb)) < 0) {
- dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb);
- return -EREMOTEIO;
- }
-
- /* because complete disabling means no output, no need to do output packet */
- if (enbb == 0)
- return 0;
-
- bits.outp.mask = enbb;
- bits.outp.highvals = outhigh;
-
- if ((err = bt878_device_control(dst->bt, DST_IG_WRITE, &bits)) < 0) {
- dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh);
- return -EREMOTEIO;
- }
- return 0;
-}
-
-static int dst_gpio_inb(struct dst_data *dst, u8 * result)
-{
- union dst_gpio_packet rd_packet;
- int err;
-
- *result = 0;
-
- if ((err = bt878_device_control(dst->bt, DST_IG_READ, &rd_packet)) < 0) {
- dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err);
- return -EREMOTEIO;
- }
- *result = (u8) rd_packet.rd.value;
- return 0;
-}
-
-#define DST_I2C_ENABLE 1
-#define DST_8820 2
-
-static int dst_reset8820(struct dst_data *dst)
-{
- int retval;
- /* pull 8820 gpio pin low, wait, high, wait, then low */
- // dprintk ("%s: reset 8820\n", __FUNCTION__);
- retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
- if (retval < 0)
- return retval;
- msleep(10);
- retval = dst_gpio_outb(dst, DST_8820, DST_8820, DST_8820);
- if (retval < 0)
- return retval;
- /* wait for more feedback on what works here *
- msleep(10);
- retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
- if (retval < 0)
- return retval;
- */
- return 0;
-}
-
-static int dst_i2c_enable(struct dst_data *dst)
-{
- int retval;
- /* pull I2C enable gpio pin low, wait */
- // dprintk ("%s: i2c enable\n", __FUNCTION__);
- retval = dst_gpio_outb(dst, ~0, DST_I2C_ENABLE, 0);
- if (retval < 0)
- return retval;
- // dprintk ("%s: i2c enable delay\n", __FUNCTION__);
- msleep(33);
- return 0;
-}
-
-static int dst_i2c_disable(struct dst_data *dst)
-{
- int retval;
- /* release I2C enable gpio pin, wait */
- // dprintk ("%s: i2c disable\n", __FUNCTION__);
- retval = dst_gpio_outb(dst, ~0, 0, 0);
- if (retval < 0)
- return retval;
- // dprintk ("%s: i2c disable delay\n", __FUNCTION__);
- msleep(33);
- return 0;
-}
-
-static int dst_wait_dst_ready(struct dst_data *dst)
-{
- u8 reply;
- int retval;
- int i;
- for (i = 0; i < 200; i++) {
- retval = dst_gpio_inb(dst, &reply);
- if (retval < 0)
- return retval;
- if ((reply & DST_I2C_ENABLE) == 0) {
- dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i);
- return 1;
- }
- msleep(5);
- }
- dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
- return 0;
-}
-
-static int write_dst(struct dst_data *dst, u8 * data, u8 len)
-{
- struct i2c_msg msg = {
- .addr = DST_I2C_ADDR,.flags = 0,.buf = data,.len = len
- };
- int err;
- int cnt;
-
- if (dst_debug && dst_verbose) {
- u8 i;
- dprintk("%s writing", __FUNCTION__);
- for (i = 0; i < len; i++) {
- dprintk(" 0x%02x", data[i]);
- }
- dprintk("\n");
- }
- msleep(30);
- for (cnt = 0; cnt < 4; cnt++) {
- if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) {
- dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]);
- dst_i2c_disable(dst);
- msleep(500);
- dst_i2c_enable(dst);
- msleep(500);
- continue;
- } else
- break;
- }
- if (cnt >= 4)
- return -EREMOTEIO;
- return 0;
-}
-
-static int read_dst(struct dst_data *dst, u8 * ret, u8 len)
-{
- struct i2c_msg msg = {.addr = DST_I2C_ADDR,.flags = I2C_M_RD,.buf = ret,.len = len };
- int err;
- int cnt;
-
- for (cnt = 0; cnt < 4; cnt++) {
- if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) {
- dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]);
- dst_i2c_disable(dst);
- dst_i2c_enable(dst);
- continue;
- } else
- break;
- }
- if (cnt >= 4)
- return -EREMOTEIO;
- dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]);
- if (dst_debug && dst_verbose) {
- for (err = 1; err < len; err++)
- dprintk(" 0x%x", ret[err]);
- if (err > 1)
- dprintk("\n");
- }
- return 0;
-}
-
-static int dst_set_freq(struct dst_data *dst, u32 freq)
-{
- u8 *val;
-
- dst->frequency = freq;
-
- // dprintk("%s: set frequency %u\n", __FUNCTION__, freq);
- if (dst->dst_type == DST_TYPE_IS_SAT) {
- freq = freq / 1000;
- if (freq < 950 || freq > 2150)
- return -EINVAL;
- val = &dst->tx_tuna[0];
- val[2] = (freq >> 8) & 0x7f;
- val[3] = (u8) freq;
- val[4] = 1;
- val[8] &= ~4;
- if (freq < 1531)
- val[8] |= 4;
- } else if (dst->dst_type == DST_TYPE_IS_TERR) {
- freq = freq / 1000;
- if (freq < 137000 || freq > 858000)
- return -EINVAL;
- val = &dst->tx_tuna[0];
- val[2] = (freq >> 16) & 0xff;
- val[3] = (freq >> 8) & 0xff;
- val[4] = (u8) freq;
- val[5] = 0;
- switch (dst->bandwidth) {
- case BANDWIDTH_6_MHZ:
- val[6] = 6;
- break;
-
- case BANDWIDTH_7_MHZ:
- case BANDWIDTH_AUTO:
- val[6] = 7;
- break;
-
- case BANDWIDTH_8_MHZ:
- val[6] = 8;
- break;
- }
-
- val[7] = 0;
- val[8] = 0;
- } else if (dst->dst_type == DST_TYPE_IS_CABLE) {
- /* guess till will get one */
- freq = freq / 1000;
- val = &dst->tx_tuna[0];
- val[2] = (freq >> 16) & 0xff;
- val[3] = (freq >> 8) & 0xff;
- val[4] = (u8) freq;
- } else
- return -EINVAL;
- return 0;
-}
-
-static int dst_set_bandwidth(struct dst_data *dst, fe_bandwidth_t bandwidth)
-{
- u8 *val;
-
- dst->bandwidth = bandwidth;
-
- if (dst->dst_type != DST_TYPE_IS_TERR)
- return 0;
-
- val = &dst->tx_tuna[0];
- switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
- val[6] = 6;
- break;
-
- case BANDWIDTH_7_MHZ:
- val[6] = 7;
- break;
-
- case BANDWIDTH_8_MHZ:
- val[6] = 8;
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int dst_set_inversion(struct dst_data *dst, fe_spectral_inversion_t inversion)
-{
- u8 *val;
-
- dst->inversion = inversion;
-
- val = &dst->tx_tuna[0];
-
- val[8] &= ~0x80;
-
- switch (inversion) {
- case INVERSION_OFF:
- break;
- case INVERSION_ON:
- val[8] |= 0x80;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-
-static int dst_set_fec(struct dst_data *dst, fe_code_rate_t fec)
-{
- dst->fec = fec;
- return 0;
-}
-
-static fe_code_rate_t dst_get_fec(struct dst_data *dst)
-{
- return dst->fec;
-}
-
-static int dst_set_symbolrate(struct dst_data *dst, u32 srate)
-{
- u8 *val;
- u32 symcalc;
- u64 sval;
-
- dst->symbol_rate = srate;
-
- if (dst->dst_type == DST_TYPE_IS_TERR) {
- return 0;
- }
- // dprintk("%s: set srate %u\n", __FUNCTION__, srate);
- srate /= 1000;
- val = &dst->tx_tuna[0];
-
- if (dst->type_flags & DST_TYPE_HAS_SYMDIV) {
- sval = srate;
- sval <<= 20;
- do_div(sval, 88000);
- symcalc = (u32) sval;
- // dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc);
- val[5] = (u8) (symcalc >> 12);
- val[6] = (u8) (symcalc >> 4);
- val[7] = (u8) (symcalc << 4);
- } else {
- val[5] = (u8) (srate >> 16) & 0x7f;
- val[6] = (u8) (srate >> 8);
- val[7] = (u8) srate;
- }
- val[8] &= ~0x20;
- if (srate > 8000)
- val[8] |= 0x20;
- return 0;
-}
-
-
-static u8 dst_check_sum(u8 * buf, u32 len)
-{
- u32 i;
- u8 val = 0;
- if (!len)
- return 0;
- for (i = 0; i < len; i++) {
- val += buf[i];
- }
- return ((~val) + 1);
-}
-
-typedef struct dst_types {
- char *mstr;
- int offs;
- u8 dst_type;
- u32 type_flags;
-} DST_TYPES;
-
-struct dst_types dst_tlist[] = {
- {"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
- {"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
- {"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204},
- {"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
- {"DST-CI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
- {"DSTMCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
- {"DSTFCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
- {"DCTNEW", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE},
- {"DCT_CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204},
- {"DTTDIG", 1, DST_TYPE_IS_TERR, 0}
-};
-
-/* DCTNEW and DCT-CI are guesses */
-
-static void dst_type_flags_print(u32 type_flags)
-{
- printk("DST type flags :");
- if (type_flags & DST_TYPE_HAS_NEWTUNE)
- printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
- if (type_flags & DST_TYPE_HAS_TS204)
- printk(" 0x%x ts204", DST_TYPE_HAS_TS204);
- if (type_flags & DST_TYPE_HAS_SYMDIV)
- printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
- printk("\n");
-}
-
-static int dst_type_print(u8 type)
-{
- char *otype;
- switch (type) {
- case DST_TYPE_IS_SAT:
- otype = "satellite";
- break;
- case DST_TYPE_IS_TERR:
- otype = "terrestial TV";
- break;
- case DST_TYPE_IS_CABLE:
- otype = "terrestial TV";
- break;
- default:
- printk("%s: invalid dst type %d\n", __FUNCTION__, type);
- return -EINVAL;
- }
- printk("DST type : %s\n", otype);
- return 0;
-}
-
-static int dst_check_ci(struct dst_data *dst)
-{
- u8 txbuf[8];
- u8 rxbuf[8];
- int retval;
- int i;
- struct dst_types *dsp;
- u8 use_dst_type;
- u32 use_type_flags;
-
- memset(txbuf, 0, sizeof(txbuf));
- txbuf[1] = 6;
- txbuf[7] = dst_check_sum(txbuf, 7);
-
- dst_i2c_enable(dst);
- dst_reset8820(dst);
- retval = write_dst(dst, txbuf, 8);
- if (retval < 0) {
- dst_i2c_disable(dst);
- dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__);
- return retval;
- }
- msleep(3);
- retval = read_dst(dst, rxbuf, 1);
- dst_i2c_disable(dst);
- if (retval < 0) {
- dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__);
- return retval;
- }
- if (rxbuf[0] != 0xff) {
- dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]);
- return retval;
- }
- if (!dst_wait_dst_ready(dst))
- return 0;
- // dst_i2c_enable(i2c); Dimitri
- retval = read_dst(dst, rxbuf, 8);
- dst_i2c_disable(dst);
- if (retval < 0) {
- dprintk("%s: read not successful\n", __FUNCTION__);
- return retval;
- }
- if (rxbuf[7] != dst_check_sum(rxbuf, 7)) {
- dprintk("%s: checksum failure\n", __FUNCTION__);
- return retval;
- }
- rxbuf[7] = '\0';
- for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) {
- if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) {
- use_type_flags = dsp->type_flags;
- use_dst_type = dsp->dst_type;
- printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr);
- break;
- }
- }
- if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) {
- printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]);
- printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__);
- use_dst_type = DST_TYPE_IS_SAT;
- use_type_flags = DST_TYPE_HAS_SYMDIV;
- }
- dst_type_print(use_dst_type);
-
- dst->type_flags = use_type_flags;
- dst->dst_type = use_dst_type;
- dst_type_flags_print(dst->type_flags);
-
- if (dst->type_flags & DST_TYPE_HAS_TS204) {
- dst_packsize(dst, 204);
- }
- return 0;
-}
-
-static int dst_command(struct dst_data *dst, u8 * data, u8 len)
-{
- int retval;
- u8 reply;
-
- dst_i2c_enable(dst);
- dst_reset8820(dst);
- retval = write_dst(dst, data, len);
- if (retval < 0) {
- dst_i2c_disable(dst);
- dprintk("%s: write not successful\n", __FUNCTION__);
- return retval;
- }
- msleep(33);
- retval = read_dst(dst, &reply, 1);
- dst_i2c_disable(dst);
- if (retval < 0) {
- dprintk("%s: read verify not successful\n", __FUNCTION__);
- return retval;
- }
- if (reply != 0xff) {
- dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
- return 0;
- }
- if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
- return 0;
- if (!dst_wait_dst_ready(dst))
- return 0;
- // dst_i2c_enable(i2c); Per dimitri
- retval = read_dst(dst, dst->rxbuffer, 8);
- dst_i2c_disable(dst);
- if (retval < 0) {
- dprintk("%s: read not successful\n", __FUNCTION__);
- return 0;
- }
- if (dst->rxbuffer[7] != dst_check_sum(dst->rxbuffer, 7)) {
- dprintk("%s: checksum failure\n", __FUNCTION__);
- return 0;
- }
- return 0;
-}
-
-static int dst_get_signal(struct dst_data *dst)
-{
- int retval;
- u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
-
- if ((dst->diseq_flags & ATTEMPT_TUNE) == 0) {
- dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
- return 0;
- }
- if (0 == (dst->diseq_flags & HAS_LOCK)) {
- dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
- return 0;
- }
- if (time_after_eq(jiffies, dst->cur_jiff + (HZ / 5))) {
- retval = dst_command(dst, get_signal, 8);
- if (retval < 0)
- return retval;
- if (dst->dst_type == DST_TYPE_IS_SAT) {
- dst->decode_lock = ((dst->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
- dst->decode_strength = dst->rxbuffer[5] << 8;
- dst->decode_snr = dst->rxbuffer[2] << 8 | dst->rxbuffer[3];
- } else if ((dst->dst_type == DST_TYPE_IS_TERR) || (dst->dst_type == DST_TYPE_IS_CABLE)) {
- dst->decode_lock = (dst->rxbuffer[1]) ? 1 : 0;
- dst->decode_strength = dst->rxbuffer[4] << 8;
- dst->decode_snr = dst->rxbuffer[3] << 8;
- }
- dst->cur_jiff = jiffies;
- }
- return 0;
-}
-
-/*
- * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
- * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
- * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
- * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
- * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
- * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
- * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
- * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
- * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8
- * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4
- * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0
- */
-
-static int dst_set_diseqc(struct dst_data *dst, u8 * cmd, u8 len)
-{
- u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
-
- if (dst->dst_type == DST_TYPE_IS_TERR)
- return 0;
-
- if (len == 0 || len > 4)
- return -EINVAL;
- memcpy(&paket[3], cmd, len);
- paket[7] = dst_check_sum(&paket[0], 7);
- dst_command(dst, paket, 8);
- return 0;
-}
-
-static int dst_tone_power_cmd(struct dst_data *dst)
-{
- u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
-
- if (dst->dst_type == DST_TYPE_IS_TERR)
- return 0;
-
- if (dst->voltage == SEC_VOLTAGE_OFF)
- paket[4] = 0;
- else
- paket[4] = 1;
- if (dst->tone == SEC_TONE_ON)
- paket[2] = dst->k22;
- else
- paket[2] = 0;
- paket[7] = dst_check_sum(&paket[0], 7);
- dst_command(dst, paket, 8);
- return 0;
-}
-
-static int dst_set_voltage(struct dst_data *dst, fe_sec_voltage_t voltage)
-{
- u8 *val;
- int need_cmd;
-
- dst->voltage = voltage;
-
- if (dst->dst_type == DST_TYPE_IS_TERR)
- return 0;
-
- need_cmd = 0;
- val = &dst->tx_tuna[0];
- val[8] &= ~0x40;
- switch (voltage) {
- case SEC_VOLTAGE_13:
- if ((dst->diseq_flags & HAS_POWER) == 0)
- need_cmd = 1;
- dst->diseq_flags |= HAS_POWER;
- break;
- case SEC_VOLTAGE_18:
- if ((dst->diseq_flags & HAS_POWER) == 0)
- need_cmd = 1;
- dst->diseq_flags |= HAS_POWER;
- val[8] |= 0x40;
- break;
- case SEC_VOLTAGE_OFF:
- need_cmd = 1;
- dst->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
- break;
- default:
- return -EINVAL;
- }
- if (need_cmd) {
- dst_tone_power_cmd(dst);
- }
- return 0;
-}
-
-
-static int dst_set_tone(struct dst_data *dst, fe_sec_tone_mode_t tone)
-{
- u8 *val;
-
- dst->tone = tone;
-
- if (dst->dst_type == DST_TYPE_IS_TERR)
- return 0;
-
- val = &dst->tx_tuna[0];
-
- val[8] &= ~0x1;
-
- switch (tone) {
- case SEC_TONE_OFF:
- break;
- case SEC_TONE_ON:
- val[8] |= 1;
- break;
- default:
- return -EINVAL;
- }
- dst_tone_power_cmd(dst);
- return 0;
-}
-
-static int dst_get_tuna(struct dst_data *dst)
-{
- int retval;
- if ((dst->diseq_flags & ATTEMPT_TUNE) == 0)
- return 0;
- dst->diseq_flags &= ~(HAS_LOCK);
- if (!dst_wait_dst_ready(dst))
- return 0;
- if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
- /* how to get variable length reply ???? */
- retval = read_dst(dst, dst->rx_tuna, 10);
- } else {
- retval = read_dst(dst, &dst->rx_tuna[2], 8);
- }
- if (retval < 0) {
- dprintk("%s: read not successful\n", __FUNCTION__);
- return 0;
- }
- if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
- if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[0], 9)) {
- dprintk("%s: checksum failure?\n", __FUNCTION__);
- return 0;
- }
- } else {
- if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[2], 7)) {
- dprintk("%s: checksum failure?\n", __FUNCTION__);
- return 0;
- }
- }
- if (dst->rx_tuna[2] == 0 && dst->rx_tuna[3] == 0)
- return 0;
- dst->decode_freq = ((dst->rx_tuna[2] & 0x7f) << 8) + dst->rx_tuna[3];
-
- dst->decode_lock = 1;
- /*
- dst->decode_n1 = (dst->rx_tuna[4] << 8) +
- (dst->rx_tuna[5]);
-
- dst->decode_n2 = (dst->rx_tuna[8] << 8) +
- (dst->rx_tuna[7]);
- */
- dst->diseq_flags |= HAS_LOCK;
- /* dst->cur_jiff = jiffies; */
- return 1;
-}
-
-static int dst_write_tuna(struct dst_data *dst)
-{
- int retval;
- u8 reply;
-
- dprintk("%s: type_flags 0x%x \n", __FUNCTION__, dst->type_flags);
- dst->decode_freq = 0;
- dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
- if (dst->dst_type == DST_TYPE_IS_SAT) {
- if (!(dst->diseq_flags & HAS_POWER))
- dst_set_voltage(dst, SEC_VOLTAGE_13);
- }
- dst->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
- dst_i2c_enable(dst);
- if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
- dst_reset8820(dst);
- dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[0], 9);
- retval = write_dst(dst, &dst->tx_tuna[0], 10);
- } else {
- dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[2], 7);
- retval = write_dst(dst, &dst->tx_tuna[2], 8);
- }
- if (retval < 0) {
- dst_i2c_disable(dst);
- dprintk("%s: write not successful\n", __FUNCTION__);
- return retval;
- }
- msleep(3);
- retval = read_dst(dst, &reply, 1);
- dst_i2c_disable(dst);
- if (retval < 0) {
- dprintk("%s: read verify not successful\n", __FUNCTION__);
- return retval;
- }
- if (reply != 0xff) {
- dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
- return 0;
- }
- dst->diseq_flags |= ATTEMPT_TUNE;
- return dst_get_tuna(dst);
-}
-
-static void dst_init(struct dst_data *dst)
-{
- static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
- static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
- static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
- static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
- static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
- static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
- dst->inversion = INVERSION_ON;
- dst->voltage = SEC_VOLTAGE_13;
- dst->tone = SEC_TONE_OFF;
- dst->symbol_rate = 29473000;
- dst->fec = FEC_AUTO;
- dst->diseq_flags = 0;
- dst->k22 = 0x02;
- dst->bandwidth = BANDWIDTH_7_MHZ;
- dst->cur_jiff = jiffies;
- if (dst->dst_type == DST_TYPE_IS_SAT) {
- dst->frequency = 950000;
- memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna));
- } else if (dst->dst_type == DST_TYPE_IS_TERR) {
- dst->frequency = 137000000;
- memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna));
- } else if (dst->dst_type == DST_TYPE_IS_CABLE) {
- dst->frequency = 51000000;
- memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna));
- }
-}
-
-struct lkup {
- unsigned int cmd;
- char *desc;
-} looker[] = {
- {
- FE_GET_INFO, "FE_GET_INFO:"}, {
- FE_READ_STATUS, "FE_READ_STATUS:"}, {
- FE_READ_BER, "FE_READ_BER:"}, {
- FE_READ_SIGNAL_STRENGTH, "FE_READ_SIGNAL_STRENGTH:"}, {
- FE_READ_SNR, "FE_READ_SNR:"}, {
- FE_READ_UNCORRECTED_BLOCKS, "FE_READ_UNCORRECTED_BLOCKS:"}, {
- FE_SET_FRONTEND, "FE_SET_FRONTEND:"}, {
- FE_GET_FRONTEND, "FE_GET_FRONTEND:"}, {
- FE_SLEEP, "FE_SLEEP:"}, {
- FE_INIT, "FE_INIT:"}, {
- FE_SET_TONE, "FE_SET_TONE:"}, {
-FE_SET_VOLTAGE, "FE_SET_VOLTAGE:"},};
-
-static int dst_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct dst_data *dst = fe->data;
- int retval;
- /*
- char *cc;
-
- cc = "FE_UNSUPP:";
- for(retval = 0; retval < sizeof(looker) / sizeof(looker[0]); retval++) {
- if (looker[retval].cmd == cmd) {
- cc = looker[retval].desc;
- break;
- }
- }
- dprintk("%s cmd %s (0x%x)\n",__FUNCTION__, cc, cmd);
- */
- // printk("%s: dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, dst, dst->bt, dst->i2c);
- /* should be set by attach, but just in case */
-
- switch (cmd) {
- case FE_GET_INFO:
- {
- struct dvb_frontend_info *info;
- info = &dst_info_sat;
- if (dst->dst_type == DST_TYPE_IS_TERR)
- info = &dst_info_terr;
- else if (dst->dst_type == DST_TYPE_IS_CABLE)
- info = &dst_info_cable;
- memcpy(arg, info, sizeof(struct dvb_frontend_info));
- break;
- }
- case FE_READ_STATUS:
- {
- fe_status_t *status = arg;
-
- *status = 0;
- if (dst->diseq_flags & HAS_LOCK) {
- dst_get_signal(dst);
- if (dst->decode_lock)
- *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
- }
- break;
- }
-
- case FE_READ_BER:
- {
- /* guess */
- // *(u32*) arg = dst->decode_n1;
- *(u32 *) arg = 0;
- return -EOPNOTSUPP;
- }
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- dst_get_signal(dst);
- *((u16 *) arg) = dst->decode_strength;
- break;
- }
-
- case FE_READ_SNR:
- {
- dst_get_signal(dst);
- *((u16 *) arg) = dst->decode_snr;
- break;
- }
-
- case FE_READ_UNCORRECTED_BLOCKS:
- {
- *((u32 *) arg) = 0; /* the stv0299 can't measure BER and */
- return -EOPNOTSUPP; /* errors at the same time.... */
- }
-
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
-
- dst_set_freq(dst, p->frequency);
- dst_set_inversion(dst, p->inversion);
- if (dst->dst_type == DST_TYPE_IS_SAT) {
- dst_set_fec(dst, p->u.qpsk.fec_inner);
- dst_set_symbolrate(dst, p->u.qpsk.symbol_rate);
- } else if (dst->dst_type == DST_TYPE_IS_TERR) {
- dst_set_bandwidth(dst, p->u.ofdm.bandwidth);
- } else if (dst->dst_type == DST_TYPE_IS_CABLE) {
- dst_set_fec(dst, p->u.qam.fec_inner);
- dst_set_symbolrate(dst, p->u.qam.symbol_rate);
- }
- dst_write_tuna(dst);
-
- break;
- }
-
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
-
-
- p->frequency = dst->decode_freq;
- p->inversion = dst->inversion;
- if (dst->dst_type == DST_TYPE_IS_SAT) {
- p->u.qpsk.symbol_rate = dst->symbol_rate;
- p->u.qpsk.fec_inner = dst_get_fec(dst);
- } else if (dst->dst_type == DST_TYPE_IS_TERR) {
- p->u.ofdm.bandwidth = dst->bandwidth;
- } else if (dst->dst_type == DST_TYPE_IS_CABLE) {
- p->u.qam.symbol_rate = dst->symbol_rate;
- p->u.qam.fec_inner = dst_get_fec(dst);
- p->u.qam.modulation = QAM_AUTO;
- }
- break;
- }
-
- case FE_SLEEP:
- return 0;
-
- case FE_INIT:
- dst_init(dst);
- break;
-
- case FE_DISEQC_SEND_MASTER_CMD:
- {
- struct dvb_diseqc_master_cmd *cmd = (struct dvb_diseqc_master_cmd *) arg;
- retval = dst_set_diseqc(dst, cmd->msg, cmd->msg_len);
- if (retval < 0)
- return retval;
- break;
- }
- case FE_SET_TONE:
- retval = dst_set_tone(dst, (fe_sec_tone_mode_t) arg);
- if (retval < 0)
- return retval;
- break;
- case FE_SET_VOLTAGE:
- retval = dst_set_voltage(dst, (fe_sec_voltage_t) arg);
- if (retval < 0)
- return retval;
- break;
- default:
- return -EOPNOTSUPP;
- };
-
- return 0;
-}
-
-static ssize_t attr_read_type(struct device *dev, char *buf)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
- return sprintf(buf, "0x%02x\n", dst->dst_type);
-}
-
-static ssize_t attr_write_type(struct device *dev, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
- unsigned long type;
- type = simple_strtoul(buf, NULL, 0);
- dst->dst_type = type & 0xff;
- return strlen(buf) + 1;
-}
-
-/* dst_type, "Type of DST card, 0 Satellite, 1 terrestial, 2 Cable, default driver determined"); */
-static struct device_attribute dev_attr_client_type = {
- .attr = {.name = "type",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE},
- .show = &attr_read_type,
- .store = &attr_write_type,
-};
-
-static ssize_t attr_read_flags(struct device *dev, char *buf)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
- return sprintf(buf, "0x%02x\n", dst->type_flags);
-}
-
-static ssize_t attr_write_flags(struct device *dev, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
- unsigned long flags;
- flags = simple_strtoul(buf, NULL, 0);
- dst->type_flags = flags & 0xffffffff;
- return strlen(buf) + 1;
-}
-
-/* dst_type_flags, "Type flags of DST card, bitfield 1=10 byte tuner, 2=TS is 204, 4=symdiv"); */
-static struct device_attribute dev_attr_client_flags = {
- .attr = {.name = "flags",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE},
- .show = &attr_read_flags,
- .store = &attr_write_flags,
-};
-
-static struct i2c_client client_template;
-
-static int attach_adapter(struct i2c_adapter *adapter)
-{
- struct i2c_client *client;
- struct dst_data *dst;
- struct bt878 *bt;
- struct dvb_frontend_info *info;
- int ret;
-
- bt = bt878_find_by_i2c_adap(adapter);
- if (!bt)
- return -ENODEV;
-
- dst = kmalloc(sizeof(struct dst_data), GFP_KERNEL);
- if (dst == NULL) {
- printk(KERN_INFO "%s: Out of memory.\n", __FUNCTION__);
- return -ENOMEM;
- }
-
- memset(dst, 0, sizeof(*dst));
- dst->bt = bt;
- dst->i2c = adapter;
- if (dst_check_ci(dst) < 0) {
- kfree(dst);
- return -ENODEV;
- }
- dst_init(dst);
-
- dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, (u32) dst, (u32) (dst->bt), (u32) (dst->i2c));
-
- switch (dst->dst_type) {
- case DST_TYPE_IS_TERR:
- info = &dst_info_terr;
- break;
- case DST_TYPE_IS_CABLE:
- info = &dst_info_cable;
- break;
- case DST_TYPE_IS_SAT:
- info = &dst_info_sat;
- break;
- default:
- printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n");
- kfree(dst);
- return -ENODEV;
- }
-
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- kfree(dst);
- return -ENOMEM;
- }
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = DST_I2C_ADDR;
-
- i2c_set_clientdata(client, (void *) dst);
-
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(client);
- kfree(dst);
- return -EFAULT;
- }
-
- BUG_ON(!dst->dvb);
-
- device_create_file(&client->dev, &dev_attr_client_type);
- device_create_file(&client->dev, &dev_attr_client_flags);
-
- ret = dvb_register_frontend(dst_ioctl, dst->dvb, dst, info, THIS_MODULE);
- if (ret) {
- i2c_detach_client(client);
- kfree(client);
- kfree(dst);
- return -EFAULT;
- }
-
- return 0;
-}
-
-static int detach_client(struct i2c_client *client)
-{
- struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
-
- dvb_unregister_frontend(dst_ioctl, state->dvb);
-
- device_remove_file(&client->dev, &dev_attr_client_type);
- device_remove_file(&client->dev, &dev_attr_client_flags);
-
- i2c_detach_client(client);
- BUG_ON(state->dvb);
-
- kfree(client);
- kfree(state);
-
- return 0;
-}
-
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
-
- switch (cmd) {
- case FE_REGISTER:
- state->dvb = (struct dvb_adapter *) arg;
- break;
- case FE_UNREGISTER:
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = "dst",
- .id = I2C_DRIVERID_DVBFE_DST,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
-
-static struct i2c_client client_template = {
- I2C_DEVNAME("dst"),
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
-
-static int __init init_dst(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit exit_dst(void)
-{
- if (i2c_del_driver(&driver))
- printk("dst: driver deregistration failed\n");
-}
-
-module_init(init_dst);
-module_exit(exit_dst);
-
-MODULE_DESCRIPTION("DST DVB-S Frontend");
-MODULE_AUTHOR("Jamie Honan");
-MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c b/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 977f20823..8e94d99f3 100644
--- a/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -1,5 +1,5 @@
-/*
- * Driver for Dummy Frontend
+/*
+ * Driver for Dummy Frontend
*
* Written by Emard <emard@softhome.net>
*
@@ -17,250 +17,265 @@
* 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/moduleparam.h>
#include <linux/init.h>
#include "dvb_frontend.h"
+#include "dvb_dummy_fe.h"
-#define FRONTEND_NAME "dvbfe_dummy"
-static int frontend_type;
-module_param(frontend_type, int, 0444);
-MODULE_PARM_DESC(frontend_type, "0 == DVB-S, 1 == DVB-C, 2 == DVB-T");
-/* depending on module parameter sct deliver different infos
- */
+struct dvb_dummy_fe_state {
-static struct dvb_frontend_info dvb_s_dummyfe_info = {
- .name = "DVB-S dummy frontend",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = 250, /* kHz for QPSK frontends */
- .frequency_tolerance = 29500,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
-/* .symbol_rate_tolerance = ???,*/
- .notifier_delay = 50, /* 1/20 s */
- .caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK
-};
+ struct dvb_frontend_ops ops;
-static struct dvb_frontend_info dvb_c_dummyfe_info = {
- .name = "DVB-C dummy frontend",
- .type = FE_QAM,
- .frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
- .symbol_rate_min = (57840000/2)/64, /* SACLK/64 == (XIN/2)/64 */
- .symbol_rate_max = (57840000/2)/4, /* SACLK/4 */
-#if 0
- .frequency_tolerance = ???,
- .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
- .notifier_delay = ?,
-#endif
- .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
- FE_CAN_QAM_128 | FE_CAN_QAM_256 |
- FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO
+ struct dvb_frontend frontend;
};
-static struct dvb_frontend_info dvb_t_dummyfe_info = {
- .name = "DVB-T dummy frontend",
- .type = FE_OFDM,
- .frequency_min = 0,
- .frequency_max = 863250000,
- .frequency_stepsize = 62500,
- /*.frequency_tolerance = */ /* FIXME: 12% of SR */
- .symbol_rate_min = 0, /* FIXME */
- .symbol_rate_max = 9360000, /* FIXME */
- .symbol_rate_tolerance = 4000,
- .notifier_delay = 0,
- .caps = 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_8_9 | FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO,
-};
+static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ *status = FE_HAS_SIGNAL
+ | FE_HAS_CARRIER
+ | FE_HAS_VITERBI
+ | FE_HAS_SYNC
+ | FE_HAS_LOCK;
+
+ return 0;
+}
-struct dvb_frontend_info *frontend_info(void)
+static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber)
{
- switch(frontend_type) {
- case 2:
- return &dvb_t_dummyfe_info;
- case 1:
- return &dvb_c_dummyfe_info;
- case 0:
- default:
- return &dvb_s_dummyfe_info;
- }
+ *ber = 0;
+ return 0;
}
+static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ *strength = 0;
+ return 0;
+}
-static int dvbdummyfe_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr)
{
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, frontend_info(),
- sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = arg;
- *status = FE_HAS_SIGNAL
- | FE_HAS_CARRIER
- | FE_HAS_VITERBI
- | FE_HAS_SYNC
- | FE_HAS_LOCK;
- break;
- }
-
- case FE_READ_BER:
- {
- u32 *ber = (u32 *) arg;
- *ber = 0;
- break;
- }
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- u8 signal = 0xff;
- *((u16*) arg) = (signal << 8) | signal;
- break;
- }
-
- case FE_READ_SNR:
- {
- u8 snr = 0xf0;
- *(u16*) arg = (snr << 8) | snr;
- break;
- }
-
- case FE_READ_UNCORRECTED_BLOCKS:
- *(u32*) arg = 0;
- break;
-
- case FE_SET_FRONTEND:
- break;
-
- case FE_GET_FRONTEND:
- break;
-
- case FE_SLEEP:
- return 0;
-
- case FE_INIT:
- return 0;
-
- case FE_SET_TONE:
- return -EOPNOTSUPP;
-
- case FE_SET_VOLTAGE:
- return 0;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-static struct i2c_client client_template;
-
-static int dvbdummyfe_attach_adapter(struct i2c_adapter *adapter)
+ *snr = 0;
+ return 0;
+}
+
+static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
- struct dvb_adapter *dvb;
- struct i2c_client *client;
- int ret;
+ *ucblocks = 0;
+ return 0;
+}
- if ((client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL)
- return -ENOMEM;
+static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ return 0;
+}
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
+static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ return 0;
+}
- if ((ret = i2c_attach_client(client))) {
- kfree(client);
- return ret;
- }
+static int dvb_dummy_fe_sleep(struct dvb_frontend* fe)
+{
+ return 0;
+}
- dvb = i2c_get_clientdata(client);
- BUG_ON(!dvb);
+static int dvb_dummy_fe_init(struct dvb_frontend* fe)
+{
+ return 0;
+}
- if ((ret = dvb_register_frontend(dvbdummyfe_ioctl, dvb, NULL,
- frontend_info(), THIS_MODULE))) {
- kfree(client);
- return ret;
- }
+static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ return 0;
+}
+static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
return 0;
}
+static void dvb_dummy_fe_release(struct dvb_frontend* fe)
+{
+ struct dvb_dummy_fe_state* state = (struct dvb_dummy_fe_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops;
-static int dvbdummyfe_detach_client(struct i2c_client *client)
+struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
{
- struct dvb_adapter *dvb = i2c_get_clientdata(client);
+ struct dvb_dummy_fe_state* state = NULL;
- dvb_unregister_frontend(dvbdummyfe_ioctl, dvb);
- i2c_detach_client(client);
- kfree(client);
- return 0;
+ /* allocate memory for the internal state */
+ state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
}
-static int dvbdummyfe_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops;
+
+struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
{
- switch(cmd) {
- case FE_REGISTER:
- i2c_set_clientdata(client, arg);
- break;
- case FE_UNREGISTER:
- break;
- default:
- return -EOPNOTSUPP;
- }
+ struct dvb_dummy_fe_state* state = NULL;
- return 0;
-}
+ /* allocate memory for the internal state */
+ state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+ if (state == NULL) goto error;
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_DUMMY,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = dvbdummyfe_attach_adapter,
- .detach_client = dvbdummyfe_detach_client,
- .command = dvbdummyfe_command,
-};
+ /* setup the state */
+ memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
-static int __init init_dvbdummyfe (void)
-{
- return i2c_add_driver(&driver);
+error:
+ if (state) kfree(state);
+ return NULL;
}
-static void __exit exit_dvbdummyfe (void)
+static struct dvb_frontend_ops dvb_dummy_fe_qam_ops;
+
+struct dvb_frontend* dvb_dummy_fe_qam_attach()
{
- if (i2c_del_driver(&driver))
- printk(KERN_ERR "dummyfe: driver deregistration failed.\n");
+ struct dvb_dummy_fe_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
}
+static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = {
+
+ .info = {
+ .name = "Dummy DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 0,
+ .frequency_max = 863250000,
+ .frequency_stepsize = 62500,
+ .caps = 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_8_9 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = dvb_dummy_fe_release,
+
+ .init = dvb_dummy_fe_init,
+ .sleep = dvb_dummy_fe_sleep,
+
+ .set_frontend = dvb_dummy_fe_set_frontend,
+ .get_frontend = dvb_dummy_fe_get_frontend,
+
+ .read_status = dvb_dummy_fe_read_status,
+ .read_ber = dvb_dummy_fe_read_ber,
+ .read_signal_strength = dvb_dummy_fe_read_signal_strength,
+ .read_snr = dvb_dummy_fe_read_snr,
+ .read_ucblocks = dvb_dummy_fe_read_ucblocks,
+};
+
+static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = {
+
+ .info = {
+ .name = "Dummy DVB-C",
+ .type = FE_QAM,
+ .frequency_stepsize = 62500,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .symbol_rate_min = (57840000/2)/64, /* SACLK/64 == (XIN/2)/64 */
+ .symbol_rate_max = (57840000/2)/4, /* SACLK/4 */
+ .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+ FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO
+ },
+
+ .release = dvb_dummy_fe_release,
+
+ .init = dvb_dummy_fe_init,
+ .sleep = dvb_dummy_fe_sleep,
+
+ .set_frontend = dvb_dummy_fe_set_frontend,
+ .get_frontend = dvb_dummy_fe_get_frontend,
+
+ .read_status = dvb_dummy_fe_read_status,
+ .read_ber = dvb_dummy_fe_read_ber,
+ .read_signal_strength = dvb_dummy_fe_read_signal_strength,
+ .read_snr = dvb_dummy_fe_read_snr,
+ .read_ucblocks = dvb_dummy_fe_read_ucblocks,
+};
-module_init(init_dvbdummyfe);
-module_exit(exit_dvbdummyfe);
+static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = {
+
+ .info = {
+ .name = "Dummy DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 250, /* kHz for QPSK frontends */
+ .frequency_tolerance = 29500,
+ .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_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK
+ },
+
+ .release = dvb_dummy_fe_release,
+
+ .init = dvb_dummy_fe_init,
+ .sleep = dvb_dummy_fe_sleep,
+
+ .set_frontend = dvb_dummy_fe_set_frontend,
+ .get_frontend = dvb_dummy_fe_get_frontend,
+
+ .read_status = dvb_dummy_fe_read_status,
+ .read_ber = dvb_dummy_fe_read_ber,
+ .read_signal_strength = dvb_dummy_fe_read_signal_strength,
+ .read_snr = dvb_dummy_fe_read_snr,
+ .read_ucblocks = dvb_dummy_fe_read_ucblocks,
+
+ .set_voltage = dvb_dummy_fe_set_voltage,
+ .set_tone = dvb_dummy_fe_set_tone,
+};
MODULE_DESCRIPTION("DVB DUMMY Frontend");
MODULE_AUTHOR("Emard");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach);
+EXPORT_SYMBOL(dvb_dummy_fe_qam_attach);
+EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach);
diff --git a/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h b/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h
new file mode 100644
index 000000000..8210f19d5
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h
@@ -0,0 +1,32 @@
+/*
+ * Driver for Dummy Frontend
+ *
+ * Written by Emard <emard@softhome.net>
+ *
+ * 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 DVB_DUMMY_FE_H
+#define DVB_DUMMY_FE_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void);
+extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void);
+extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void);
+
+#endif // DVB_DUMMY_FE_H
diff --git a/linux/drivers/media/dvb/frontends/grundig_29504-401.c b/linux/drivers/media/dvb/frontends/grundig_29504-401.c
deleted file mode 100644
index 731dea0b4..000000000
--- a/linux/drivers/media/dvb/frontends/grundig_29504-401.c
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- driver for Grundig 29504-401 DVB-T Frontends based on
- LSI L64781 COFDM demodulator as used in Technotrend DVB-T cards
-
- Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
- for Convergence Integrated Media GmbH
- Marko Kohtala <marko.kohtala@luukku.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/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#define FRONTEND_NAME "dvbfe_l64781"
-
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
-
-static int debug;
-static int old_set_tv_freq;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-module_param(old_set_tv_freq, int, 0644);
-MODULE_PARM_DESC(old_set_tv_freq, "Use old tsa5060_set_tv_freq calculations.");
-
-struct l64781_state {
- int first:1;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
-};
-
-struct dvb_frontend_info l64781_info = {
- .name = "Grundig 29504-401 (LSI L64781 Based)",
- .type = FE_OFDM,
-/* .frequency_min = ???,*/
-/* .frequency_max = ???,*/
- .frequency_stepsize = 166666,
-/* .frequency_tolerance = ???,*/
-/* .symbol_rate_tolerance = ???,*/
- .notifier_delay = 0,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
- FE_CAN_MUTE_TS
-};
-
-
-static int l64781_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
-{
- int ret;
- u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = 0x55, .flags = 0, .buf = buf, .len = 2 };
-
- if ((ret = i2c_transfer(i2c, &msg, 1)) != 1)
- dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
- __FUNCTION__, reg, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-
-static u8 l64781_readreg (struct i2c_adapter *i2c, u8 reg)
-{
- int ret;
- u8 b0 [] = { reg };
- u8 b1 [] = { 0 };
- struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
- { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
- ret = i2c_transfer(i2c, msg, 2);
-
- if (ret != 2)
- dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
- return b1[0];
-}
-
-
-static int tsa5060_write (struct i2c_adapter *i2c, u8 data [4])
-{
- int ret;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 };
-
- if ((ret = i2c_transfer(i2c, &msg, 1)) != 1)
- dprintk ("%s: write_reg error == %02x!\n", __FUNCTION__, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-
-/**
- * set up the downconverter frequency divisor for a
- * reference clock comparision frequency of 166666 Hz.
- * frequency offset is 36125000 Hz.
- */
-static int tsa5060_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
-{
- u32 div;
- u8 buf [4];
- u8 cfg, cpump, band_select;
-
- if (old_set_tv_freq)
- div = (36000000 + freq) / 166666;
- else
- div = (36125000 + freq) / 166666;
-
- cfg = 0x88;
-
- cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 :
- freq < 470000000 ? 2 : freq < 750000000 ? 1 : 3;
-
- band_select = freq < 175000000 ? 0x0e : freq < 470000000 ? 0x05 : 0x03;
-
- buf [0] = (div >> 8) & 0x7f;
- buf [1] = div & 0xff;
- buf [2] = ((div >> 10) & 0x60) | cfg;
-
- if (old_set_tv_freq)
- buf [3] = 0xc0;
- else
- buf [3] = (cpump << 6) | band_select;
-
- return tsa5060_write(i2c, buf);
-}
-
-
-
-static void apply_tps (struct i2c_adapter *i2c)
-{
- l64781_writereg (i2c, 0x2a, 0x00);
- l64781_writereg (i2c, 0x2a, 0x01);
-
- /* This here is a little bit questionable because it enables
- the automatic update of TPS registers. I think we'd need to
- handle the IRQ from FE to update some other registers as
- well, or at least implement some magic to tuning to correct
- to the TPS received from transmission. */
- l64781_writereg (i2c, 0x2a, 0x02);
-}
-
-
-static void reset_afc (struct i2c_adapter *i2c)
-{
- /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for
- timing offset */
- l64781_writereg (i2c, 0x07, 0x9e); /* stall AFC */
- l64781_writereg (i2c, 0x08, 0); /* AFC INIT FREQ */
- l64781_writereg (i2c, 0x09, 0);
- l64781_writereg (i2c, 0x0a, 0);
- l64781_writereg (i2c, 0x07, 0x8e);
- l64781_writereg (i2c, 0x0e, 0); /* AGC gain to zero in beginning */
- l64781_writereg (i2c, 0x11, 0x80); /* stall TIM */
- l64781_writereg (i2c, 0x10, 0); /* TIM_OFFSET_LSB */
- l64781_writereg (i2c, 0x12, 0);
- l64781_writereg (i2c, 0x13, 0);
- l64781_writereg (i2c, 0x11, 0x00);
-}
-
-
-static int apply_frontend_param (struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *param)
-{
- /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
- static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
- /* QPSK, QAM_16, QAM_64 */
- static const u8 qam_tab [] = { 2, 4, 0, 6 };
- static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */
- static const u8 guard_tab [] = { 1, 2, 4, 8 };
- /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
- static const u32 ppm = 8000;
- struct dvb_ofdm_parameters *p = &param->u.ofdm;
- u32 ddfs_offset_fixed;
-/* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
-/* bw_tab[p->bandWidth]<<10)/15625; */
- u32 init_freq;
- u32 spi_bias;
- u8 val0x04;
- u8 val0x05;
- u8 val0x06;
- int bw = p->bandwidth - BANDWIDTH_8_MHZ;
-
- if (param->inversion != INVERSION_ON &&
- param->inversion != INVERSION_OFF)
- return -EINVAL;
-
- if (bw < 0 || bw > 2)
- return -EINVAL;
-
- if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
- p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 &&
- p->code_rate_HP != FEC_7_8)
- return -EINVAL;
-
- if (p->hierarchy_information != HIERARCHY_NONE &&
- (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
- p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
- p->code_rate_LP != FEC_7_8))
- return -EINVAL;
-
- if (p->constellation != QPSK && p->constellation != QAM_16 &&
- p->constellation != QAM_64)
- return -EINVAL;
-
- if (p->transmission_mode != TRANSMISSION_MODE_2K &&
- p->transmission_mode != TRANSMISSION_MODE_8K)
- return -EINVAL;
-
- if (p->guard_interval < GUARD_INTERVAL_1_32 ||
- p->guard_interval > GUARD_INTERVAL_1_4)
- return -EINVAL;
-
- if (p->hierarchy_information < HIERARCHY_NONE ||
- p->hierarchy_information > HIERARCHY_4)
- return -EINVAL;
-
- ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000;
-
- /* This works up to 20000 ppm, it overflows if too large ppm! */
- init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
- bw_tab[p->bandwidth] & 0xFFFFFF);
-
- /* SPI bias calculation is slightly modified to fit in 32bit */
- /* will work for high ppm only... */
- spi_bias = 378 * (1 << 10);
- spi_bias *= 16;
- spi_bias *= bw_tab[p->bandwidth];
- spi_bias *= qam_tab[p->constellation];
- spi_bias /= p->code_rate_HP + 1;
- spi_bias /= (guard_tab[p->guard_interval] + 32);
- spi_bias *= 1000ULL;
- spi_bias /= 1000ULL + ppm/1000;
- spi_bias *= p->code_rate_HP;
-
- val0x04 = (p->transmission_mode << 2) | p->guard_interval;
- val0x05 = fec_tab[p->code_rate_HP];
-
- if (p->hierarchy_information != HIERARCHY_NONE)
- val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
-
- val0x06 = (p->hierarchy_information << 2) | p->constellation;
-
- l64781_writereg (i2c, 0x04, val0x04);
- l64781_writereg (i2c, 0x05, val0x05);
- l64781_writereg (i2c, 0x06, val0x06);
-
- reset_afc (i2c);
-
- /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */
- l64781_writereg (i2c, 0x15,
- p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3);
- l64781_writereg (i2c, 0x16, init_freq & 0xff);
- l64781_writereg (i2c, 0x17, (init_freq >> 8) & 0xff);
- l64781_writereg (i2c, 0x18, (init_freq >> 16) & 0xff);
-
- l64781_writereg (i2c, 0x1b, spi_bias & 0xff);
- l64781_writereg (i2c, 0x1c, (spi_bias >> 8) & 0xff);
- l64781_writereg (i2c, 0x1d, ((spi_bias >> 16) & 0x7f) |
- (param->inversion == INVERSION_ON ? 0x80 : 0x00));
-
- l64781_writereg (i2c, 0x22, ddfs_offset_fixed & 0xff);
- l64781_writereg (i2c, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
-
- l64781_readreg (i2c, 0x00); /* clear interrupt registers... */
- l64781_readreg (i2c, 0x01); /* dto. */
-
- apply_tps (i2c);
-
- return 0;
-}
-
-
-static int reset_and_configure (struct i2c_adapter *i2c)
-{
- u8 buf [] = { 0x06 };
- struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };
-
- return (i2c_transfer(i2c, &msg, 1) == 1) ? 0 : -ENODEV;
-}
-
-
-static int get_frontend(struct i2c_adapter* i2c, struct dvb_frontend_parameters* param)
-{
- int tmp;
-
-
- tmp = l64781_readreg(i2c, 0x04);
- switch(tmp & 3) {
- case 0:
- param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
- break;
- case 1:
- param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
- break;
- case 2:
- param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
- break;
- case 3:
- param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
- break;
- }
- switch((tmp >> 2) & 3) {
- case 0:
- param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
- break;
- case 1:
- param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
- break;
- default:
- printk("Unexpected value for transmission_mode\n");
- }
-
-
-
- tmp = l64781_readreg(i2c, 0x05);
- switch(tmp & 7) {
- case 0:
- param->u.ofdm.code_rate_HP = FEC_1_2;
- break;
- case 1:
- param->u.ofdm.code_rate_HP = FEC_2_3;
- break;
- case 2:
- param->u.ofdm.code_rate_HP = FEC_3_4;
- break;
- case 3:
- param->u.ofdm.code_rate_HP = FEC_5_6;
- break;
- case 4:
- param->u.ofdm.code_rate_HP = FEC_7_8;
- break;
- default:
- printk("Unexpected value for code_rate_HP\n");
- }
- switch((tmp >> 3) & 7) {
- case 0:
- param->u.ofdm.code_rate_LP = FEC_1_2;
- break;
- case 1:
- param->u.ofdm.code_rate_LP = FEC_2_3;
- break;
- case 2:
- param->u.ofdm.code_rate_LP = FEC_3_4;
- break;
- case 3:
- param->u.ofdm.code_rate_LP = FEC_5_6;
- break;
- case 4:
- param->u.ofdm.code_rate_LP = FEC_7_8;
- break;
- default:
- printk("Unexpected value for code_rate_LP\n");
- }
-
-
- tmp = l64781_readreg(i2c, 0x06);
- switch(tmp & 3) {
- case 0:
- param->u.ofdm.constellation = QPSK;
- break;
- case 1:
- param->u.ofdm.constellation = QAM_16;
- break;
- case 2:
- param->u.ofdm.constellation = QAM_64;
- break;
- default:
- printk("Unexpected value for constellation\n");
- }
- switch((tmp >> 2) & 7) {
- case 0:
- param->u.ofdm.hierarchy_information = HIERARCHY_NONE;
- break;
- case 1:
- param->u.ofdm.hierarchy_information = HIERARCHY_1;
- break;
- case 2:
- param->u.ofdm.hierarchy_information = HIERARCHY_2;
- break;
- case 3:
- param->u.ofdm.hierarchy_information = HIERARCHY_4;
- break;
- default:
- printk("Unexpected value for hierarchy\n");
- }
-
-
- tmp = l64781_readreg (i2c, 0x1d);
- param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
-
- tmp = (int) (l64781_readreg (i2c, 0x08) |
- (l64781_readreg (i2c, 0x09) << 8) |
- (l64781_readreg (i2c, 0x0a) << 16));
- param->frequency += tmp;
-
- return 0;
-}
-
-
-static int init (struct i2c_adapter *i2c)
-{
- reset_and_configure (i2c);
-
- /* Power up */
- l64781_writereg (i2c, 0x3e, 0xa5);
-
- /* Reset hard */
- l64781_writereg (i2c, 0x2a, 0x04);
- l64781_writereg (i2c, 0x2a, 0x00);
-
- /* Set tuner specific things */
- /* AFC_POL, set also in reset_afc */
- l64781_writereg (i2c, 0x07, 0x8e);
-
- /* Use internal ADC */
- l64781_writereg (i2c, 0x0b, 0x81);
-
- /* AGC loop gain, and polarity is positive */
- l64781_writereg (i2c, 0x0c, 0x84);
-
- /* Internal ADC outputs two's complement */
- l64781_writereg (i2c, 0x0d, 0x8c);
-
- /* With ppm=8000, it seems the DTR_SENSITIVITY will result in
- value of 2 with all possible bandwidths and guard
- intervals, which is the initial value anyway. */
- /*l64781_writereg (i2c, 0x19, 0x92);*/
-
- /* Everything is two's complement, soft bit and CSI_OUT too */
- l64781_writereg (i2c, 0x1e, 0x09);
-
- return 0;
-}
-
-
-static
-int l64781_ioctl (struct dvb_frontend *fe,
- unsigned int cmd, void *arg)
-{
- struct l64781_state* state = fe->data;
- struct i2c_adapter *i2c = state->i2c;
- int res;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, &l64781_info,
- sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = (fe_status_t *) arg;
- int sync = l64781_readreg (i2c, 0x32);
- int gain = l64781_readreg (i2c, 0x0e);
-
- l64781_readreg (i2c, 0x00); /* clear interrupt registers... */
- l64781_readreg (i2c, 0x01); /* dto. */
-
- *status = 0;
-
- if (gain > 5)
- *status |= FE_HAS_SIGNAL;
-
- if (sync & 0x02) /* VCXO locked, this criteria should be ok */
- *status |= FE_HAS_CARRIER;
-
- if (sync & 0x20)
- *status |= FE_HAS_VITERBI;
-
- if (sync & 0x40)
- *status |= FE_HAS_SYNC;
-
- if (sync == 0x7f)
- *status |= FE_HAS_LOCK;
-
- break;
- }
-
- case FE_READ_BER:
- {
- /* XXX FIXME: set up counting period (reg 0x26...0x28)
- */
- u32 *ber = (u32 *) arg;
- *ber = l64781_readreg (i2c, 0x39)
- | (l64781_readreg (i2c, 0x3a) << 8);
- break;
- }
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- u8 gain = l64781_readreg (i2c, 0x0e);
- *(u16 *) arg = (gain << 8) | gain;
- break;
- }
-
- case FE_READ_SNR:
- {
- u16 *snr = (u16 *) arg;
- u8 avg_quality = 0xff - l64781_readreg (i2c, 0x33);
- *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/
- break;
- }
-
- case FE_READ_UNCORRECTED_BLOCKS:
- {
- u32 *ub = (u32 *) arg;
- *ub = l64781_readreg (i2c, 0x37)
- | (l64781_readreg (i2c, 0x38) << 8);
- break;
- }
-
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
-
- tsa5060_set_tv_freq (i2c, p->frequency);
- return apply_frontend_param (i2c, p);
- }
-
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- return get_frontend(i2c, p);
- }
-
- case FE_SLEEP:
- /* Power down */
- return l64781_writereg (i2c, 0x3e, 0x5a);
-
- case FE_INIT:
- res = init (i2c);
- if ((res == 0) && (state->first)) {
- state->first = 0;
- msleep(200);
- }
- return res;
-
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
- fesettings->min_delay_ms = 200;
- fesettings->step_size = 166667;
- fesettings->max_drift = 166667*2;
- return 0;
- }
-
- default:
- dprintk ("%s: unknown command !!!\n", __FUNCTION__);
- return -EINVAL;
- };
-
- return 0;
-}
-
-static int l64781_probe(struct i2c_adapter *i2c)
-{
- u8 reg0x3e;
- u8 b0 [] = { 0x1a };
- u8 b1 [] = { 0x00 };
- struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
- { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
-
- /**
- * the L64781 won't show up before we send the reset_and_configure()
- * broadcast. If nothing responds there is no L64781 on the bus...
- */
- if (reset_and_configure(i2c) < 0) {
- dprintk("No response to reset and configure broadcast...\n");
- return -ENODEV;
- }
-
- /* The chip always responds to reads */
- if (i2c_transfer(i2c, msg, 2) != 2) {
- dprintk("No response to read on I2C bus\n");
- return -ENODEV;
- }
-
- /* Save current register contents for bailout */
- reg0x3e = l64781_readreg(i2c, 0x3e);
-
- /* Reading the POWER_DOWN register always returns 0 */
- if (reg0x3e != 0) {
- dprintk("Device doesn't look like L64781\n");
- return -ENODEV;
- }
-
- /* Turn the chip off */
- l64781_writereg (i2c, 0x3e, 0x5a);
-
- /* Responds to all reads with 0 */
- if (l64781_readreg(i2c, 0x1a) != 0) {
- dprintk("Read 1 returned unexpcted value\n");
- goto out;
- }
-
- /* Turn the chip on */
- l64781_writereg (i2c, 0x3e, 0xa5);
-
- /* Responds with register default value */
- if (l64781_readreg(i2c, 0x1a) != 0xa1) {
- dprintk("Read 2 returned unexpcted value\n");
- goto out;
- }
-
- return 0;
-out:
- l64781_writereg (i2c, 0x3e, reg0x3e); /* restore reg 0x3e */
- return -ENODEV;
-}
-
-static struct i2c_client client_template;
-
-static int l64781_attach_adapter(struct i2c_adapter *adapter)
-{
- struct l64781_state *state;
- struct i2c_client *client;
- int ret;
-
- dprintk("Trying to attach to adapter 0x%x:%s.\n",
- adapter->id, adapter->name);
-
- if ((ret = l64781_probe(adapter)))
- return ret;
-
- if ( !(state = kmalloc(sizeof(struct l64781_state), GFP_KERNEL)) )
- return -ENOMEM;
-
- memset(state, 0, sizeof(struct l64781_state));
- state->i2c = adapter;
- state->first = 1;
-
- if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
- kfree(state);
- return -ENOMEM;
- }
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = 0; //XXX
- i2c_set_clientdata(client, state);
-
- if ((ret = i2c_attach_client(client))) {
- kfree(state);
- kfree(client);
- return ret;
- }
-
- BUG_ON(!state->dvb);
-
- if ((ret = dvb_register_frontend(l64781_ioctl, state->dvb, state,
- &l64781_info, THIS_MODULE))) {
- i2c_detach_client(client);
- kfree(state);
- kfree(client);
- return ret;
- }
-
- return 0;
-}
-
-static int l64781_detach_client(struct i2c_client *client)
-{
- struct l64781_state *state = i2c_get_clientdata(client);
-
- dvb_unregister_frontend(l64781_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
- return 0;
-}
-
-static int l64781_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
-{
- struct l64781_state *data = i2c_get_clientdata(client);
- dprintk ("%s\n", __FUNCTION__);
-
- switch (cmd) {
- case FE_REGISTER: {
- data->dvb = arg;
- break;
- }
- case FE_UNREGISTER: {
- data->dvb = NULL;
- break;
- }
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_L64781,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = l64781_attach_adapter,
- .detach_client = l64781_detach_client,
- .command = l64781_command,
-};
-
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
-
-static int __init init_l64781 (void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit exit_l64781 (void)
-{
- if (i2c_del_driver(&driver))
- printk(KERN_ERR "l64781: driver deregistration failed\n");
-}
-
-module_init(init_l64781);
-module_exit(exit_l64781);
-
-MODULE_DESCRIPTION("Grundig 29504-401 DVB-T Frontend (LSI L64781 Based)");
-MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
-MODULE_LICENSE("GPL");
-
diff --git a/linux/drivers/media/dvb/frontends/grundig_29504-491.c b/linux/drivers/media/dvb/frontends/grundig_29504-491.c
deleted file mode 100644
index 53ea55bea..000000000
--- a/linux/drivers/media/dvb/frontends/grundig_29504-491.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend
-
- Copyright (C) 2001 Convergence Integrated Media GmbH
-
- written by Ralph Metzler <ralph@convergence.de>
-
- adoption to the new DVB frontend API and diagnostic ioctl's
- by Holger Waechtler <holger@convergence.de>
-
- 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/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dvb_frontend.h"
-
-#define FRONTEND_NAME "dvbfe_tda8083"
-
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
-
-struct tda8083_state {
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
-};
-
-static struct dvb_frontend_info tda8083_info = {
- .name = "Grundig 29504-491, (TDA8083 based)",
- .type = FE_QPSK,
- .frequency_min = 950000, /* FIXME: guessed! */
- .frequency_max = 1400000, /* FIXME: guessed! */
- .frequency_stepsize = 125, /* kHz for QPSK frontends */
-/* .frequency_tolerance = ???,*/
- .symbol_rate_min = 1000000, /* FIXME: guessed! */
- .symbol_rate_max = 45000000, /* FIXME: guessed! */
-/* .symbol_rate_tolerance = ???,*/
- .notifier_delay = 0,
- .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_8_9 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_MUTE_TS
-};
-
-static u8 tda8083_init_tab [] = {
- 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea,
- 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10,
- 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8,
- 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00,
- 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
-};
-
-
-static int tda8083_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
-{
- int ret;
- u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 };
-
- ret = i2c_transfer(i2c, &msg, 1);
-
- if (ret != 1)
- dprintk ("%s: writereg error (reg %02x, ret == %i)\n",
- __FUNCTION__, reg, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-
-static int tda8083_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len)
-{
- int ret;
- struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = &reg1, .len = 1 },
- { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } };
-
- ret = i2c_transfer(i2c, msg, 2);
-
- if (ret != 2)
- dprintk ("%s: readreg error (reg %02x, ret == %i)\n",
- __FUNCTION__, reg1, ret);
-
- return ret == 2 ? 0 : -1;
-}
-
-
-static inline u8 tda8083_readreg (struct i2c_adapter *i2c, u8 reg)
-{
- u8 val;
-
- tda8083_readregs (i2c, reg, &val, 1);
-
- return val;
-}
-
-
-static int tsa5522_write (struct i2c_adapter *i2c, u8 data [4])
-{
- int ret;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 };
-
- ret = i2c_transfer(i2c, &msg, 1);
-
- if (ret != 1)
- dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-
-/**
- * set up the downconverter frequency divisor for a
- * reference clock comparision frequency of 125 kHz.
- */
-static int tsa5522_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
-{
- u32 div = freq / 125;
- u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x8e, 0x00 };
-
- return tsa5522_write (i2c, buf);
-}
-
-
-static int tda8083_init (struct i2c_adapter *i2c)
-{
- int i;
-
- dprintk("%s: init TDA8083\n", __FILE__);
-
- for (i=0; i<44; i++)
- tda8083_writereg (i2c, i, tda8083_init_tab[i]);
-
- return 0;
-}
-
-
-static int tda8083_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion_t inversion)
-{
- /* XXX FIXME: implement other modes than FEC_AUTO */
- if (inversion == INVERSION_AUTO)
- return 0;
-
- return -EINVAL;
-}
-
-
-static int tda8083_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec)
-{
- if (fec == FEC_AUTO)
- return tda8083_writereg (i2c, 0x07, 0xff);
-
- if (fec >= FEC_1_2 && fec <= FEC_8_9)
- return tda8083_writereg (i2c, 0x07, 1 << (FEC_8_9 - fec));
-
- return -EINVAL;
-}
-
-
-static fe_code_rate_t tda8083_get_fec (struct i2c_adapter *i2c)
-{
- u8 index;
- static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
- FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 };
-
- index = tda8083_readreg(i2c, 0x0e) & 0x07;
-
- return fec_tab [index];
-}
-
-
-static int tda8083_set_symbolrate (struct i2c_adapter *i2c, u32 srate)
-{
- u32 ratio;
- u32 tmp;
- u8 filter;
-
- if (srate > 32000000)
- srate = 32000000;
- if (srate < 500000)
- srate = 500000;
-
- filter = 0;
- if (srate < 24000000)
- filter = 2;
- if (srate < 16000000)
- filter = 3;
-
- tmp = 31250 << 16;
- ratio = tmp / srate;
-
- tmp = (tmp % srate) << 8;
- ratio = (ratio << 8) + tmp / srate;
-
- tmp = (tmp % srate) << 8;
- ratio = (ratio << 8) + tmp / srate;
-
- dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio);
-
- tda8083_writereg (i2c, 0x05, filter);
- tda8083_writereg (i2c, 0x02, (ratio >> 16) & 0xff);
- tda8083_writereg (i2c, 0x03, (ratio >> 8) & 0xff);
- tda8083_writereg (i2c, 0x04, (ratio ) & 0xff);
-
- tda8083_writereg (i2c, 0x00, 0x3c);
- tda8083_writereg (i2c, 0x00, 0x04);
-
- return 1;
-}
-
-
-static void tda8083_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout)
-{
- unsigned long start = jiffies;
-
- while (jiffies - start < timeout &&
- !(tda8083_readreg(i2c, 0x02) & 0x80))
- {
- msleep(50);
- };
-}
-
-
-static int tda8083_send_diseqc_msg (struct i2c_adapter *i2c,
- struct dvb_diseqc_master_cmd *m)
-{
- int i;
-
- tda8083_writereg (i2c, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */
-
- for (i=0; i<m->msg_len; i++)
- tda8083_writereg (i2c, 0x23 + i, m->msg[i]);
-
- tda8083_writereg (i2c, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */
-
- tda8083_wait_diseqc_fifo (i2c, 100);
-
- return 0;
-}
-
-
-static int tda8083_send_diseqc_burst (struct i2c_adapter *i2c, fe_sec_mini_cmd_t burst)
-{
- switch (burst) {
- case SEC_MINI_A:
- tda8083_writereg (i2c, 0x29, (5 << 2)); /* send burst A */
- break;
- case SEC_MINI_B:
- tda8083_writereg (i2c, 0x29, (7 << 2)); /* send B */
- break;
- default:
- return -EINVAL;
- };
-
- tda8083_wait_diseqc_fifo (i2c, 100);
-
- return 0;
-}
-
-
-static int tda8083_set_tone (struct i2c_adapter *i2c, fe_sec_tone_mode_t tone)
-{
- tda8083_writereg (i2c, 0x26, 0xf1);
-
- switch (tone) {
- case SEC_TONE_OFF:
- return tda8083_writereg (i2c, 0x29, 0x00);
- case SEC_TONE_ON:
- return tda8083_writereg (i2c, 0x29, 0x80);
- default:
- return -EINVAL;
- };
-}
-
-
-static int tda8083_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage)
-{
- switch (voltage) {
- case SEC_VOLTAGE_13:
- return tda8083_writereg (i2c, 0x20, 0x00);
- case SEC_VOLTAGE_18:
- return tda8083_writereg (i2c, 0x20, 0x11);
- default:
- return -EINVAL;
- };
-}
-
-
-static int tda8083_ioctl(struct dvb_frontend *fe, unsigned int cmd,
- void *arg)
-{
- struct tda8083_state *state = fe->data;
- struct i2c_adapter *i2c = state->i2c;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, &tda8083_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status=(fe_status_t *) arg;
- u8 signal = ~tda8083_readreg (i2c, 0x01);
- u8 sync = tda8083_readreg (i2c, 0x02);
-
- *status = 0;
-
- if (signal > 10)
- *status |= FE_HAS_SIGNAL;
-
- if (sync & 0x01)
- *status |= FE_HAS_CARRIER;
-
- if (sync & 0x02)
- *status |= FE_HAS_VITERBI;
-
- if (sync & 0x10)
- *status |= FE_HAS_SYNC;
-
- if ((sync & 0x1f) == 0x1f)
- *status |= FE_HAS_LOCK;
-
- break;
- }
-
- case FE_READ_BER:
- *((u32*) arg) = 0; /* XXX FIXME: implement me!!! */
- return -EOPNOTSUPP;
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- u8 signal = ~tda8083_readreg (i2c, 0x01);
- *((u16*) arg) = (signal << 8) | signal;
- break;
- }
- case FE_READ_SNR:
- {
- u8 snr = tda8083_readreg (i2c, 0x08);
- *((u16*) arg) = (snr << 8) | snr;
- break;
- }
- case FE_READ_UNCORRECTED_BLOCKS:
- *((u32*) arg) = 0; /* XXX FIXME: implement me!!! */
- return -EOPNOTSUPP;
-
-
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
-
- tsa5522_set_tv_freq (i2c, p->frequency);
- tda8083_set_inversion (i2c, p->inversion);
- tda8083_set_fec (i2c, p->u.qpsk.fec_inner);
- tda8083_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
-
- tda8083_writereg (i2c, 0x00, 0x3c);
- tda8083_writereg (i2c, 0x00, 0x04);
-
- break;
- }
-
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
-
- /* FIXME: get symbolrate & frequency offset...*/
- /*p->frequency = ???;*/
- p->inversion = (tda8083_readreg (i2c, 0x0e) & 0x80) ?
- INVERSION_ON : INVERSION_OFF;
- p->u.qpsk.fec_inner = tda8083_get_fec (i2c);
- /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (i2c);*/
- break;
- }
-
- case FE_SLEEP:
- tda8083_writereg (i2c, 0x00, 0x02);
- break;
-
- case FE_INIT:
- tda8083_init (i2c);
- tda8083_writereg (i2c, 0x00, 0x3c);
- tda8083_writereg (i2c, 0x00, 0x04);
- break;
-
- case FE_DISEQC_SEND_MASTER_CMD:
- return tda8083_send_diseqc_msg (i2c, arg);
-
- case FE_DISEQC_SEND_BURST:
- tda8083_send_diseqc_burst (i2c, (fe_sec_mini_cmd_t) arg);
- tda8083_writereg (i2c, 0x00, 0x3c);
- tda8083_writereg (i2c, 0x00, 0x04);
-
- break;
-
- case FE_SET_TONE:
- tda8083_set_tone (i2c, (fe_sec_tone_mode_t) arg);
- tda8083_writereg (i2c, 0x00, 0x3c);
- tda8083_writereg (i2c, 0x00, 0x04);
- break;
-
- case FE_SET_VOLTAGE:
- tda8083_set_voltage (i2c, (fe_sec_voltage_t) arg);
- tda8083_writereg (i2c, 0x00, 0x3c);
- tda8083_writereg (i2c, 0x00, 0x04);
- break;
-
- default:
- return -EOPNOTSUPP;
- };
-
- return 0;
-}
-
-static struct i2c_client client_template;
-
-static int tda8083_attach_adapter(struct i2c_adapter *adapter)
-{
- struct tda8083_state *state;
- struct i2c_client *client;
- int ret;
-
- dprintk("Trying to attach to adapter 0x%x:%s.\n",
- adapter->id, adapter->name);
-
- if ((tda8083_readreg (adapter, 0x00)) != 0x05)
- return -ENODEV;
-
- if ( !(state = kmalloc(sizeof(struct tda8083_state), GFP_KERNEL)) )
- return -ENOMEM;
-
- if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
- kfree(state);
- return -ENOMEM;
- }
-
- memset(state, 0, sizeof(struct tda8083_state));
- state->i2c = adapter;
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = 0; //XXX
- i2c_set_clientdata(client, state);
-
- if ((ret = i2c_attach_client(client))) {
- kfree(state);
- kfree(client);
- return ret;
- }
-
- BUG_ON(!state->dvb);
-
- if ((ret = dvb_register_frontend(tda8083_ioctl, state->dvb, state,
- &tda8083_info, THIS_MODULE))) {
- i2c_detach_client(client);
- kfree(state);
- kfree(client);
- return ret;
- }
-
- return 0;
-}
-
-static int tda8083_detach_client(struct i2c_client *client)
-{
- struct tda8083_state *state = i2c_get_clientdata(client);
-
- dvb_unregister_frontend (tda8083_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
- return 0;
-}
-
-static int tda8083_command (struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct tda8083_state *data = i2c_get_clientdata(client);
- dprintk ("%s\n", __FUNCTION__);
-
- switch (cmd) {
- case FE_REGISTER: {
- data->dvb = arg;
- break;
- }
- case FE_UNREGISTER: {
- data->dvb = NULL;
- break;
- }
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_TDA8083,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = tda8083_attach_adapter,
- .detach_client = tda8083_detach_client,
- .command = tda8083_command,
-};
-
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
-
-static int __init init_tda8083 (void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit exit_tda8083(void)
-{
- if (i2c_del_driver(&driver))
- printk("grundig_29504_401: driver deregistration failed\n");
-}
-
-module_init(init_tda8083);
-module_exit(exit_tda8083);
-
-MODULE_DESCRIPTION("Grundig 29504-491 DVB frontend driver (TDA8083 Based)");
-MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
-MODULE_LICENSE("GPL");
-
diff --git a/linux/drivers/media/dvb/frontends/l64781.c b/linux/drivers/media/dvb/frontends/l64781.c
new file mode 100644
index 000000000..2074ddf12
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/l64781.c
@@ -0,0 +1,623 @@
+/*
+ driver for LSI L64781 COFDM demodulator
+
+ Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
+ for Convergence Integrated Media GmbH
+ Marko Kohtala <marko.kohtala@nokia.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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "l64781.h"
+
+
+struct l64781_state {
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ const struct l64781_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* private demodulator data */
+ int first:1;
+};
+
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "l64781: " args); \
+ } while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+
+static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf [] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+ if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
+ dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
+ __FUNCTION__, reg, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static int l64781_readreg (struct l64781_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) return ret;
+
+ return b1[0];
+}
+
+static void apply_tps (struct l64781_state* state)
+{
+ l64781_writereg (state, 0x2a, 0x00);
+ l64781_writereg (state, 0x2a, 0x01);
+
+ /* This here is a little bit questionable because it enables
+ the automatic update of TPS registers. I think we'd need to
+ handle the IRQ from FE to update some other registers as
+ well, or at least implement some magic to tuning to correct
+ to the TPS received from transmission. */
+ l64781_writereg (state, 0x2a, 0x02);
+}
+
+
+static void reset_afc (struct l64781_state* state)
+{
+ /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for
+ timing offset */
+ l64781_writereg (state, 0x07, 0x9e); /* stall AFC */
+ l64781_writereg (state, 0x08, 0); /* AFC INIT FREQ */
+ l64781_writereg (state, 0x09, 0);
+ l64781_writereg (state, 0x0a, 0);
+ l64781_writereg (state, 0x07, 0x8e);
+ l64781_writereg (state, 0x0e, 0); /* AGC gain to zero in beginning */
+ l64781_writereg (state, 0x11, 0x80); /* stall TIM */
+ l64781_writereg (state, 0x10, 0); /* TIM_OFFSET_LSB */
+ l64781_writereg (state, 0x12, 0);
+ l64781_writereg (state, 0x13, 0);
+ l64781_writereg (state, 0x11, 0x00);
+}
+
+static int reset_and_configure (struct l64781_state* state)
+{
+ u8 buf [] = { 0x06 };
+ struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };
+ // NOTE: this is correct in writing to address 0x00
+
+ return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+ /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
+ static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
+ /* QPSK, QAM_16, QAM_64 */
+ static const u8 qam_tab [] = { 2, 4, 0, 6 };
+ static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */
+ static const u8 guard_tab [] = { 1, 2, 4, 8 };
+ /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
+ static const u32 ppm = 8000;
+ struct dvb_ofdm_parameters *p = &param->u.ofdm;
+ u32 ddfs_offset_fixed;
+/* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
+/* bw_tab[p->bandWidth]<<10)/15625; */
+ u32 init_freq;
+ u32 spi_bias;
+ u8 val0x04;
+ u8 val0x05;
+ u8 val0x06;
+ int bw = p->bandwidth - BANDWIDTH_8_MHZ;
+
+ state->config->pll_set(fe, param);
+
+ if (param->inversion != INVERSION_ON &&
+ param->inversion != INVERSION_OFF)
+ return -EINVAL;
+
+ if (bw < 0 || bw > 2)
+ return -EINVAL;
+
+ if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
+ p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 &&
+ p->code_rate_HP != FEC_7_8)
+ return -EINVAL;
+
+ if (p->hierarchy_information != HIERARCHY_NONE &&
+ (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
+ p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
+ p->code_rate_LP != FEC_7_8))
+ return -EINVAL;
+
+ if (p->constellation != QPSK && p->constellation != QAM_16 &&
+ p->constellation != QAM_64)
+ return -EINVAL;
+
+ if (p->transmission_mode != TRANSMISSION_MODE_2K &&
+ p->transmission_mode != TRANSMISSION_MODE_8K)
+ return -EINVAL;
+
+ if (p->guard_interval < GUARD_INTERVAL_1_32 ||
+ p->guard_interval > GUARD_INTERVAL_1_4)
+ return -EINVAL;
+
+ if (p->hierarchy_information < HIERARCHY_NONE ||
+ p->hierarchy_information > HIERARCHY_4)
+ return -EINVAL;
+
+ ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000;
+
+ /* This works up to 20000 ppm, it overflows if too large ppm! */
+ init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
+ bw_tab[p->bandwidth] & 0xFFFFFF);
+
+ /* SPI bias calculation is slightly modified to fit in 32bit */
+ /* will work for high ppm only... */
+ spi_bias = 378 * (1 << 10);
+ spi_bias *= 16;
+ spi_bias *= bw_tab[p->bandwidth];
+ spi_bias *= qam_tab[p->constellation];
+ spi_bias /= p->code_rate_HP + 1;
+ spi_bias /= (guard_tab[p->guard_interval] + 32);
+ spi_bias *= 1000ULL;
+ spi_bias /= 1000ULL + ppm/1000;
+ spi_bias *= p->code_rate_HP;
+
+ val0x04 = (p->transmission_mode << 2) | p->guard_interval;
+ val0x05 = fec_tab[p->code_rate_HP];
+
+ if (p->hierarchy_information != HIERARCHY_NONE)
+ val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
+
+ val0x06 = (p->hierarchy_information << 2) | p->constellation;
+
+ l64781_writereg (state, 0x04, val0x04);
+ l64781_writereg (state, 0x05, val0x05);
+ l64781_writereg (state, 0x06, val0x06);
+
+ reset_afc (state);
+
+ /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */
+ l64781_writereg (state, 0x15,
+ p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3);
+ l64781_writereg (state, 0x16, init_freq & 0xff);
+ l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff);
+ l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff);
+
+ l64781_writereg (state, 0x1b, spi_bias & 0xff);
+ l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);
+ l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |
+ (param->inversion == INVERSION_ON ? 0x80 : 0x00));
+
+ l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);
+ l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
+
+ l64781_readreg (state, 0x00); /* clear interrupt registers... */
+ l64781_readreg (state, 0x01); /* dto. */
+
+ apply_tps (state);
+
+ return 0;
+}
+
+static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+ int tmp;
+
+
+ tmp = l64781_readreg(state, 0x04);
+ switch(tmp & 3) {
+ case 0:
+ param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+ switch((tmp >> 2) & 3) {
+ case 0:
+ param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ default:
+ printk("Unexpected value for transmission_mode\n");
+ }
+
+
+
+ tmp = l64781_readreg(state, 0x05);
+ switch(tmp & 7) {
+ case 0:
+ param->u.ofdm.code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ param->u.ofdm.code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ param->u.ofdm.code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ param->u.ofdm.code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ param->u.ofdm.code_rate_HP = FEC_7_8;
+ break;
+ default:
+ printk("Unexpected value for code_rate_HP\n");
+ }
+ switch((tmp >> 3) & 7) {
+ case 0:
+ param->u.ofdm.code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ param->u.ofdm.code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ param->u.ofdm.code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ param->u.ofdm.code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ param->u.ofdm.code_rate_LP = FEC_7_8;
+ break;
+ default:
+ printk("Unexpected value for code_rate_LP\n");
+ }
+
+
+ tmp = l64781_readreg(state, 0x06);
+ switch(tmp & 3) {
+ case 0:
+ param->u.ofdm.constellation = QPSK;
+ break;
+ case 1:
+ param->u.ofdm.constellation = QAM_16;
+ break;
+ case 2:
+ param->u.ofdm.constellation = QAM_64;
+ break;
+ default:
+ printk("Unexpected value for constellation\n");
+ }
+ switch((tmp >> 2) & 7) {
+ case 0:
+ param->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ break;
+ case 1:
+ param->u.ofdm.hierarchy_information = HIERARCHY_1;
+ break;
+ case 2:
+ param->u.ofdm.hierarchy_information = HIERARCHY_2;
+ break;
+ case 3:
+ param->u.ofdm.hierarchy_information = HIERARCHY_4;
+ break;
+ default:
+ printk("Unexpected value for hierarchy\n");
+ }
+
+
+ tmp = l64781_readreg (state, 0x1d);
+ param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
+
+ tmp = (int) (l64781_readreg (state, 0x08) |
+ (l64781_readreg (state, 0x09) << 8) |
+ (l64781_readreg (state, 0x0a) << 16));
+ param->frequency += tmp;
+
+ return 0;
+}
+
+static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+ int sync = l64781_readreg (state, 0x32);
+ int gain = l64781_readreg (state, 0x0e);
+
+ l64781_readreg (state, 0x00); /* clear interrupt registers... */
+ l64781_readreg (state, 0x01); /* dto. */
+
+ *status = 0;
+
+ if (gain > 5)
+ *status |= FE_HAS_SIGNAL;
+
+ if (sync & 0x02) /* VCXO locked, this criteria should be ok */
+ *status |= FE_HAS_CARRIER;
+
+ if (sync & 0x20)
+ *status |= FE_HAS_VITERBI;
+
+ if (sync & 0x40)
+ *status |= FE_HAS_SYNC;
+
+ if (sync == 0x7f)
+ *status |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int l64781_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+ /* XXX FIXME: set up counting period (reg 0x26...0x28)
+ */
+ *ber = l64781_readreg (state, 0x39)
+ | (l64781_readreg (state, 0x3a) << 8);
+
+ return 0;
+}
+
+static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+ u8 gain = l64781_readreg (state, 0x0e);
+ *signal_strength = (gain << 8) | gain;
+
+ return 0;
+}
+
+static int l64781_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+ u8 avg_quality = 0xff - l64781_readreg (state, 0x33);
+ *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/
+
+ return 0;
+}
+
+static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+ *ucblocks = l64781_readreg (state, 0x37)
+ | (l64781_readreg (state, 0x38) << 8);
+
+ return 0;
+}
+
+static int l64781_sleep(struct dvb_frontend* fe)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+ /* Power down */
+ return l64781_writereg (state, 0x3e, 0x5a);
+}
+
+static int l64781_init(struct dvb_frontend* fe)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+ reset_and_configure (state);
+
+ /* Power up */
+ l64781_writereg (state, 0x3e, 0xa5);
+
+ /* Reset hard */
+ l64781_writereg (state, 0x2a, 0x04);
+ l64781_writereg (state, 0x2a, 0x00);
+
+ /* Set tuner specific things */
+ /* AFC_POL, set also in reset_afc */
+ l64781_writereg (state, 0x07, 0x8e);
+
+ /* Use internal ADC */
+ l64781_writereg (state, 0x0b, 0x81);
+
+ /* AGC loop gain, and polarity is positive */
+ l64781_writereg (state, 0x0c, 0x84);
+
+ /* Internal ADC outputs two's complement */
+ l64781_writereg (state, 0x0d, 0x8c);
+
+ /* With ppm=8000, it seems the DTR_SENSITIVITY will result in
+ value of 2 with all possible bandwidths and guard
+ intervals, which is the initial value anyway. */
+ /*l64781_writereg (state, 0x19, 0x92);*/
+
+ /* Everything is two's complement, soft bit and CSI_OUT too */
+ l64781_writereg (state, 0x1e, 0x09);
+
+ if (state->config->pll_init) state->config->pll_init(fe);
+
+ /* delay a bit after first init attempt */
+ if (state->first) {
+ state->first = 0;
+ msleep(200);
+ }
+
+ return 0;
+}
+
+static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+ fesettings->min_delay_ms = 200;
+ fesettings->step_size = 166667;
+ fesettings->max_drift = 166667*2;
+ return 0;
+}
+
+static void l64781_release(struct dvb_frontend* fe)
+{
+ struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops l64781_ops;
+
+struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct l64781_state* state = NULL;
+ int reg0x3e = -1;
+ u8 b0 [] = { 0x1a };
+ u8 b1 [] = { 0x00 };
+ struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+ { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+ /* allocate memory for the internal state */
+ state = (struct l64781_state*) kmalloc(sizeof(struct l64781_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
+ state->first = 1;
+
+ /**
+ * the L64781 won't show up before we send the reset_and_configure()
+ * broadcast. If nothing responds there is no L64781 on the bus...
+ */
+ if (reset_and_configure(state) < 0) {
+ dprintk("No response to reset and configure broadcast...\n");
+ goto error;
+ }
+
+ /* The chip always responds to reads */
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ dprintk("No response to read on I2C bus\n");
+ goto error;
+ }
+
+ /* Save current register contents for bailout */
+ reg0x3e = l64781_readreg(state, 0x3e);
+
+ /* Reading the POWER_DOWN register always returns 0 */
+ if (reg0x3e != 0) {
+ dprintk("Device doesn't look like L64781\n");
+ goto error;
+ }
+
+ /* Turn the chip off */
+ l64781_writereg (state, 0x3e, 0x5a);
+
+ /* Responds to all reads with 0 */
+ if (l64781_readreg(state, 0x1a) != 0) {
+ dprintk("Read 1 returned unexpcted value\n");
+ goto error;
+ }
+
+ /* Turn the chip on */
+ l64781_writereg (state, 0x3e, 0xa5);
+
+ /* Responds with register default value */
+ if (l64781_readreg(state, 0x1a) != 0xa1) {
+ dprintk("Read 2 returned unexpcted value\n");
+ goto error;
+ }
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (reg0x3e >= 0) l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops l64781_ops = {
+
+ .info = {
+ .name = "LSI L64781 DVB-T",
+ .type = FE_OFDM,
+ /* .frequency_min = ???,*/
+ /* .frequency_max = ???,*/
+ .frequency_stepsize = 166666,
+ /* .frequency_tolerance = ???,*/
+ /* .symbol_rate_tolerance = ???,*/
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_MUTE_TS
+ },
+
+ .release = l64781_release,
+
+ .init = l64781_init,
+ .sleep = l64781_sleep,
+
+ .set_frontend = apply_frontend_param,
+ .get_frontend = get_frontend,
+ .get_tune_settings = l64781_get_tune_settings,
+
+ .read_status = l64781_read_status,
+ .read_ber = l64781_read_ber,
+ .read_signal_strength = l64781_read_signal_strength,
+ .read_snr = l64781_read_snr,
+ .read_ucblocks = l64781_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver");
+MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(l64781_attach);
diff --git a/linux/drivers/media/dvb/frontends/l64781.h b/linux/drivers/media/dvb/frontends/l64781.h
new file mode 100644
index 000000000..259dfffcc
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/l64781.h
@@ -0,0 +1,43 @@
+/*
+ driver for LSI L64781 COFDM demodulator
+
+ Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
+ for Convergence Integrated Media GmbH
+ Marko Kohtala <marko.kohtala@nokia.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 L64781_H
+#define L64781_H
+
+#include <linux/dvb/frontend.h>
+
+struct l64781_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+
+extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // L64781_H
diff --git a/linux/drivers/media/dvb/frontends/mt312.c b/linux/drivers/media/dvb/frontends/mt312.c
index 267991a2f..1b31e982c 100644
--- a/linux/drivers/media/dvb/frontends/mt312.c
+++ b/linux/drivers/media/dvb/frontends/mt312.c
@@ -1,5 +1,5 @@
-/*
- Driver for Zarlink MT312 Satellite Channel Decoder
+/*
+ Driver for Zarlink VP310/MT312 Satellite Channel Decoder
Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
@@ -31,71 +31,52 @@
#include <linux/moduleparam.h>
#include "dvb_frontend.h"
+#include "mt312_priv.h"
#include "mt312.h"
-#define FRONTEND_NAME "dvbfe_mt312"
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
+struct mt312_state {
-static int debug;
+ struct i2c_adapter* i2c;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct mt312_config* config;
+ struct dvb_frontend frontend;
-#define I2C_ADDR_MT312 0x0e
-#define I2C_ADDR_SL1935 0x61
-#define I2C_ADDR_TSA5059 0x61
+ u8 id;
+ u8 frequency;
+};
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "mt312: " args); \
+ } while (0)
#define MT312_SYS_CLK 90000000UL /* 90 MHz */
#define MT312_LPOWER_SYS_CLK 60000000UL /* 60 MHz */
#define MT312_PLL_CLK 10000000UL /* 10 MHz */
-static struct dvb_frontend_info mt312_info = {
- .name = "Zarlink MT312",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
- /*.frequency_tolerance = 29500, FIXME: binary compatibility waste? */
- .symbol_rate_min = MT312_SYS_CLK / 128,
- .symbol_rate_max = MT312_SYS_CLK / 2,
- /*.symbol_rate_tolerance = 500, FIXME: binary compatibility waste? 2% */
- .notifier_delay = 0,
- .caps =
- FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS |
- FE_CAN_RECOVER
-};
-
-struct mt312_state {
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
- int id;
-};
-
-static int mt312_read(struct i2c_adapter *i2c,
- const enum mt312_reg_addr reg, void *buf,
- const size_t count)
+static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
+ void *buf, const size_t count)
{
int ret;
struct i2c_msg msg[2];
u8 regbuf[1] = { reg };
- msg[0].addr = I2C_ADDR_MT312;
+ msg[0].addr = state->config->demod_address;
msg[0].flags = 0;
msg[0].buf = regbuf;
msg[0].len = 1;
- msg[1].addr = I2C_ADDR_MT312;
+ msg[1].addr = state->config->demod_address;
msg[1].flags = I2C_M_RD;
msg[1].buf = buf;
msg[1].len = count;
- ret = i2c_transfer(i2c, msg, 2);
+ ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret);
@@ -113,9 +94,8 @@ static int mt312_read(struct i2c_adapter *i2c,
return 0;
}
-static int mt312_write(struct i2c_adapter *i2c,
- const enum mt312_reg_addr reg, const void *src,
- const size_t count)
+static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
+ const void *src, const size_t count)
{
int ret;
u8 buf[count + 1];
@@ -132,12 +112,12 @@ static int mt312_write(struct i2c_adapter *i2c,
buf[0] = reg;
memcpy(&buf[1], src, count);
- msg.addr = I2C_ADDR_MT312;
+ msg.addr = state->config->demod_address;
msg.flags = 0;
msg.buf = buf;
msg.len = count + 1;
- ret = i2c_transfer(i2c, &msg, 1);
+ ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1) {
dprintk("%s: ret == %d\n", __FUNCTION__, ret);
@@ -147,123 +127,136 @@ static int mt312_write(struct i2c_adapter *i2c,
return 0;
}
-static inline int mt312_readreg(struct i2c_adapter *i2c,
+static inline int mt312_readreg(struct mt312_state* state,
const enum mt312_reg_addr reg, u8 *val)
{
- return mt312_read(i2c, reg, val, 1);
+ return mt312_read(state, reg, val, 1);
}
-static inline int mt312_writereg(struct i2c_adapter *i2c,
+static inline int mt312_writereg(struct mt312_state* state,
const enum mt312_reg_addr reg, const u8 val)
{
- return mt312_write(i2c, reg, &val, 1);
+ return mt312_write(state, reg, &val, 1);
}
-static int mt312_pll_write(struct i2c_adapter *i2c, const u8 addr,
- u8 * buf, const u8 len)
+static inline u32 mt312_div(u32 a, u32 b)
{
- int ret;
- struct i2c_msg msg;
-
- msg.addr = addr;
- msg.flags = 0;
- msg.buf = buf;
- msg.len = len;
+ return (a + (b / 2)) / b;
+}
- if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x40)) < 0)
- return ret;
+static int mt312_reset(struct mt312_state* state, const u8 full)
+{
+ return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
+}
- if ((ret = i2c_transfer(i2c, &msg, 1)) != 1)
- printk(KERN_ERR "%s: i/o error (ret == %d)\n", __FUNCTION__, ret);
+static int mt312_get_inversion(struct mt312_state* state,
+ fe_spectral_inversion_t *i)
+{
+ int ret;
+ u8 vit_mode;
- if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x00)) < 0)
+ if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0)
return ret;
+ if (vit_mode & 0x80) /* auto inversion was used */
+ *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
+
return 0;
}
-static inline u32 mt312_div(u32 a, u32 b)
+static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
{
- return (a + (b / 2)) / b;
-}
+ int ret;
+ u8 sym_rate_h;
+ u8 dec_ratio;
+ u16 sym_rat_op;
+ u16 monitor;
+ u8 buf[2];
-static int sl1935_set_tv_freq(struct i2c_adapter *i2c, u32 freq, u32 sr)
-{
- /* 155 uA, Baseband Path B */
- u8 buf[4] = { 0x00, 0x00, 0x80, 0x00 };
-
- u8 exp;
- u32 ref;
- u32 div;
-
- if (sr < 10000000) { /* 1-10 MSym/s: ratio 2 ^ 3 */
- exp = 3;
- buf[2] |= 0x40; /* 690 uA */
- } else if (sr < 15000000) { /* 10-15 MSym/s: ratio 2 ^ 4 */
- exp = 4;
- buf[2] |= 0x20; /* 330 uA */
- } else { /* 15-45 MSym/s: ratio 2 ^ 7 */
- exp = 7;
- buf[3] |= 0x08; /* Baseband Path A */
- }
+ if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0)
+ return ret;
- div = mt312_div(MT312_PLL_CLK, 1 << exp);
- ref = mt312_div(freq * 1000, div);
- mt312_info.frequency_stepsize = mt312_div(div, 1000);
+ if (sym_rate_h & 0x80) { /* symbol rate search was used */
+ if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0)
+ return ret;
- buf[0] = (ref >> 8) & 0x7f;
- buf[1] = (ref >> 0) & 0xff;
- buf[2] |= (exp - 1);
+ if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+ return ret;
- if (freq < 1550000)
- buf[3] |= 0x10;
+ monitor = (buf[0] << 8) | buf[1];
- dprintk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0],
- buf[1], buf[2], buf[3]);
+ dprintk(KERN_DEBUG "sr(auto) = %u\n",
+ mt312_div(monitor * 15625, 4));
+ } else {
+ if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0)
+ return ret;
- return mt312_pll_write(i2c, I2C_ADDR_SL1935, buf, sizeof(buf));
-}
+ if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+ return ret;
-static int tsa5059_set_tv_freq(struct i2c_adapter *i2c, u32 freq, u32 sr)
-{
- u8 buf[4];
+ dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
- u32 ref = mt312_div(freq, 125);
+ if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
+ return ret;
- buf[0] = (ref >> 8) & 0x7f;
- buf[1] = (ref >> 0) & 0xff;
- buf[2] = 0x84 | ((ref >> 10) & 0x60);
- buf[3] = 0x80;
-
- if (freq < 1550000)
- buf[3] |= 0x02;
+ sym_rat_op = (buf[0] << 8) | buf[1];
- dprintk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0],
- buf[1], buf[2], buf[3]);
+ dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
+ sym_rat_op, dec_ratio);
+ dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
+ (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
+ 2) - dec_ratio);
+ }
- return mt312_pll_write(i2c, I2C_ADDR_TSA5059, buf, sizeof(buf));
+ return 0;
}
-static int mt312_reset(struct i2c_adapter *i2c, const u8 full)
+static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
{
- return mt312_writereg(i2c, RESET, full ? 0x80 : 0x40);
+ const fe_code_rate_t fec_tab[8] =
+ { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
+ FEC_AUTO, FEC_AUTO };
+
+ int ret;
+ u8 fec_status;
+
+ if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0)
+ return ret;
+
+ *cr = fec_tab[(fec_status >> 4) & 0x07];
+
+ return 0;
}
-static int mt312_initfe(struct mt312_state *state, u8 pll)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int mt312_initfe(struct dvb_frontend* fe)
{
- struct i2c_adapter *i2c = state->i2c;
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 buf[2];
/* wake up */
- if ((ret = mt312_writereg(i2c, CONFIG, (pll == 60 ? 0x88 : 0x8c))) < 0)
+ if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0)
return ret;
/* wait at least 150 usec */
udelay(150);
/* full reset */
- if ((ret = mt312_reset(i2c, 1)) < 0)
+ if ((ret = mt312_reset(state, 1)) < 0)
return ret;
// Per datasheet, write correct values. 09/28/03 ACCJr.
@@ -271,56 +264,63 @@ static int mt312_initfe(struct mt312_state *state, u8 pll)
{
u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00};
- if ((ret = mt312_write(i2c, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
+ if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
return ret;
}
/* SYS_CLK */
- buf[0] = mt312_div((pll == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
+ buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
/* DISEQC_RATIO */
buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
- if ((ret = mt312_write(i2c, SYS_CLK, buf, sizeof(buf))) < 0)
+ if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0)
return ret;
- if ((ret = mt312_writereg(i2c, SNR_THS_HIGH, 0x32)) < 0)
+ if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0)
return ret;
- if ((ret = mt312_writereg(i2c, OP_CTRL, 0x53)) < 0)
+ if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0)
return ret;
/* TS_SW_LIM */
buf[0] = 0x8c;
buf[1] = 0x98;
- if ((ret = mt312_write(i2c, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
+ if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
return ret;
- if ((ret = mt312_writereg(i2c, CS_SW_LIM, 0x69)) < 0)
+ if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
return ret;
+ if (state->config->pll_init) {
+ mt312_writereg(state, GPP_CTRL, 0x40);
+ state->config->pll_init(fe);
+ mt312_writereg(state, GPP_CTRL, 0x00);
+ }
+
return 0;
}
-static int mt312_send_master_cmd(struct i2c_adapter *i2c,
- const struct dvb_diseqc_master_cmd *c)
+static int mt312_send_master_cmd(struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *c)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 diseqc_mode;
if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
return -EINVAL;
- if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+ if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
return ret;
if ((ret =
- mt312_write(i2c, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
+ mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
return ret;
if ((ret =
- mt312_writereg(i2c, DISEQC_MODE,
+ mt312_writereg(state, DISEQC_MODE,
(diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
| 0x04)) < 0)
return ret;
@@ -328,21 +328,15 @@ static int mt312_send_master_cmd(struct i2c_adapter *i2c,
/* set DISEQC_MODE[2:0] to zero if a return message is expected */
if (c->msg[0] & 0x02)
if ((ret =
- mt312_writereg(i2c, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
+ mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
return ret;
return 0;
}
-static int mt312_recv_slave_reply(struct i2c_adapter *i2c,
- struct dvb_diseqc_slave_reply *r)
-{
- /* TODO */
- return -EOPNOTSUPP;
-}
-
-static int mt312_send_burst(struct i2c_adapter *i2c, const fe_sec_mini_cmd_t c)
+static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
const u8 mini_tab[2] = { 0x02, 0x03 };
int ret;
@@ -351,19 +345,20 @@ static int mt312_send_burst(struct i2c_adapter *i2c, const fe_sec_mini_cmd_t c)
if (c > SEC_MINI_B)
return -EINVAL;
- if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+ if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
return ret;
if ((ret =
- mt312_writereg(i2c, DISEQC_MODE,
+ mt312_writereg(state, DISEQC_MODE,
(diseqc_mode & 0x40) | mini_tab[c])) < 0)
return ret;
return 0;
}
-static int mt312_set_tone(struct i2c_adapter *i2c, const fe_sec_tone_mode_t t)
+static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
const u8 tone_tab[2] = { 0x01, 0x00 };
int ret;
@@ -372,36 +367,37 @@ static int mt312_set_tone(struct i2c_adapter *i2c, const fe_sec_tone_mode_t t)
if (t > SEC_TONE_OFF)
return -EINVAL;
- if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0)
+ if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
return ret;
if ((ret =
- mt312_writereg(i2c, DISEQC_MODE,
+ mt312_writereg(state, DISEQC_MODE,
(diseqc_mode & 0x40) | tone_tab[t])) < 0)
return ret;
return 0;
}
-static int mt312_set_voltage(struct i2c_adapter *i2c, const fe_sec_voltage_t v)
+static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
if (v > SEC_VOLTAGE_OFF)
return -EINVAL;
- return mt312_writereg(i2c, DISEQC_MODE, volt_tab[v]);
+ return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
}
-static int mt312_read_status(struct mt312_state *state, fe_status_t *s)
+static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
{
- struct i2c_adapter *i2c = state->i2c;
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 status[3], vit_mode;
*s = 0;
- if ((ret = mt312_read(i2c, QPSK_STAT_H, status, sizeof(status))) < 0)
+ if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0)
return ret;
dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
@@ -419,24 +415,25 @@ static int mt312_read_status(struct mt312_state *state, fe_status_t *s)
// VP310 doesn't have AUTO, so we "implement it here" ACCJr
if ((state->id == ID_VP310) && !(status[0] & 0x01)) {
- if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0)
+ if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0)
return ret;
vit_mode ^= 0x40;
- if ((ret = mt312_writereg(i2c, VIT_MODE, vit_mode)) < 0)
+ if ((ret = mt312_writereg(state, VIT_MODE, vit_mode)) < 0)
return ret;
- if ((ret = mt312_writereg(i2c, GO, 0x01)) < 0)
+ if ((ret = mt312_writereg(state, GO, 0x01)) < 0)
return ret;
}
return 0;
}
-static int mt312_read_bercnt(struct i2c_adapter *i2c, u32 *ber)
+static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 buf[3];
- if ((ret = mt312_read(i2c, RS_BERCNT_H, buf, 3)) < 0)
+ if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0)
return ret;
*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
@@ -444,14 +441,15 @@ static int mt312_read_bercnt(struct i2c_adapter *i2c, u32 *ber)
return 0;
}
-static int mt312_read_agc(struct i2c_adapter *i2c, u16 *signal_strength)
+static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 buf[3];
u16 agc;
s16 err_db;
- if ((ret = mt312_read(i2c, AGC_H, buf, sizeof(buf))) < 0)
+ if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0)
return ret;
agc = (buf[0] << 6) | (buf[1] >> 2);
@@ -464,12 +462,13 @@ static int mt312_read_agc(struct i2c_adapter *i2c, u16 *signal_strength)
return 0;
}
-static int mt312_read_snr(struct i2c_adapter *i2c, u16 *snr)
+static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 buf[2];
- if ((ret = mt312_read(i2c, M_SNR_H, &buf, sizeof(buf))) < 0)
+ if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0)
return ret;
*snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
@@ -477,12 +476,13 @@ static int mt312_read_snr(struct i2c_adapter *i2c, u16 *snr)
return 0;
}
-static int mt312_read_ubc(struct i2c_adapter *i2c, u32 *ubc)
+static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 buf[2];
- if ((ret = mt312_read(i2c, RS_UBC_H, &buf, sizeof(buf))) < 0)
+ if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0)
return ret;
*ubc = (buf[0] << 8) | buf[1];
@@ -490,10 +490,10 @@ static int mt312_read_ubc(struct i2c_adapter *i2c, u32 *ubc)
return 0;
}
-static int mt312_set_frontend(struct mt312_state *state,
- const struct dvb_frontend_parameters *p)
+static int mt312_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
{
- struct i2c_adapter *i2c = state->i2c;
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 buf[5], config_val;
u16 sr;
@@ -502,20 +502,18 @@ static int mt312_set_frontend(struct mt312_state *state,
{ 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
- int (*set_tv_freq)(struct i2c_adapter *i2c, u32 freq, u32 sr);
-
dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
- if ((p->frequency < mt312_info.frequency_min)
- || (p->frequency > mt312_info.frequency_max))
+ if ((p->frequency < fe->ops->info.frequency_min)
+ || (p->frequency > fe->ops->info.frequency_max))
return -EINVAL;
if ((p->inversion < INVERSION_OFF)
- || (p->inversion > INVERSION_AUTO))
+ || (p->inversion > INVERSION_ON))
return -EINVAL;
- if ((p->u.qpsk.symbol_rate < mt312_info.symbol_rate_min)
- || (p->u.qpsk.symbol_rate > mt312_info.symbol_rate_max))
+ if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
+ || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
return -EINVAL;
if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -530,31 +528,36 @@ static int mt312_set_frontend(struct mt312_state *state,
case ID_VP310:
// For now we will do this only for the VP310.
// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
- if ((ret = mt312_readreg(i2c, CONFIG, &config_val) < 0))
+ if ((ret = mt312_readreg(state, CONFIG, &config_val) < 0))
return ret;
if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
{
- if ((config_val & 0x0c) == 0x08) //We are running 60MHz
- if ((ret = mt312_initfe(state, (u8) 90)) < 0)
+ if ((config_val & 0x0c) == 0x08) { //We are running 60MHz
+ state->frequency = 90;
+ if ((ret = mt312_initfe(fe)) < 0)
return ret;
+ }
}
else
{
- if ((config_val & 0x0c) == 0x0C) //We are running 90MHz
- if ((ret = mt312_initfe(state, (u8) 60)) < 0)
+ if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz
+ state->frequency = 60;
+ if ((ret = mt312_initfe(fe)) < 0)
return ret;
+ }
}
- set_tv_freq = tsa5059_set_tv_freq;
break;
+
case ID_MT312:
- set_tv_freq = sl1935_set_tv_freq;
break;
+
default:
return -EINVAL;
}
- if ((ret = set_tv_freq(i2c, p->frequency, p->u.qpsk.symbol_rate)) < 0)
- return ret;
+ mt312_writereg(state, GPP_CTRL, 0x40);
+ state->config->pll_set(fe, p);
+ mt312_writereg(state, GPP_CTRL, 0x00);
/* sr = (u16)(sr * 256.0 / 1000000.0) */
sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
@@ -575,334 +578,154 @@ static int mt312_set_frontend(struct mt312_state *state,
/* GO */
buf[4] = 0x01;
- if ((ret = mt312_write(i2c, SYM_RATE_H, buf, sizeof(buf))) < 0)
- return ret;
-
- mt312_reset(i2c, 0);
-
- return 0;
-}
-
-static int mt312_get_inversion(struct i2c_adapter *i2c,
- fe_spectral_inversion_t *i)
-{
- int ret;
- u8 vit_mode;
-
- if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0)
- return ret;
-
- if (vit_mode & 0x80) /* auto inversion was used */
- *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
-
- return 0;
-}
-
-static int mt312_get_symbol_rate(struct i2c_adapter *i2c, u32 *sr)
-{
- int ret;
- u8 sym_rate_h;
- u8 dec_ratio;
- u16 sym_rat_op;
- u16 monitor;
- u8 buf[2];
-
- if ((ret = mt312_readreg(i2c, SYM_RATE_H, &sym_rate_h)) < 0)
- return ret;
-
- if (sym_rate_h & 0x80) { /* symbol rate search was used */
- if ((ret = mt312_writereg(i2c, MON_CTRL, 0x03)) < 0)
- return ret;
-
- if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0)
- return ret;
-
- monitor = (buf[0] << 8) | buf[1];
-
- dprintk(KERN_DEBUG "sr(auto) = %u\n",
- mt312_div(monitor * 15625, 4));
- } else {
- if ((ret = mt312_writereg(i2c, MON_CTRL, 0x05)) < 0)
- return ret;
-
- if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0)
- return ret;
-
- dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
-
- if ((ret = mt312_read(i2c, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
- return ret;
-
- sym_rat_op = (buf[0] << 8) | buf[1];
-
- dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
- sym_rat_op, dec_ratio);
- dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
- (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
- 2) - dec_ratio);
- }
-
- return 0;
-}
-
-static int mt312_get_code_rate(struct i2c_adapter *i2c, fe_code_rate_t *cr)
-{
- const fe_code_rate_t fec_tab[8] =
- { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
- FEC_AUTO, FEC_AUTO };
-
- int ret;
- u8 fec_status;
-
- if ((ret = mt312_readreg(i2c, FEC_STATUS, &fec_status)) < 0)
+ if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0)
return ret;
- *cr = fec_tab[(fec_status >> 4) & 0x07];
+ mt312_reset(state, 0);
return 0;
}
-static int mt312_get_frontend(struct i2c_adapter *i2c,
+static int mt312_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *p)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
- if ((ret = mt312_get_inversion(i2c, &p->inversion)) < 0)
+ if ((ret = mt312_get_inversion(state, &p->inversion)) < 0)
return ret;
- if ((ret = mt312_get_symbol_rate(i2c, &p->u.qpsk.symbol_rate)) < 0)
+ if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0)
return ret;
- if ((ret = mt312_get_code_rate(i2c, &p->u.qpsk.fec_inner)) < 0)
+ if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0)
return ret;
return 0;
}
-static int mt312_sleep(struct i2c_adapter *i2c)
+static int mt312_sleep(struct dvb_frontend* fe)
{
+ struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv;
int ret;
u8 config;
/* reset all registers to defaults */
- if ((ret = mt312_reset(i2c, 1)) < 0)
+ if ((ret = mt312_reset(state, 1)) < 0)
return ret;
- if ((ret = mt312_readreg(i2c, CONFIG, &config)) < 0)
+ if ((ret = mt312_readreg(state, CONFIG, &config)) < 0)
return ret;
/* enter standby */
- if ((ret = mt312_writereg(i2c, CONFIG, config & 0x7f)) < 0)
+ if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0)
return ret;
return 0;
}
-static int mt312_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
- struct mt312_state *state = fe->data;
- struct i2c_adapter *i2c = state->i2c;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy(arg, &mt312_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_DISEQC_RESET_OVERLOAD:
- return -EOPNOTSUPP;
-
- case FE_DISEQC_SEND_MASTER_CMD:
- return mt312_send_master_cmd(i2c, arg);
-
- case FE_DISEQC_RECV_SLAVE_REPLY:
- if (state->id == ID_MT312)
- return mt312_recv_slave_reply(i2c, arg);
- else
- return -EOPNOTSUPP;
-
- case FE_DISEQC_SEND_BURST:
- return mt312_send_burst(i2c, (fe_sec_mini_cmd_t) arg);
-
- case FE_SET_TONE:
- return mt312_set_tone(i2c, (fe_sec_tone_mode_t) arg);
-
- case FE_SET_VOLTAGE:
- return mt312_set_voltage(i2c, (fe_sec_voltage_t) arg);
-
- case FE_ENABLE_HIGH_LNB_VOLTAGE:
- return -EOPNOTSUPP;
-
- case FE_READ_STATUS:
- return mt312_read_status(state, arg);
-
- case FE_READ_BER:
- return mt312_read_bercnt(i2c, arg);
-
- case FE_READ_SIGNAL_STRENGTH:
- return mt312_read_agc(i2c, arg);
-
- case FE_READ_SNR:
- return mt312_read_snr(i2c, arg);
-
- case FE_READ_UNCORRECTED_BLOCKS:
- return mt312_read_ubc(i2c, arg);
-
- case FE_SET_FRONTEND:
- return mt312_set_frontend(state, arg);
-
- case FE_GET_FRONTEND:
- return mt312_get_frontend(i2c, arg);
-
- case FE_GET_EVENT:
- return -EOPNOTSUPP;
-
- case FE_SLEEP:
- return mt312_sleep(i2c);
-
- case FE_INIT:
- /* For the VP310 we should run at 60MHz when ever possible.
- * It should be better to run the mt312 ar lower speed when
- * ever possible, but tunning will be slower. ACCJr 09/29/03
- */
- if (state->id == ID_MT312)
- return mt312_initfe(state, (u8) 90);
- else
- return mt312_initfe(state, (u8) 60);
-
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
- fesettings->min_delay_ms = 50;
- fesettings->step_size = 0;
- fesettings->max_drift = 0;
- return 0;
- }
-
- default:
- return -ENOIOCTLCMD;
- }
-
+ fesettings->min_delay_ms = 50;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
return 0;
}
-static struct i2c_client client_template;
-
-static int mt312_attach_adapter(struct i2c_adapter *adapter)
+static void mt312_release(struct dvb_frontend* fe)
{
- struct mt312_state *state;
- struct i2c_client *client;
- int ret;
- u8 id;
-
- dprintk("Trying to attach to adapter 0x%x:%s.\n",
- adapter->id, adapter->name);
-
- if (mt312_readreg(adapter, ID, &id) < 0)
- return -ENODEV;
-
- if ((id != ID_VP310) && (id != ID_MT312))
- return -ENODEV;
-
- if ( !(state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL)) )
- return -ENOMEM;
-
- memset(state, 0, sizeof(struct mt312_state));
- state->i2c = adapter;
- state->id = id;
-
- if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
- kfree(state);
- return -ENOMEM;
- }
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = I2C_ADDR_MT312;
- i2c_set_clientdata(client, state);
-
- if ((ret = i2c_attach_client(client))) {
- kfree(client);
- kfree(state);
- return ret;
- }
-
- BUG_ON(!state->dvb);
-
- if ((ret = dvb_register_frontend(mt312_ioctl, state->dvb, state,
- &mt312_info, THIS_MODULE))) {
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return ret;
- }
-
- return 0;
-}
-
-static int mt312_detach_client(struct i2c_client *client)
-{
- struct mt312_state *state = i2c_get_clientdata(client);
-
- dprintk ("%s\n", __FUNCTION__);
-
- dvb_unregister_frontend (mt312_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
+ struct mt312_state* state = (struct mt312_state*) fe->demodulator_priv;
kfree(state);
- return 0;
}
-static int mt312_command (struct i2c_client *client, unsigned int cmd, void *arg)
+static struct dvb_frontend_ops mt312_ops;
+
+struct dvb_frontend* mt312_attach(const struct mt312_config* config,
+ struct i2c_adapter* i2c)
{
- struct mt312_state *state = i2c_get_clientdata(client);
+ struct mt312_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
+ if (state == NULL) goto error;
- dprintk ("%s\n", __FUNCTION__);
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &mt312_ops, sizeof(struct dvb_frontend_ops));
- switch (cmd) {
- case FE_REGISTER:
- state->dvb = arg;
+ /* check if the demod is there */
+ if (mt312_readreg(state, ID, &state->id) < 0) goto error;
+ switch(state->id) {
+ case ID_VP310:
+ state->frequency = 90;
+ printk("mt312: Detected Zarlink VP310\n");
break;
- case FE_UNREGISTER:
- state->dvb = NULL;
+
+ case ID_MT312:
+ state->frequency = 60;
+ printk("mt312: Detected Zarlink MT312\n");
break;
+
default:
- return -EOPNOTSUPP;
+ goto error;
}
- return 0;
-}
-
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_MT312,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = mt312_attach_adapter,
- .detach_client = mt312_detach_client,
- .command = mt312_command,
-};
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops mt312_ops = {
+
+ .info = {
+ .name = "Zarlink VP310/MT312 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
+ /*.frequency_tolerance = 29500, FIXME: binary compatibility waste? */
+ .symbol_rate_min = MT312_SYS_CLK / 128,
+ .symbol_rate_max = MT312_SYS_CLK / 2,
+ /*.symbol_rate_tolerance = 500, FIXME: binary compatibility waste? 2% */
+ .caps =
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS |
+ FE_CAN_RECOVER
+ },
+
+ .release = mt312_release,
+
+ .init = mt312_initfe,
+ .sleep = mt312_sleep,
+
+ .set_frontend = mt312_set_frontend,
+ .get_frontend = mt312_get_frontend,
+ .get_tune_settings = mt312_get_tune_settings,
+
+ .read_status = mt312_read_status,
+ .read_ber = mt312_read_ber,
+ .read_signal_strength = mt312_read_signal_strength,
+ .read_snr = mt312_read_snr,
+ .read_ucblocks = mt312_read_ucblocks,
+
+ .diseqc_send_master_cmd = mt312_send_master_cmd,
+ .diseqc_send_burst = mt312_send_burst,
+ .set_tone = mt312_set_tone,
+ .set_voltage = mt312_set_voltage,
};
-static int __init mt312_module_init(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit mt312_module_exit(void)
-{
- if (i2c_del_driver(&driver))
- printk(KERN_ERR "mt312: driver deregistration failed.\n");
-}
-
-module_init(mt312_module_init);
-module_exit(mt312_module_exit);
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("MT312 Satellite Channel Decoder Driver");
+MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(mt312_attach);
diff --git a/linux/drivers/media/dvb/frontends/mt312.h b/linux/drivers/media/dvb/frontends/mt312.h
index 222c6ecbd..cece3ca84 100644
--- a/linux/drivers/media/dvb/frontends/mt312.h
+++ b/linux/drivers/media/dvb/frontends/mt312.h
@@ -1,5 +1,5 @@
-/*
- Driver for Zarlink MT312 QPSK Frontend
+/*
+ Driver for Zarlink MT312 Satellite Channel Decoder
Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
@@ -18,145 +18,27 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ References:
+ http://products.zarlink.com/product_profiles/MT312.htm
+ http://products.zarlink.com/product_profiles/SL1935.htm
*/
-#ifndef _DVB_FRONTENDS_MT312
-#define _DVB_FRONTENDS_MT312
+#ifndef MT312_H
+#define MT312_H
-enum mt312_reg_addr {
- QPSK_INT_H = 0,
- QPSK_INT_M = 1,
- QPSK_INT_L = 2,
- FEC_INT = 3,
- QPSK_STAT_H = 4,
- QPSK_STAT_L = 5,
- FEC_STATUS = 6,
- LNB_FREQ_H = 7,
- LNB_FREQ_L = 8,
- M_SNR_H = 9,
- M_SNR_L = 10,
- VIT_ERRCNT_H = 11,
- VIT_ERRCNT_M = 12,
- VIT_ERRCNT_L = 13,
- RS_BERCNT_H = 14,
- RS_BERCNT_M = 15,
- RS_BERCNT_L = 16,
- RS_UBC_H = 17,
- RS_UBC_L = 18,
- SIG_LEVEL = 19,
- GPP_CTRL = 20,
- RESET = 21,
- DISEQC_MODE = 22,
- SYM_RATE_H = 23,
- SYM_RATE_L = 24,
- VIT_MODE = 25,
- QPSK_CTRL = 26,
- GO = 27,
- IE_QPSK_H = 28,
- IE_QPSK_M = 29,
- IE_QPSK_L = 30,
- IE_FEC = 31,
- QPSK_STAT_EN = 32,
- FEC_STAT_EN = 33,
- SYS_CLK = 34,
- DISEQC_RATIO = 35,
- DISEQC_INSTR = 36,
- FR_LIM = 37,
- FR_OFF = 38,
- AGC_CTRL = 39,
- AGC_INIT = 40,
- AGC_REF = 41,
- AGC_MAX = 42,
- AGC_MIN = 43,
- AGC_LK_TH = 44,
- TS_AGC_LK_TH = 45,
- AGC_PWR_SET = 46,
- QPSK_MISC = 47,
- SNR_THS_LOW = 48,
- SNR_THS_HIGH = 49,
- TS_SW_RATE = 50,
- TS_SW_LIM_L = 51,
- TS_SW_LIM_H = 52,
- CS_SW_RATE_1 = 53,
- CS_SW_RATE_2 = 54,
- CS_SW_RATE_3 = 55,
- CS_SW_RATE_4 = 56,
- CS_SW_LIM = 57,
- TS_LPK = 58,
- TS_LPK_M = 59,
- TS_LPK_L = 60,
- CS_KPROP_H = 61,
- CS_KPROP_L = 62,
- CS_KINT_H = 63,
- CS_KINT_L = 64,
- QPSK_SCALE = 65,
- TLD_OUTCLK_TH = 66,
- TLD_INCLK_TH = 67,
- FLD_TH = 68,
- PLD_OUTLK3 = 69,
- PLD_OUTLK2 = 70,
- PLD_OUTLK1 = 71,
- PLD_OUTLK0 = 72,
- PLD_INLK3 = 73,
- PLD_INLK2 = 74,
- PLD_INLK1 = 75,
- PLD_INLK0 = 76,
- PLD_ACC_TIME = 77,
- SWEEP_PAR = 78,
- STARTUP_TIME = 79,
- LOSSLOCK_TH = 80,
- FEC_LOCK_TM = 81,
- LOSSLOCK_TM = 82,
- VIT_ERRPER_H = 83,
- VIT_ERRPER_M = 84,
- VIT_ERRPER_L = 85,
- VIT_SETUP = 86,
- VIT_REF0 = 87,
- VIT_REF1 = 88,
- VIT_REF2 = 89,
- VIT_REF3 = 90,
- VIT_REF4 = 91,
- VIT_REF5 = 92,
- VIT_REF6 = 93,
- VIT_MAXERR = 94,
- BA_SETUPT = 95,
- OP_CTRL = 96,
- FEC_SETUP = 97,
- PROG_SYNC = 98,
- AFC_SEAR_TH = 99,
- CSACC_DIF_TH = 100,
- QPSK_LK_CT = 101,
- QPSK_ST_CT = 102,
- MON_CTRL = 103,
- QPSK_RESET = 104,
- QPSK_TST_CT = 105,
- QPSK_TST_ST = 106,
- TEST_R = 107,
- AGC_H = 108,
- AGC_M = 109,
- AGC_L = 110,
- FREQ_ERR1_H = 111,
- FREQ_ERR1_M = 112,
- FREQ_ERR1_L = 113,
- FREQ_ERR2_H = 114,
- FREQ_ERR2_L = 115,
- SYM_RAT_OP_H = 116,
- SYM_RAT_OP_L = 117,
- DESEQC2_INT = 118,
- DISEQC2_STAT = 119,
- DISEQC2_FIFO = 120,
- DISEQC2_CTRL1 = 121,
- DISEQC2_CTRL2 = 122,
- MONITOR_H = 123,
- MONITOR_L = 124,
- TEST_MODE = 125,
- ID = 126,
- CONFIG = 127
-};
+#include <linux/dvb/frontend.h>
+
+struct mt312_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
-enum mt312_model_id {
- ID_VP310 = 1,
- ID_MT312 = 3
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
-#endif /* DVB_FRONTENDS_MT312 */
+extern struct dvb_frontend* mt312_attach(const struct mt312_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // MT312_H
diff --git a/linux/drivers/media/dvb/frontends/mt312_priv.h b/linux/drivers/media/dvb/frontends/mt312_priv.h
new file mode 100644
index 000000000..1ddff687e
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/mt312_priv.h
@@ -0,0 +1,162 @@
+/*
+ Driver for Zarlink MT312 QPSK Frontend
+
+ Copyright (C) 2003 Andreas Oberritter <obi@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 _DVB_FRONTENDS_MT312_PRIV
+#define _DVB_FRONTENDS_MT312_PRIV
+
+enum mt312_reg_addr {
+ QPSK_INT_H = 0,
+ QPSK_INT_M = 1,
+ QPSK_INT_L = 2,
+ FEC_INT = 3,
+ QPSK_STAT_H = 4,
+ QPSK_STAT_L = 5,
+ FEC_STATUS = 6,
+ LNB_FREQ_H = 7,
+ LNB_FREQ_L = 8,
+ M_SNR_H = 9,
+ M_SNR_L = 10,
+ VIT_ERRCNT_H = 11,
+ VIT_ERRCNT_M = 12,
+ VIT_ERRCNT_L = 13,
+ RS_BERCNT_H = 14,
+ RS_BERCNT_M = 15,
+ RS_BERCNT_L = 16,
+ RS_UBC_H = 17,
+ RS_UBC_L = 18,
+ SIG_LEVEL = 19,
+ GPP_CTRL = 20,
+ RESET = 21,
+ DISEQC_MODE = 22,
+ SYM_RATE_H = 23,
+ SYM_RATE_L = 24,
+ VIT_MODE = 25,
+ QPSK_CTRL = 26,
+ GO = 27,
+ IE_QPSK_H = 28,
+ IE_QPSK_M = 29,
+ IE_QPSK_L = 30,
+ IE_FEC = 31,
+ QPSK_STAT_EN = 32,
+ FEC_STAT_EN = 33,
+ SYS_CLK = 34,
+ DISEQC_RATIO = 35,
+ DISEQC_INSTR = 36,
+ FR_LIM = 37,
+ FR_OFF = 38,
+ AGC_CTRL = 39,
+ AGC_INIT = 40,
+ AGC_REF = 41,
+ AGC_MAX = 42,
+ AGC_MIN = 43,
+ AGC_LK_TH = 44,
+ TS_AGC_LK_TH = 45,
+ AGC_PWR_SET = 46,
+ QPSK_MISC = 47,
+ SNR_THS_LOW = 48,
+ SNR_THS_HIGH = 49,
+ TS_SW_RATE = 50,
+ TS_SW_LIM_L = 51,
+ TS_SW_LIM_H = 52,
+ CS_SW_RATE_1 = 53,
+ CS_SW_RATE_2 = 54,
+ CS_SW_RATE_3 = 55,
+ CS_SW_RATE_4 = 56,
+ CS_SW_LIM = 57,
+ TS_LPK = 58,
+ TS_LPK_M = 59,
+ TS_LPK_L = 60,
+ CS_KPROP_H = 61,
+ CS_KPROP_L = 62,
+ CS_KINT_H = 63,
+ CS_KINT_L = 64,
+ QPSK_SCALE = 65,
+ TLD_OUTCLK_TH = 66,
+ TLD_INCLK_TH = 67,
+ FLD_TH = 68,
+ PLD_OUTLK3 = 69,
+ PLD_OUTLK2 = 70,
+ PLD_OUTLK1 = 71,
+ PLD_OUTLK0 = 72,
+ PLD_INLK3 = 73,
+ PLD_INLK2 = 74,
+ PLD_INLK1 = 75,
+ PLD_INLK0 = 76,
+ PLD_ACC_TIME = 77,
+ SWEEP_PAR = 78,
+ STARTUP_TIME = 79,
+ LOSSLOCK_TH = 80,
+ FEC_LOCK_TM = 81,
+ LOSSLOCK_TM = 82,
+ VIT_ERRPER_H = 83,
+ VIT_ERRPER_M = 84,
+ VIT_ERRPER_L = 85,
+ VIT_SETUP = 86,
+ VIT_REF0 = 87,
+ VIT_REF1 = 88,
+ VIT_REF2 = 89,
+ VIT_REF3 = 90,
+ VIT_REF4 = 91,
+ VIT_REF5 = 92,
+ VIT_REF6 = 93,
+ VIT_MAXERR = 94,
+ BA_SETUPT = 95,
+ OP_CTRL = 96,
+ FEC_SETUP = 97,
+ PROG_SYNC = 98,
+ AFC_SEAR_TH = 99,
+ CSACC_DIF_TH = 100,
+ QPSK_LK_CT = 101,
+ QPSK_ST_CT = 102,
+ MON_CTRL = 103,
+ QPSK_RESET = 104,
+ QPSK_TST_CT = 105,
+ QPSK_TST_ST = 106,
+ TEST_R = 107,
+ AGC_H = 108,
+ AGC_M = 109,
+ AGC_L = 110,
+ FREQ_ERR1_H = 111,
+ FREQ_ERR1_M = 112,
+ FREQ_ERR1_L = 113,
+ FREQ_ERR2_H = 114,
+ FREQ_ERR2_L = 115,
+ SYM_RAT_OP_H = 116,
+ SYM_RAT_OP_L = 117,
+ DESEQC2_INT = 118,
+ DISEQC2_STAT = 119,
+ DISEQC2_FIFO = 120,
+ DISEQC2_CTRL1 = 121,
+ DISEQC2_CTRL2 = 122,
+ MONITOR_H = 123,
+ MONITOR_L = 124,
+ TEST_MODE = 125,
+ ID = 126,
+ CONFIG = 127
+};
+
+enum mt312_model_id {
+ ID_VP310 = 1,
+ ID_MT312 = 3
+};
+
+#endif /* DVB_FRONTENDS_MT312_PRIV */
diff --git a/linux/drivers/media/dvb/frontends/mt352.c b/linux/drivers/media/dvb/frontends/mt352.c
index 58606728b..dfad921dd 100644
--- a/linux/drivers/media/dvb/frontends/mt352.c
+++ b/linux/drivers/media/dvb/frontends/mt352.c
@@ -37,443 +37,90 @@
#include <linux/delay.h>
#include "dvb_frontend.h"
+#include "mt352_priv.h"
#include "mt352.h"
-#define FRONTEND_NAME "dvbfe_mt352"
-
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
-
-static int debug;
-#define MAX_CARDS 4
-static int force_card[MAX_CARDS] = { -1, -1, -1, -1 };
-static int force_card_count = 0;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-#include <linux/version.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
-module_param_array(force_card, int, force_card_count, 0444);
-#else
-module_param_array(force_card, int, &force_card_count, 0444);
-#endif
-MODULE_PARM_DESC(force_card, "Forces the type of each attached mt352 frontend.\n\t"
- "If your card is not autodetected, then you must specify its type here.\n\t"
- "Valid card types are: 0 == AVDVBT771, 1 == TUA6034, 2 == TDTC9251DH01C,\n\t"
- "3 == DVICO FusionHDTV DVB-T1, 4 == DVICO FusionHDTV DVB-T Lite.");
-
struct mt352_state {
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
- struct dvb_frontend_info fe_info;
- int card_type;
-};
-#define mt352_write(ibuf, ilen) \
-do { \
- struct i2c_msg msg = { .addr = I2C_MT352_ADDR, .flags = 0, \
- .buf = ibuf, .len = ilen }; \
- int err = i2c_transfer(i2c, &msg, 1); \
- if (err != 1) { \
- printk(KERN_WARNING \
- "mt352_write() failed (err = %d)!\n", err); \
- return err; \
- } \
-} while (0)
-
-static struct _tuner_info tuner_info [] = {
- {
- .fe_name = "AverMedia DVB-T 771",
- .fe_frequency_min = 174000000,
- .fe_frequency_max = 862000000,
- .fe_frequency_stepsize = 166667,
- .pll_i2c_addr = 0xc2,
- .mt352_init = mt352_init_AVERMEDIA771,
- .mt352_charge_pump = mt352_cp_AVERMEDIA771,
- .mt352_band_select = mt352_bs_AVERMEDIA771
- },
- {
- .fe_name = "Zarlink MT352 + TUA6034 DVB-T",
- .fe_frequency_min = 174000000,
- .fe_frequency_max = 862000000,
- .fe_frequency_stepsize = 166667,
- .pll_i2c_addr = 0xc2,
- .mt352_init = mt352_init_TUA6034,
- .mt352_charge_pump = mt352_cp_TUA6034,
- .mt352_band_select = mt352_bs_TUA6034
- },
- {
- .fe_name = "Zarlink MT352 + Samsung TDTC9251DH01C DVB-T",
- .fe_frequency_min = 474000000,
- .fe_frequency_max = 858000000,
- .fe_frequency_stepsize = 166667,
- .pll_i2c_addr = 0xc2,
- .mt352_init = mt352_init_TDTC9251DH01C,
- .mt352_charge_pump = mt352_cp_TDTC9251DH01C,
- .mt352_band_select = mt352_bs_TDTC9251DH01C
- },
- {
- .fe_name = "DVICO FusionHDTV DVB-T1",
- .fe_frequency_min = 174000000,
- .fe_frequency_max = 862000000,
- .fe_frequency_stepsize = 166667,
- .pll_i2c_addr = 0xc2,
- .mt352_init = mt352_init_DVICODVBT1,
- .mt352_charge_pump = mt352_cp_DVICODVBT1,
- .mt352_band_select = mt352_bs_DVICODVBT1,
- },
- {
- .fe_name = "DVICO FusionHDTV DVB-T Lite",
- .fe_frequency_min = 174000000,
- .fe_frequency_max = 862000000,
- .fe_frequency_stepsize = 166667,
- .pll_i2c_addr = 0xc0,
- .mt352_init = mt352_init_DVICODVBTLITE,
- .mt352_charge_pump = mt352_cp_DVICODVBTLITE,
- .mt352_band_select = mt352_bs_DVICODVBTLITE,
- }
-};
+ struct i2c_adapter* i2c;
-static struct dvb_frontend_info mt352_info_template = {
- .name = "DVB-T Zarlink MT352 demodulator driver",
- .type = FE_OFDM,
-/*
- .frequency_min = 0,
- .frequency_max = 0,
- .frequency_stepsize = 0,
- .frequency_tolerance = 0,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
- .symbol_rate_tolerance = ???,
-*/
- .notifier_delay = 0,
- .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
- FE_CAN_MUTE_TS
-};
+ struct dvb_frontend_ops ops;
-static u8 mt352_reset [] = { RESET, 0x80 };
-static u8 mt352_adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
-static u8 mt352_capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+ /* configuration settings */
+ const struct mt352_config* config;
-static int mt352_init_TUA6034(struct i2c_adapter *i2c)
-{
- static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
- static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x19, 0xa0 };
-
- mt352_write(mt352_clock_config, sizeof(mt352_clock_config));
- udelay(2000);
- mt352_write(mt352_reset, sizeof(mt352_reset));
- mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
- mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg));
- mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
- return 0;
-}
-
-static int mt352_init_AVERMEDIA771(struct i2c_adapter *i2c)
-{
- static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
- static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x10, 0x23, 0x00, 0xFF, 0xFF,
- 0x00, 0xFF, 0x00, 0x40, 0x40 };
- static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
- static u8 mt352_capt_range_cfg[] = { CAPT_RANGE, 0x32 };
-
- mt352_write(mt352_clock_config, sizeof(mt352_clock_config));
- udelay(2000);
- mt352_write(mt352_reset, sizeof(mt352_reset));
- mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
- mt352_write(mt352_agc_cfg,sizeof(mt352_agc_cfg));
- udelay(2000);
- mt352_write(mt352_av771_extra,sizeof(mt352_av771_extra));
- mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
- return 0;
-}
-
-static int mt352_init_TDTC9251DH01C(struct i2c_adapter *i2c)
-{
- static u8 mt352_clock_config [] = { CLOCK_CTL, 0x10, 0x2d };
- static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x28, 0xa1 };
-
- mt352_write(mt352_clock_config, sizeof(mt352_clock_config));
- udelay(2000);
- mt352_write(mt352_reset, sizeof(mt352_reset));
- mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
- mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg));
- mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
- return 0;
-}
-
-static int mt352_init_DVICODVBT1(struct i2c_adapter *i2c)
-{
- static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
- static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x24, 0x20 };
- static u8 mt352_gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
-
- mt352_write(mt352_clock_config, sizeof(mt352_clock_config));
- udelay(200);
- mt352_write(mt352_reset, sizeof(mt352_reset));
- mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
- mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg));
- mt352_write(mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
- mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+ struct dvb_frontend frontend;
+};
- return 0;
-}
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "mt352: " args); \
+ } while (0)
-static int mt352_init_DVICODVBTLITE(struct i2c_adapter *i2c)
+int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
{
- static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x38 };
- static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
- static u8 mt352_gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
-
- mt352_write(mt352_clock_config, sizeof(mt352_clock_config));
- udelay(200);
- mt352_write(mt352_reset, sizeof(mt352_reset));
- mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
- mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg));
- mt352_write(mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
- mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0,
+ .buf = ibuf, .len = ilen };
+ int err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
+ printk(KERN_WARNING
+ "mt352_write() failed (err = %d)!\n", err);
+ return err;
+ }
return 0;
}
-static unsigned char mt352_cp_TUA6034(u32 freq)
-{
- unsigned char cp = 0;
-
- if (freq < 542000000)
- cp = 0xbe;
- else if (freq < 830000000)
- cp = 0xf6;
- else
- cp = 0xfe;
-
- return cp;
-}
-
-static unsigned char mt352_cp_AVERMEDIA771(u32 freq)
-{
- unsigned char cp = 0;
-
- if (freq < 150000000)
- cp = 0xB4;
- else if (freq < 173000000)
- cp = 0xBC;
- else if (freq < 250000000)
- cp = 0xB4;
- else if (freq < 400000000)
- cp = 0xBC;
- else if (freq < 420000000)
- cp = 0xF4;
- else if (freq < 470000000)
- cp = 0xFC;
- else if (freq < 600000000)
- cp = 0xBC;
- else if (freq < 730000000)
- cp = 0xF4;
- else
- cp = 0xFC;
-
- return cp;
-}
-
-static unsigned char mt352_cp_TDTC9251DH01C(u32 freq)
-{
- return(0xcc);
-}
-
-static unsigned char mt352_cp_DVICODVBT1(u32 freq)
-{
- unsigned char cp = 0;
-
- if (freq < 542000000)
- cp = 0xbc;
- else if (freq < 830000000)
- cp = 0xf4;
- else
- cp = 0xfc;
-
- return cp;
-}
-
-static unsigned char mt352_cp_DVICODVBTLITE(u32 freq)
-{
- unsigned char cp = 0;
-
- if (freq < 542000000)
- cp = 0xb4;
- else if (freq < 771000000)
- cp = 0xbc;
- else
- cp = 0xf4;
-
- return cp;
-}
-
-static unsigned char mt352_bs_TUA6034(u32 freq)
+static u8 mt352_read_register(struct mt352_state* state, u8 reg)
{
- unsigned char bs = 0;
-
- if (freq < 250000000)
- bs = 0x01;
- else
- bs = 0x08;
+ 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 } };
- return bs;
-}
+ ret = i2c_transfer(state->i2c, msg, 2);
-static unsigned char mt352_bs_AVERMEDIA771(u32 freq)
-{
- unsigned char bs = 0;
-
- if (freq < 150000000)
- bs = 0x01;
- else if (freq < 173000000)
- bs = 0x01;
- else if (freq < 250000000)
- bs = 0x02;
- else if (freq < 400000000)
- bs = 0x02;
- else if (freq < 420000000)
- bs = 0x02;
- else if (freq < 470000000)
- bs = 0x02;
- else if (freq < 600000000)
- bs = 0x08;
- else if (freq < 730000000)
- bs = 0x08;
- else
- bs = 0x08;
+ if (ret != 2)
+ printk(KERN_WARNING
+ "%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
- return bs;
+ return b1[0];
}
-static unsigned char mt352_bs_TDTC9251DH01C(u32 freq)
-{
- unsigned char bs = 0;
- if (freq >= 48000000 && freq <= 154000000) /* low band */
- bs = 0x09;
- if (freq >= 161000000 && freq <= 439000000) /* medium band */
- bs = 0x0a;
- if (freq >= 447000000 && freq <= 863000000) /* high band */
- bs = 0x08;
- return bs;
-}
-static unsigned char mt352_bs_DVICODVBT1(u32 freq)
-{
- unsigned char bs = 0;
-
- if (freq == 0) /* power down PLL */
- bs = 0x03;
- else if (freq < 157500000) /* low band */
- bs = 0x01;
- else if (freq < 443250000) /* mid band */
- bs = 0x02;
- else /* high band */
- bs = 0x04;
-
- return bs;
-}
-static unsigned char mt352_bs_DVICODVBTLITE(u32 freq)
-{
- unsigned char bs = 0;
- if (freq == 0) /* power down PLL */
- bs = 0x03;
- else if (freq < 443250000) /* mid band */
- bs = 0x02;
- else /* high band */
- bs = 0x08;
- return bs;
-}
-static u32 mt352_read_eeprom_dword(struct i2c_adapter *i2c, int dword_base)
-{
- int i;
- u32 dword = 0;
- u8 reg, val;
- struct i2c_msg msg[2] = {
- {
- .addr = 0x50,
- .flags = 0,
- .buf = &reg,
- .len = 1
- },
- {
- .addr = 0x50,
- .flags = I2C_M_RD,
- .buf = &val,
- .len = 1
- }
- };
- for (i = 0; i < 4; i++) {
- reg = dword_base + i;
- if (i2c_transfer(i2c, msg, 2) != 2)
- return 0;
- dword = (dword << 8) | val;
- }
- return dword;
-}
-
-static int mt352_init(struct i2c_adapter *i2c, int card_type)
-{
- /**
- * all register write sequence have the register address of the
- * first register in the first byte, thenafter the value to write
- * into this and the following registers.
- *
- *
- * We only write non-default settings, all default settings are
- * restored by the full mt352_reset sequence.
- *
- *
- * The optimal AGC target value and slope might vary from tuner
- * type to tuner type, so check whether you need to adjust this one...
- **/
-
- return(MT352_INIT(i2c));
-}
-
-static int mt352_sleep(struct i2c_adapter *i2c)
+static int mt352_sleep(struct dvb_frontend* fe)
{
static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 };
- mt352_write(mt352_softdown, sizeof(mt352_softdown));
+ mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
return 0;
}
-static int mt352_set_parameters(struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *param,
- int card_type)
+static int mt352_set_parameters(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *param)
{
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
unsigned char buf[14];
unsigned int tps = 0;
struct dvb_ofdm_parameters *op = &param->u.ofdm;
- uint16_t tmp;
int i;
switch (op->code_rate_HP) {
@@ -605,22 +252,7 @@ static int mt352_set_parameters(struct i2c_adapter *i2c,
buf[6] = 0x31; /* INPUT_FREQ_(1|0), 20.48MHz clock, 36.166667MHz IF */
buf[7] = 0x05; /* see MT352 Design Manual page 32 for details */
- buf[8] = PLL_I2C_ADDR;
-
- /**
- * All the following settings are tuner module dependent,
- * check the datasheet...
- */
-
- /* here we assume 1/6MHz == 166.66kHz stepsize */
- #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
- tmp = (((param->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
- buf[9] = msb(tmp); /* CHAN_START_(1|0) */
- buf[10] = lsb(tmp);
-
- buf[11] = MT352_CHARGE_PUMP(param->frequency);
- buf[12] = MT352_BAND_SELECT(param->frequency);
+ state->config->pll_set(fe, param, buf+8);
buf[13] = 0x01; /* TUNER_GO!! */
@@ -628,39 +260,18 @@ static int mt352_set_parameters(struct i2c_adapter *i2c,
* parameters already set. Enhances tuning time and prevents stream
* breakup when retuning the same transponder. */
for (i = 1; i < 13; i++)
- if (buf[i] != mt352_read_register(i2c, i + 0x50)) {
- mt352_write(buf, sizeof(buf));
+ if (buf[i] != mt352_read_register(state, i + 0x50)) {
+ mt352_write(fe, buf, sizeof(buf));
break;
}
return 0;
}
-static u8 mt352_read_register(struct i2c_adapter *i2c, u8 reg)
-{
- int ret;
- u8 b0 [] = { reg };
- u8 b1 [] = { 0 };
- struct i2c_msg msg [] = { { .addr = I2C_MT352_ADDR,
- .flags = 0,
- .buf = b0, .len = 1 },
- { .addr = I2C_MT352_ADDR,
- .flags = I2C_M_RD,
- .buf = b1, .len = 1 } };
-
- ret = i2c_transfer(i2c, msg, 2);
-
- if (ret != 2)
- printk(KERN_WARNING
- "%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
- return b1[0];
-}
-
-
-static int mt352_get_parameters(struct i2c_adapter *i2c,
+static int mt352_get_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
u16 tps;
u16 div;
u8 trl;
@@ -677,7 +288,7 @@ static int mt352_get_parameters(struct i2c_adapter *i2c,
FEC_AUTO
};
- if ( (mt352_read_register(i2c,0x00) & 0xC0) != 0xC0 )
+ if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 )
{
return -EINVAL;
}
@@ -685,9 +296,9 @@ static int mt352_get_parameters(struct i2c_adapter *i2c,
/* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because
* the mt352 sometimes works with the wrong parameters
*/
- tps = (mt352_read_register(i2c, TPS_RECEIVED_1) << 8) | mt352_read_register(i2c, TPS_RECEIVED_0);
- div = (mt352_read_register(i2c, CHAN_START_1) << 8) | mt352_read_register(i2c, CHAN_START_0);
- trl = mt352_read_register(i2c, TRL_NOMINAL_RATE_1);
+ tps = (mt352_read_register(state, TPS_RECEIVED_1) << 8) | mt352_read_register(state, TPS_RECEIVED_0);
+ div = (mt352_read_register(state, CHAN_START_1) << 8) | mt352_read_register(state, CHAN_START_0);
+ trl = mt352_read_register(state, TRL_NOMINAL_RATE_1);
op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
@@ -764,7 +375,7 @@ static int mt352_get_parameters(struct i2c_adapter *i2c,
}
- if (mt352_read_register(i2c, STATUS_2) & 0x02)
+ if (mt352_read_register(state, STATUS_2) & 0x02)
param->inversion = INVERSION_OFF;
else
param->inversion = INVERSION_ON;
@@ -772,270 +383,174 @@ static int mt352_get_parameters(struct i2c_adapter *i2c,
return 0;
}
-
-static int mt352_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- struct mt352_state *state = fe->data;
- struct i2c_adapter *i2c = state->i2c;
- int card_type = state->card_type;
- u8 r,snr;
- fe_status_t *status;
- u16 signal;
- struct dvb_frontend_tune_settings *fe_tune_settings;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy(arg, &state->fe_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- status = arg;
- *status = 0;
- r = mt352_read_register (i2c, STATUS_0);
- if (r & (1 << 4))
- *status = FE_HAS_CARRIER;
- if (r & (1 << 1))
- *status |= FE_HAS_VITERBI;
- if (r & (1 << 5))
- *status |= FE_HAS_LOCK;
-
- r = mt352_read_register (i2c, STATUS_1);
- if (r & (1 << 1))
- *status |= FE_HAS_SYNC;
-
- r = mt352_read_register (i2c, STATUS_3);
- if (r & (1 << 6))
- *status |= FE_HAS_SIGNAL;
-
- break;
-
- case FE_READ_BER:
- *((u32 *) arg) = (mt352_read_register (i2c, RS_ERR_CNT_2) << 16) |
- (mt352_read_register (i2c, RS_ERR_CNT_1) << 8) |
- (mt352_read_register (i2c, RS_ERR_CNT_0));
- break;
-
- case FE_READ_SIGNAL_STRENGTH:
- signal = (mt352_read_register (i2c, AGC_GAIN_3) << 8) |
- (mt352_read_register (i2c, AGC_GAIN_2));
- *((u16*) arg) = ~signal;
- break;
-
- case FE_READ_SNR:
- snr = mt352_read_register (i2c, SNR);
- *((u16*) arg) = (snr << 8) | snr;
- break;
-
- case FE_READ_UNCORRECTED_BLOCKS:
- *(u32*) arg = (mt352_read_register (i2c, RS_UBC_1) << 8) |
- (mt352_read_register (i2c, RS_UBC_0));
- break;
-
- case FE_SET_FRONTEND:
- return mt352_set_parameters (i2c,
- (struct dvb_frontend_parameters *) arg,
- card_type);
-
- case FE_GET_FRONTEND:
- return mt352_get_parameters (i2c,
- (struct dvb_frontend_parameters *) arg);
-
- case FE_GET_TUNE_SETTINGS:
- fe_tune_settings = (struct dvb_frontend_tune_settings *) arg;
- fe_tune_settings->min_delay_ms = 800;
- fe_tune_settings->step_size = 0;
- fe_tune_settings->max_drift = 0;
- break;
-
- case FE_SLEEP:
- return mt352_sleep(i2c);
-
- case FE_INIT:
- /* Only send the initialisation command if the demodulator
- * isn't already enabled. Greatly enhances tuning time. */
- if ((mt352_read_register(i2c, CLOCK_CTL) & 0x10) == 0 ||
- (mt352_read_register(i2c, CONFIG) & 0x20) == 0)
- return mt352_init(i2c, card_type);
- else
- return 0;
-
- default:
- return -EOPNOTSUPP;
- }
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+ u8 r;
+
+ *status = 0;
+ r = mt352_read_register (state, STATUS_0);
+ if (r & (1 << 4))
+ *status = FE_HAS_CARRIER;
+ if (r & (1 << 1))
+ *status |= FE_HAS_VITERBI;
+ if (r & (1 << 5))
+ *status |= FE_HAS_LOCK;
+
+ r = mt352_read_register (state, STATUS_1);
+ if (r & (1 << 1))
+ *status |= FE_HAS_SYNC;
+
+ r = mt352_read_register (state, STATUS_3);
+ if (r & (1 << 6))
+ *status |= FE_HAS_SIGNAL;
return 0;
}
-static struct i2c_client client_template;
-
-static int mt352_attach_adapter(struct i2c_adapter *i2c)
+static int mt352_read_ber(struct dvb_frontend* fe, u32* ber)
{
- static int num_cards_probed;
- struct mt352_state *state;
- struct i2c_client *client;
- static u8 mt352_reset_attach [] = { RESET, 0xC0 };
- int ret;
- int card_type, forced_card = -1;
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
- dprintk("Trying to attach to adapter 0x%x:%s.\n",
- i2c->id, i2c->name);
+ *ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) |
+ (mt352_read_register (state, RS_ERR_CNT_1) << 8) |
+ (mt352_read_register (state, RS_ERR_CNT_0));
- if (mt352_read_register(i2c, CHIP_ID) != ID_MT352)
- return -ENODEV;
+ return 0;
+}
- if ( !(state = kmalloc(sizeof(struct mt352_state), GFP_KERNEL)) )
- return -ENOMEM;
+static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
- memset(state, 0, sizeof(struct mt352_state));
- state->i2c = i2c;
- state->card_type = -1;
- memcpy(&state->fe_info, &mt352_info_template, sizeof(struct dvb_frontend_info));
-
- /* Attempt autodetection of card type based on PCI ID information
- * stored in any on-board EEPROM. */
- switch (mt352_read_eeprom_dword(i2c, 0xFC)) { /* BT878A chipset */
- case 0x07711461:
- state->card_type = CARD_AVDVBT771;
- break;
- case 0xdb1018ac:
- state->card_type = CARD_DVICODVBTLITE;
- break;
- default:
- break;
- }
+ u16 signal = (mt352_read_register (state, AGC_GAIN_3) << 8) |
+ (mt352_read_register (state, AGC_GAIN_2));
- switch (mt352_read_eeprom_dword(i2c, 0x04)) { /* CX2388x chipset */
- case 0xac1800db:
- state->card_type = CARD_DVICODVBT1;
- break;
- default:
- break;
- }
+ *strength = ~signal;
+ return 0;
+}
- if (num_cards_probed < force_card_count)
- forced_card = force_card[num_cards_probed++];
+static int mt352_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
- if (state->card_type == -1 && forced_card < 0) {
- dprintk("Card type not automatically detected. You "
- "must use the 'force_card' module parameter.\n");
- kfree(state);
- return -ENODEV;
- }
+ u8 _snr = mt352_read_register (state, SNR);
+ *snr = (_snr << 8) | _snr;
- if (forced_card >= 0) {
- if (state->card_type >= 0 && forced_card != state->card_type)
- printk(KERN_WARNING FRONTEND_NAME ": Warning, overriding"
- " detected card type.\n");
- state->card_type = forced_card;
- }
+ return 0;
+}
- card_type = state->card_type;
- printk(KERN_INFO FRONTEND_NAME ": Setup for %s\n", FE_NAME);
+static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
- /* set the frontend name and card-specific frequency info */
- strlcpy(state->fe_info.name, FE_NAME, sizeof(state->fe_info.name));
- state->fe_info.frequency_min = FE_FREQ_MIN;
- state->fe_info.frequency_max = FE_FREQ_MAX;
- state->fe_info.frequency_stepsize = FE_FREQ_STEPSIZE;
+ *ucblocks = (mt352_read_register (state, RS_UBC_1) << 8) |
+ (mt352_read_register (state, RS_UBC_0));
- /* Do a "hard" reset */
- mt352_write(mt352_reset_attach, sizeof(mt352_reset_attach));
+ return 0;
+}
- /* Try to intiialise the device */
- if (mt352_init(i2c, card_type) != 0) {
- kfree(state);
- return -ENODEV;
- }
+static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+ fe_tune_settings->min_delay_ms = 800;
+ fe_tune_settings->step_size = 0;
+ fe_tune_settings->max_drift = 0;
- if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) {
- kfree(state);
- return -ENOMEM;
- }
+ return 0;
+}
+
+static int mt352_init(struct dvb_frontend* fe)
+{
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+
+ static u8 mt352_reset_attach [] = { RESET, 0xC0 };
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = i2c;
- client->addr = 0; // XXX
- i2c_set_clientdata(client, state);
+ if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 ||
+ (mt352_read_register(state, CONFIG) & 0x20) == 0) {
- if ((ret = i2c_attach_client(client))) {
- kfree(client);
- kfree(state);
- return ret;
+ /* Do a "hard" reset */
+ mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
+ return state->config->demod_init(fe);
}
return 0;
}
-static int mt352_detach_client(struct i2c_client *client)
+static void mt352_release(struct dvb_frontend* fe)
{
- struct mt352_state *state = i2c_get_clientdata(client);
-
- if (state->dvb)
- dvb_unregister_frontend(mt352_ioctl, state->dvb);
- i2c_detach_client(client);
- kfree(client);
+ struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
kfree(state);
- return 0;
}
-static int mt352_command (struct i2c_client *client, unsigned int cmd, void *arg)
+static struct dvb_frontend_ops mt352_ops;
+
+struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+ struct i2c_adapter* i2c)
{
- struct mt352_state *state = i2c_get_clientdata(client);
- int ret;
+ struct mt352_state* state = NULL;
- switch (cmd) {
- case FE_REGISTER:
- if (!state->dvb) {
- if ((ret = dvb_register_frontend(mt352_ioctl, arg,
- state, &state->fe_info,
- THIS_MODULE)))
- return ret;
- state->dvb = arg;
- }
- break;
- case FE_UNREGISTER:
- if (state->dvb == arg) {
- dvb_unregister_frontend(mt352_ioctl, state->dvb);
- state->dvb = NULL;
- }
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
+ /* allocate memory for the internal state */
+ state = (struct mt352_state*) kmalloc(sizeof(struct mt352_state), GFP_KERNEL);
+ if (state == NULL) goto error;
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_MT352,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = mt352_attach_adapter,
- .detach_client = mt352_detach_client,
- .command = mt352_command,
-};
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+ /* check if the demod is there */
+ if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
-static int __init mt352_module_init(void)
-{
- return i2c_add_driver(&driver);
-}
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
-static void __exit mt352_module_exit(void)
-{
- if (i2c_del_driver(&driver))
- printk(KERN_ERR "mt352: driver deregistration failed.\n");
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init(mt352_module_init);
-module_exit(mt352_module_exit);
+static struct dvb_frontend_ops mt352_ops = {
+
+ .info = {
+ .name = "Zarlink MT352 DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 174000000,
+ .frequency_max = 862000000,
+ .frequency_stepsize = 166667,
+ .frequency_tolerance = 0,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+ FE_CAN_MUTE_TS
+ },
+
+ .release = mt352_release,
+
+ .init = mt352_init,
+ .sleep = mt352_sleep,
+
+ .set_frontend = mt352_set_parameters,
+ .get_frontend = mt352_get_parameters,
+ .get_tune_settings = mt352_get_tune_settings,
+
+ .read_status = mt352_read_status,
+ .read_ber = mt352_read_ber,
+ .read_signal_strength = mt352_read_signal_strength,
+ .read_snr = mt352_read_snr,
+ .read_ucblocks = mt352_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("DVB-T MT352 Zarlink");
+MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver");
MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(mt352_attach);
+EXPORT_SYMBOL(mt352_write);
diff --git a/linux/drivers/media/dvb/frontends/mt352.h b/linux/drivers/media/dvb/frontends/mt352.h
index 5b5fc2da1..635095b49 100644
--- a/linux/drivers/media/dvb/frontends/mt352.h
+++ b/linux/drivers/media/dvb/frontends/mt352.h
@@ -30,145 +30,29 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
*/
-#ifndef _MT352_
-#define _MT352_
+#ifndef MT352_H
+#define MT352_H
-#define I2C_MT352_ADDR 0x0f
-#define ID_MT352 0x13
+#include <linux/dvb/frontend.h>
-#define CARD_AVDVBT771 0x00
-#define CARD_TUA6034 0x01
-#define CARD_TDTC9251DH01C 0x02
-#define CARD_DVICODVBT1 0x03
-#define CARD_DVICODVBTLITE 0x04
+struct mt352_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
-#define msb(x) (((x) >> 8) & 0xff)
-#define lsb(x) ((x) & 0xff)
+ /* Initialise the demodulator and PLL. Cannot be NULL */
+ int (*demod_init)(struct dvb_frontend* fe);
-enum mt352_reg_addr {
- STATUS_0 = 0x00,
- STATUS_1 = 0x01,
- STATUS_2 = 0x02,
- STATUS_3 = 0x03,
- STATUS_4 = 0x04,
- INTERRUPT_0 = 0x05,
- INTERRUPT_1 = 0x06,
- INTERRUPT_2 = 0x07,
- INTERRUPT_3 = 0x08,
- SNR = 0x09,
- VIT_ERR_CNT_2 = 0x0A,
- VIT_ERR_CNT_1 = 0x0B,
- VIT_ERR_CNT_0 = 0x0C,
- RS_ERR_CNT_2 = 0x0D,
- RS_ERR_CNT_1 = 0x0E,
- RS_ERR_CNT_0 = 0x0F,
- RS_UBC_1 = 0x10,
- RS_UBC_0 = 0x11,
- AGC_GAIN_3 = 0x12,
- AGC_GAIN_2 = 0x13,
- AGC_GAIN_1 = 0x14,
- AGC_GAIN_0 = 0x15,
- FREQ_OFFSET_2 = 0x17,
- FREQ_OFFSET_1 = 0x18,
- FREQ_OFFSET_0 = 0x19,
- TIMING_OFFSET_1 = 0x1A,
- TIMING_OFFSET_0 = 0x1B,
- CHAN_FREQ_1 = 0x1C,
- CHAN_FREQ_0 = 0x1D,
- TPS_RECEIVED_1 = 0x1E,
- TPS_RECEIVED_0 = 0x1F,
- TPS_CURRENT_1 = 0x20,
- TPS_CURRENT_0 = 0x21,
- TPS_CELL_ID_1 = 0x22,
- TPS_CELL_ID_0 = 0x23,
- TPS_MISC_DATA_2 = 0x24,
- TPS_MISC_DATA_1 = 0x25,
- TPS_MISC_DATA_0 = 0x26,
- RESET = 0x50,
- TPS_GIVEN_1 = 0x51,
- TPS_GIVEN_0 = 0x52,
- ACQ_CTL = 0x53,
- TRL_NOMINAL_RATE_1 = 0x54,
- TRL_NOMINAL_RATE_0 = 0x55,
- INPUT_FREQ_1 = 0x56,
- INPUT_FREQ_0 = 0x57,
- TUNER_ADDR = 0x58,
- CHAN_START_1 = 0x59,
- CHAN_START_0 = 0x5A,
- CONT_1 = 0x5B,
- CONT_0 = 0x5C,
- TUNER_GO = 0x5D,
- STATUS_EN_0 = 0x5F,
- STATUS_EN_1 = 0x60,
- INTERRUPT_EN_0 = 0x61,
- INTERRUPT_EN_1 = 0x62,
- INTERRUPT_EN_2 = 0x63,
- INTERRUPT_EN_3 = 0x64,
- AGC_TARGET = 0x67,
- AGC_CTL = 0x68,
- CAPT_RANGE = 0x75,
- SNR_SELECT_1 = 0x79,
- SNR_SELECT_0 = 0x7A,
- RS_ERR_PER_1 = 0x7C,
- RS_ERR_PER_0 = 0x7D,
- CHIP_ID = 0x7F,
- CHAN_STOP_1 = 0x80,
- CHAN_STOP_0 = 0x81,
- CHAN_STEP_1 = 0x82,
- CHAN_STEP_0 = 0x83,
- FEC_LOCK_TIME = 0x85,
- OFDM_LOCK_TIME = 0x86,
- ACQ_DELAY = 0x87,
- SCAN_CTL = 0x88,
- CLOCK_CTL = 0x89,
- CONFIG = 0x8A,
- MCLK_RATIO = 0x8B,
- GPP_CTL = 0x8C,
- ADC_CTL_1 = 0x8E,
- ADC_CTL_0 = 0x8F
+ /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings.
+ * byte0: Set to pll i2c address (nonlinux; left shifted by 1)
+ * byte1-4: PLL configuration.
+ */
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf);
};
-struct _tuner_info {
- char *fe_name;
-#define FE_NAME tuner_info[card_type].fe_name
+extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+ struct i2c_adapter* i2c);
- __u32 fe_frequency_min;
-#define FE_FREQ_MIN tuner_info[card_type].fe_frequency_min
+extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen);
- __u32 fe_frequency_max;
-#define FE_FREQ_MAX tuner_info[card_type].fe_frequency_max
-
- __u32 fe_frequency_stepsize; //verificare se u32 e' corretto
-#define FE_FREQ_STEPSIZE tuner_info[card_type].fe_frequency_stepsize
-
- u8 pll_i2c_addr;
-#define PLL_I2C_ADDR tuner_info[card_type].pll_i2c_addr
-
- int (* mt352_init) (struct i2c_adapter *i2c);
-#define MT352_INIT tuner_info[card_type].mt352_init
-
- unsigned char (* mt352_charge_pump) (u32 freq);
-#define MT352_CHARGE_PUMP tuner_info[card_type].mt352_charge_pump
-
- unsigned char (* mt352_band_select) (u32 freq);
-#define MT352_BAND_SELECT tuner_info[card_type].mt352_band_select
-};
-
-static int mt352_init_TUA6034(struct i2c_adapter *i2c);
-static int mt352_init_AVERMEDIA771(struct i2c_adapter *i2c);
-static int mt352_init_TDTC9251DH01C(struct i2c_adapter *i2c);
-static int mt352_init_DVICODVBT1(struct i2c_adapter *i2c);
-static int mt352_init_DVICODVBTLITE(struct i2c_adapter *i2c);
-static unsigned char mt352_cp_TUA6034(u32 freq);
-static unsigned char mt352_cp_AVERMEDIA771(u32 freq);
-static unsigned char mt352_cp_TDTC9251DH01C(u32 freq);
-static unsigned char mt352_cp_DVICODVBT1(u32 freq);
-static unsigned char mt352_cp_DVICODVBTLITE(u32 freq);
-static unsigned char mt352_bs_TUA6034(u32 freq);
-static unsigned char mt352_bs_AVERMEDIA771(u32 freq);
-static unsigned char mt352_bs_TDTC9251DH01C(u32 freq);
-static unsigned char mt352_bs_DVICODVBT1(u32 freq);
-static unsigned char mt352_bs_DVICODVBTLITE(u32 freq);
-static u8 mt352_read_register(struct i2c_adapter *i2c, u8 reg);
-
-#endif /* _MT352_ */
+#endif // MT352_H
diff --git a/linux/drivers/media/dvb/frontends/mt352_priv.h b/linux/drivers/media/dvb/frontends/mt352_priv.h
new file mode 100644
index 000000000..44ad0d4c8
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/mt352_priv.h
@@ -0,0 +1,127 @@
+/*
+ * Driver for Zarlink DVB-T MT352 demodulator
+ *
+ * Written by Holger Waechtler <holger@qanu.de>
+ * and Daniel Mack <daniel@qanu.de>
+ *
+ * AVerMedia AVerTV DVB-T 771 support by
+ * Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ * Support for Samsung TDTC9251DH01C(M) tuner
+ * Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ * Amauri Celani <acelani@essegi.net>
+ *
+ * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
+ * Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ * 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 _MT352_PRIV_
+#define _MT352_PRIV_
+
+#define ID_MT352 0x13
+
+#define msb(x) (((x) >> 8) & 0xff)
+#define lsb(x) ((x) & 0xff)
+
+enum mt352_reg_addr {
+ STATUS_0 = 0x00,
+ STATUS_1 = 0x01,
+ STATUS_2 = 0x02,
+ STATUS_3 = 0x03,
+ STATUS_4 = 0x04,
+ INTERRUPT_0 = 0x05,
+ INTERRUPT_1 = 0x06,
+ INTERRUPT_2 = 0x07,
+ INTERRUPT_3 = 0x08,
+ SNR = 0x09,
+ VIT_ERR_CNT_2 = 0x0A,
+ VIT_ERR_CNT_1 = 0x0B,
+ VIT_ERR_CNT_0 = 0x0C,
+ RS_ERR_CNT_2 = 0x0D,
+ RS_ERR_CNT_1 = 0x0E,
+ RS_ERR_CNT_0 = 0x0F,
+ RS_UBC_1 = 0x10,
+ RS_UBC_0 = 0x11,
+ AGC_GAIN_3 = 0x12,
+ AGC_GAIN_2 = 0x13,
+ AGC_GAIN_1 = 0x14,
+ AGC_GAIN_0 = 0x15,
+ FREQ_OFFSET_2 = 0x17,
+ FREQ_OFFSET_1 = 0x18,
+ FREQ_OFFSET_0 = 0x19,
+ TIMING_OFFSET_1 = 0x1A,
+ TIMING_OFFSET_0 = 0x1B,
+ CHAN_FREQ_1 = 0x1C,
+ CHAN_FREQ_0 = 0x1D,
+ TPS_RECEIVED_1 = 0x1E,
+ TPS_RECEIVED_0 = 0x1F,
+ TPS_CURRENT_1 = 0x20,
+ TPS_CURRENT_0 = 0x21,
+ TPS_CELL_ID_1 = 0x22,
+ TPS_CELL_ID_0 = 0x23,
+ TPS_MISC_DATA_2 = 0x24,
+ TPS_MISC_DATA_1 = 0x25,
+ TPS_MISC_DATA_0 = 0x26,
+ RESET = 0x50,
+ TPS_GIVEN_1 = 0x51,
+ TPS_GIVEN_0 = 0x52,
+ ACQ_CTL = 0x53,
+ TRL_NOMINAL_RATE_1 = 0x54,
+ TRL_NOMINAL_RATE_0 = 0x55,
+ INPUT_FREQ_1 = 0x56,
+ INPUT_FREQ_0 = 0x57,
+ TUNER_ADDR = 0x58,
+ CHAN_START_1 = 0x59,
+ CHAN_START_0 = 0x5A,
+ CONT_1 = 0x5B,
+ CONT_0 = 0x5C,
+ TUNER_GO = 0x5D,
+ STATUS_EN_0 = 0x5F,
+ STATUS_EN_1 = 0x60,
+ INTERRUPT_EN_0 = 0x61,
+ INTERRUPT_EN_1 = 0x62,
+ INTERRUPT_EN_2 = 0x63,
+ INTERRUPT_EN_3 = 0x64,
+ AGC_TARGET = 0x67,
+ AGC_CTL = 0x68,
+ CAPT_RANGE = 0x75,
+ SNR_SELECT_1 = 0x79,
+ SNR_SELECT_0 = 0x7A,
+ RS_ERR_PER_1 = 0x7C,
+ RS_ERR_PER_0 = 0x7D,
+ CHIP_ID = 0x7F,
+ CHAN_STOP_1 = 0x80,
+ CHAN_STOP_0 = 0x81,
+ CHAN_STEP_1 = 0x82,
+ CHAN_STEP_0 = 0x83,
+ FEC_LOCK_TIME = 0x85,
+ OFDM_LOCK_TIME = 0x86,
+ ACQ_DELAY = 0x87,
+ SCAN_CTL = 0x88,
+ CLOCK_CTL = 0x89,
+ CONFIG = 0x8A,
+ MCLK_RATIO = 0x8B,
+ GPP_CTL = 0x8C,
+ ADC_CTL_1 = 0x8E,
+ ADC_CTL_0 = 0x8F
+};
+
+/* here we assume 1/6MHz == 166.66kHz stepsize */
+#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
+
+#endif /* _MT352_PRIV_ */
diff --git a/linux/drivers/media/dvb/frontends/nxt6000.c b/linux/drivers/media/dvb/frontends/nxt6000.c
index 7983b55fd..c0fa123e9 100644
--- a/linux/drivers/media/dvb/frontends/nxt6000.c
+++ b/linux/drivers/media/dvb/frontends/nxt6000.c
@@ -1,12 +1,6 @@
/*
NxtWave Communications - NXT6000 demodulator driver
- This driver currently supports:
-
- Alps TDME7 (Tuner: MITEL SP5659)
- Alps TDED4 (Tuner: TI ALP510, external Nxt6000)
- Comtech DVBT-6k07 (PLL IC: SP5730)
-
Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
@@ -32,216 +26,68 @@
#include <linux/slab.h>
#include "dvb_frontend.h"
+#include "nxt6000_priv.h"
#include "nxt6000.h"
-MODULE_DESCRIPTION("NxtWave NXT6000 DVB demodulator driver");
-MODULE_AUTHOR("Florian Schirmer");
-MODULE_LICENSE("GPL");
-static int debug = 0;
-MODULE_PARM(debug, "i");
-
-static struct dvb_frontend_info nxt6000_info = {
- .name = "NxtWave NXT6000",
- .type = FE_OFDM,
- .frequency_min = 0,
- .frequency_max = 863250000,
- .frequency_stepsize = 62500,
- /*.frequency_tolerance = *//* FIXME: 12% of SR */
- .symbol_rate_min = 0, /* FIXME */
- .symbol_rate_max = 9360000, /* FIXME */
- .symbol_rate_tolerance = 4000,
- .notifier_delay = 0,
- .caps = 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_8_9 | FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO,
-};
-struct nxt6000_config {
- u8 demod_addr;
- u8 tuner_addr;
- u8 tuner_type;
- u8 clock_inversion;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
-};
+struct nxt6000_state {
+
+ struct i2c_adapter* i2c;
-#define TUNER_TYPE_ALP510 0
-#define TUNER_TYPE_SP5659 1
-#define TUNER_TYPE_SP5730 2
+ struct dvb_frontend_ops ops;
-// #define FE2NXT(fe) ((struct nxt6000_config *)((fe)->data))
-#define FREQ2DIV(freq) ((freq + 36166667) / 166667)
+ /* configuration settings */
+ const struct nxt6000_config* config;
+ struct dvb_frontend frontend;
+
+};
+
+static int debug = 0;
#define dprintk if (debug) printk
-static int nxt6000_write(struct i2c_adapter *i2c, u8 addr, u8 reg, u8 data)
+static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
{
u8 buf[] = { reg, data };
- struct i2c_msg msg = {.addr = addr >> 1,.flags = 0,.buf = buf,.len = 2 };
+ struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 };
int ret;
- if ((ret = i2c_transfer(i2c, &msg, 1)) != 1)
- dprintk("nxt6000: nxt6000_write error (.addr = 0x%02X, reg: 0x%02X, data: 0x%02X, ret: %d)\n", addr, reg, data, ret);
+ if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
+ dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret);
return (ret != 1) ? -EFAULT : 0;
}
-static u8 nxt6000_writereg(struct nxt6000_config *nxt, u8 reg, u8 data)
-{
- return nxt6000_write(nxt->i2c, nxt->demod_addr, reg, data);
-}
-
-static u8 nxt6000_read(struct i2c_adapter *i2c, u8 addr, u8 reg)
+static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msgs[] = {
- {.addr = addr >> 1,.flags = 0,.buf = b0,.len = 1},
- {.addr = addr >> 1,.flags = I2C_M_RD,.buf = b1,.len = 1}
+ {.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(i2c, msgs, 2);
+ ret = i2c_transfer(state->i2c, msgs, 2);
if (ret != 2)
- dprintk("nxt6000: nxt6000_read error (.addr = 0x%02X, reg: 0x%02X, ret: %d)\n", addr, reg, ret);
+ dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret);
return b1[0];
}
-static u8 nxt6000_readreg(struct nxt6000_config *nxt, u8 reg)
-{
- return nxt6000_read(nxt->i2c, nxt->demod_addr, reg);
-}
-
-static int pll_test(struct i2c_adapter *i2c, u8 demod_addr, u8 tuner_addr)
-{
- u8 buf [1];
- struct i2c_msg msg = {.addr = tuner_addr >> 1,.flags = I2C_M_RD,.buf = buf,.len = 1 };
- int ret;
-
- nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- ret = i2c_transfer(i2c, &msg, 1);
- nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
-
- return (ret != 1) ? -EFAULT : 0;
-}
-
-static int pll_write(struct i2c_adapter *i2c, u8 demod_addr, u8 tuner_addr, u8 * buf, u8 len)
-{
- struct i2c_msg msg = {.addr = tuner_addr >> 1,.flags = 0,.buf = buf,.len = len };
- int ret;
-
- nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- ret = i2c_transfer(i2c, &msg, 1);
- nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
-
- if (ret != 1)
- dprintk("nxt6000: pll_write error %d\n", ret);
-
- return (ret != 1) ? -EFAULT : 0;
-}
-
-static int sp5659_set_tv_freq(struct nxt6000_config *nxt, u32 freq)
-{
- u8 buf[4];
-
- buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
- buf[1] = FREQ2DIV(freq) & 0xFF;
- buf[2] = (((FREQ2DIV(freq) >> 15) & 0x03) << 5) | 0x85;
-
- if ((freq >= 174000000) && (freq < 230000000))
- buf[3] = 0x82;
- else if ((freq >= 470000000) && (freq < 782000000))
- buf[3] = 0x85;
- else if ((freq >= 782000000) && (freq < 863000000))
- buf[3] = 0xC5;
- else
- return -EINVAL;
-
- return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-}
-
-static int alp510_set_tv_freq(struct nxt6000_config *nxt, u32 freq)
-{
- u8 buf[4];
-
- buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
- buf[1] = FREQ2DIV(freq) & 0xFF;
- buf[2] = 0x85;
-
-#if 0
- if ((freq >= 47000000) && (freq < 153000000))
- buf[3] = 0x01;
- else if ((freq >= 153000000) && (freq < 430000000))
- buf[3] = 0x02;
- else if ((freq >= 430000000) && (freq < 824000000))
- buf[3] = 0x08;
- else if ((freq >= 824000000) && (freq < 863000000))
- buf[3] = 0x88;
- else
- return -EINVAL;
-#else
- if ((freq >= 47000000) && (freq < 153000000))
- buf[3] = 0x01;
- else if ((freq >= 153000000) && (freq < 430000000))
- buf[3] = 0x02;
- else if ((freq >= 430000000) && (freq < 824000000))
- buf[3] = 0x0C;
- else if ((freq >= 824000000) && (freq < 863000000))
- buf[3] = 0x8C;
- else
- return -EINVAL;
-#endif
-
- return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-}
-
-static int sp5730_set_tv_freq(struct nxt6000_config *nxt, u32 freq)
-{
- u8 buf[4];
-
- buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F;
- buf[1] = FREQ2DIV(freq) & 0xFF;
- buf[2] = 0x93;
-
- if ((freq >= 51000000) && (freq < 132100000))
- buf[3] = 0x05;
- else if ((freq >= 132100000) && (freq < 143000000))
- buf[3] = 0x45;
- else if ((freq >= 146000000) && (freq < 349100000))
- buf[3] = 0x06;
- else if ((freq >= 349100000) && (freq < 397100000))
- buf[3] = 0x46;
- else if ((freq >= 397100000) && (freq < 426000000))
- buf[3] = 0x86;
- else if ((freq >= 430000000) && (freq < 659100000))
- buf[3] = 0x03;
- else if ((freq >= 659100000) && (freq < 759100000))
- buf[3] = 0x43;
- else if ((freq >= 759100000) && (freq < 858000000))
- buf[3] = 0x83;
- else
- return -EINVAL;
-
- return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4);
-}
-
-static void nxt6000_reset(struct nxt6000_config *fe)
+static void nxt6000_reset(struct nxt6000_state* state)
{
u8 val;
- val = nxt6000_readreg(fe, OFDM_COR_CTL);
+ val = nxt6000_readreg(state, OFDM_COR_CTL);
- nxt6000_writereg(fe, OFDM_COR_CTL, val & ~COREACT);
- nxt6000_writereg(fe, OFDM_COR_CTL, val | COREACT);
+ nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT);
+ nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT);
}
-static int nxt6000_set_bandwidth(struct nxt6000_config *fe, fe_bandwidth_t bandwidth)
+static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth)
{
u16 nominal_rate;
int result;
@@ -264,43 +110,43 @@ static int nxt6000_set_bandwidth(struct nxt6000_config *fe, fe_bandwidth_t bandw
return -EINVAL;
}
- if ((result = nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0)
+ if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0)
return result;
- return nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
+ return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF);
}
-static int nxt6000_set_guard_interval(struct nxt6000_config *fe, fe_guard_interval_t guard_interval)
+static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval)
{
switch (guard_interval) {
case GUARD_INTERVAL_1_32:
- return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
+ return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
case GUARD_INTERVAL_1_16:
- return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
+ return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
case GUARD_INTERVAL_AUTO:
case GUARD_INTERVAL_1_8:
- return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
+ return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
case GUARD_INTERVAL_1_4:
- return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03));
+ return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03));
default:
return -EINVAL;
}
}
-static int nxt6000_set_inversion(struct nxt6000_config *fe, fe_spectral_inversion_t inversion)
+static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion)
{
switch (inversion) {
case INVERSION_OFF:
- return nxt6000_writereg(fe, OFDM_ITB_CTL, 0x00);
+ return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00);
case INVERSION_ON:
- return nxt6000_writereg(fe, OFDM_ITB_CTL, ITBINV);
+ return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV);
default:
return -EINVAL;
@@ -308,24 +154,24 @@ static int nxt6000_set_inversion(struct nxt6000_config *fe, fe_spectral_inversio
}
}
-static int nxt6000_set_transmission_mode(struct nxt6000_config *fe, fe_transmit_mode_t transmission_mode)
+static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode)
{
int result;
switch (transmission_mode) {
case TRANSMISSION_MODE_2K:
- if ((result = nxt6000_writereg(fe, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(fe, EN_DMD_RACQ) & ~0x03))) < 0)
+ if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
return result;
- return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x04));
+ return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
case TRANSMISSION_MODE_8K:
case TRANSMISSION_MODE_AUTO:
- if ((result = nxt6000_writereg(fe, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(fe, EN_DMD_RACQ) & ~0x03))) < 0)
+ if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0)
return result;
- return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x04));
+ return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04));
default:
return -EINVAL;
@@ -333,35 +179,43 @@ static int nxt6000_set_transmission_mode(struct nxt6000_config *fe, fe_transmit_
}
}
-static void nxt6000_setup(struct nxt6000_config *fe)
+static void nxt6000_setup(struct dvb_frontend* fe)
{
- nxt6000_writereg(fe, RS_COR_SYNC_PARAM, SYNC_PARAM);
- nxt6000_writereg(fe, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01);
- nxt6000_writereg(fe, VIT_COR_CTL, VIT_COR_RESYNC);
- nxt6000_writereg(fe, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(fe, OFDM_COR_CTL) & 0x0F));
- nxt6000_writereg(fe, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02);
- nxt6000_writereg(fe, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW);
- nxt6000_writereg(fe, OFDM_ITB_FREQ_1, 0x06);
- nxt6000_writereg(fe, OFDM_ITB_FREQ_2, 0x31);
- nxt6000_writereg(fe, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04);
- nxt6000_writereg(fe, CAS_FREQ, 0xBB); /* CHECKME */
- nxt6000_writereg(fe, OFDM_SYR_CTL, 1 << 2);
- nxt6000_writereg(fe, OFDM_PPM_CTL_1, PPM256);
- nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_1, 0x49);
- nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, 0x72);
- nxt6000_writereg(fe, ANALOG_CONTROL_0, 1 << 5);
- nxt6000_writereg(fe, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2);
- nxt6000_writereg(fe, DIAG_CONFIG, TB_SET);
-
- if (fe->clock_inversion)
- nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, CLKINVERSION);
+ struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
+
+ nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM);
+ nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01);
+ nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC);
+ nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F));
+ nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02);
+ nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW);
+ nxt6000_writereg(state, OFDM_ITB_FREQ_1, 0x06);
+ nxt6000_writereg(state, OFDM_ITB_FREQ_2, 0x31);
+ nxt6000_writereg(state, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04);
+ nxt6000_writereg(state, CAS_FREQ, 0xBB); /* CHECKME */
+ nxt6000_writereg(state, OFDM_SYR_CTL, 1 << 2);
+ nxt6000_writereg(state, OFDM_PPM_CTL_1, PPM256);
+ nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, 0x49);
+ nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, 0x72);
+ nxt6000_writereg(state, ANALOG_CONTROL_0, 1 << 5);
+ nxt6000_writereg(state, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2);
+ nxt6000_writereg(state, DIAG_CONFIG, TB_SET);
+
+ if (state->config->clock_inversion)
+ nxt6000_writereg(state, SUB_DIAG_MODE_SEL, CLKINVERSION);
else
- nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, 0);
+ nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
- nxt6000_writereg(fe, TS_FORMAT, 0);
+ nxt6000_writereg(state, TS_FORMAT, 0);
+
+ if (state->config->pll_init) {
+ nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
+ state->config->pll_init(fe);
+ nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
+ }
}
-static void nxt6000_dump_status(struct nxt6000_config *fe)
+static void nxt6000_dump_status(struct nxt6000_state *state)
{
u8 val;
@@ -379,12 +233,12 @@ static void nxt6000_dump_status(struct nxt6000_config *fe)
*/
printk("NXT6000 status:");
- val = nxt6000_readreg(fe, RS_COR_STAT);
+ val = nxt6000_readreg(state, RS_COR_STAT);
printk(" DATA DESCR LOCK: %d,", val & 0x01);
printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01);
- val = nxt6000_readreg(fe, VIT_SYNC_STATUS);
+ val = nxt6000_readreg(state, VIT_SYNC_STATUS);
printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01);
@@ -415,7 +269,7 @@ static void nxt6000_dump_status(struct nxt6000_config *fe)
}
- val = nxt6000_readreg(fe, OFDM_COR_STAT);
+ val = nxt6000_readreg(state, OFDM_COR_STAT);
printk(" CHCTrack: %d,", (val >> 7) & 0x01);
printk(" TPSLock: %d,", (val >> 6) & 0x01);
@@ -457,7 +311,7 @@ static void nxt6000_dump_status(struct nxt6000_config *fe)
}
- val = nxt6000_readreg(fe, OFDM_SYR_STAT);
+ val = nxt6000_readreg(state, OFDM_SYR_STAT);
printk(" SYRLock: %d,", (val >> 4) & 0x01);
printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K");
@@ -481,7 +335,7 @@ static void nxt6000_dump_status(struct nxt6000_config *fe)
break;
}
- val = nxt6000_readreg(fe, OFDM_TPS_RCVD_3);
+ val = nxt6000_readreg(state, OFDM_TPS_RCVD_3);
switch ((val >> 4) & 0x07) {
@@ -537,7 +391,7 @@ static void nxt6000_dump_status(struct nxt6000_config *fe)
}
- val = nxt6000_readreg(fe, OFDM_TPS_RCVD_4);
+ val = nxt6000_readreg(state, OFDM_TPS_RCVD_4);
printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K");
@@ -562,288 +416,156 @@ static void nxt6000_dump_status(struct nxt6000_config *fe)
}
/* Strange magic required to gain access to RF_AGC_STATUS */
- nxt6000_readreg(fe, RF_AGC_VAL_1);
- val = nxt6000_readreg(fe, RF_AGC_STATUS);
- val = nxt6000_readreg(fe, RF_AGC_STATUS);
+ nxt6000_readreg(state, RF_AGC_VAL_1);
+ val = nxt6000_readreg(state, RF_AGC_STATUS);
+ val = nxt6000_readreg(state, RF_AGC_STATUS);
printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01);
printk("\n");
}
-static int nxt6000_ioctl(struct dvb_frontend *f, unsigned int cmd, void *arg)
-{
- struct nxt6000_config *fe = (struct nxt6000_config *) f->data;
-
- switch (cmd) {
-
- case FE_GET_INFO:
- memcpy(arg, &nxt6000_info, sizeof(struct dvb_frontend_info));
- return 0;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = (fe_status_t *) arg;
-
- u8 core_status;
-
- *status = 0;
-
- core_status = nxt6000_readreg(fe, OFDM_COR_STAT);
- if (core_status & AGCLOCKED)
- *status |= FE_HAS_SIGNAL;
- if (nxt6000_readreg(fe, OFDM_SYR_STAT) & GI14_SYR_LOCK)
- *status |= FE_HAS_CARRIER;
- if (nxt6000_readreg(fe, VIT_SYNC_STATUS) & VITINSYNC)
- *status |= FE_HAS_VITERBI;
- if (nxt6000_readreg(fe, RS_COR_STAT) & RSCORESTATUS)
- *status |= FE_HAS_SYNC;
- if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)))
- *status |= FE_HAS_LOCK;
- if (debug)
- nxt6000_dump_status(fe);
- return 0;
- }
- case FE_READ_BER:
- {
- u32 *ber = (u32 *) arg;
- *ber = 0;
-
- return 0;
-
- }
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- s16 *signal = (s16 *) arg;
-/*
- *signal=(((signed char)readreg(client, 0x16))+128)<<8;
-*/
- *signal = 0;
- return 0;
-
- }
-
- case FE_READ_SNR:
- {
- s16 *snr = (s16 *) arg;
-/*
- *snr=readreg(client, 0x24)<<8;
- *snr|=readreg(client, 0x25);
-*/
- *snr = 0;
- break;
- }
-
- case FE_READ_UNCORRECTED_BLOCKS:
- {
- u32 *ublocks = (u32 *) arg;
-
- *ublocks = 0;
- break;
- }
-
- case FE_INIT:
- nxt6000_reset(fe);
- nxt6000_setup(fe);
- break;
-
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *param = (struct dvb_frontend_parameters *) arg;
- int result;
+static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ u8 core_status;
+ struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
- switch (fe->tuner_type) {
+ *status = 0;
- case TUNER_TYPE_ALP510:
- if ((result = alp510_set_tv_freq(fe, param->frequency)) < 0)
- return result;
- break;
+ core_status = nxt6000_readreg(state, OFDM_COR_STAT);
- case TUNER_TYPE_SP5659:
- if ((result = sp5659_set_tv_freq(fe, param->frequency)) < 0)
- return result;
- break;
+ if (core_status & AGCLOCKED)
+ *status |= FE_HAS_SIGNAL;
- case TUNER_TYPE_SP5730:
- if ((result = sp5730_set_tv_freq(fe, param->frequency)) < 0)
- return result;
- break;
+ if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK)
+ *status |= FE_HAS_CARRIER;
- default:
- return -EFAULT;
+ if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC)
+ *status |= FE_HAS_VITERBI;
- }
+ if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS)
+ *status |= FE_HAS_SYNC;
- if ((result = nxt6000_set_bandwidth(fe, param->u.ofdm.bandwidth)) < 0)
- return result;
- if ((result = nxt6000_set_guard_interval(fe, param->u.ofdm.guard_interval)) < 0)
- return result;
- if ((result = nxt6000_set_transmission_mode(fe, param->u.ofdm.transmission_mode)) < 0)
- return result;
- if ((result = nxt6000_set_inversion(fe, param->inversion)) < 0)
- return result;
+ if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)))
+ *status |= FE_HAS_LOCK;
- break;
- }
-
- default:
- return -EOPNOTSUPP;
- }
+ if (debug)
+ nxt6000_dump_status(state);
return 0;
}
-static u8 demod_addr_tbl[] = { 0x14, 0x18, 0x24, 0x28 };
-
-static struct i2c_client client_template;
-
-static int attach_adapter(struct i2c_adapter *adapter)
+static int nxt6000_init(struct dvb_frontend* fe)
{
- struct i2c_client *client;
- struct nxt6000_config *nxt;
- u8 addr_nr;
- int ret;
-
- if ((nxt = kmalloc(sizeof(struct nxt6000_config), GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- memset(nxt, 0, sizeof(*nxt));
- nxt->i2c = adapter;
-
- for (addr_nr = 0; addr_nr < sizeof(demod_addr_tbl); addr_nr++) {
+ struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
- if (nxt6000_read(adapter, demod_addr_tbl[addr_nr], OFDM_MSC_REV) != NXT6000ASICDEVICE)
- continue;
+ nxt6000_reset(state);
+ nxt6000_setup(fe);
- if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC0) == 0) {
- nxt->tuner_addr = 0xC0;
- nxt->tuner_type = TUNER_TYPE_ALP510;
- nxt->clock_inversion = 1;
-
- dprintk("nxt6000: detected TI ALP510 tuner at 0x%02X\n", nxt->tuner_addr);
-
- } else if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC2) == 0) {
- nxt->tuner_addr = 0xC2;
- nxt->tuner_type = TUNER_TYPE_SP5659;
- nxt->clock_inversion = 0;
+ return 0;
+}
- dprintk("nxt6000: detected MITEL SP5659 tuner at 0x%02X\n", nxt->tuner_addr);
- } else if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC0) == 0) {
- nxt->tuner_addr = 0xC0;
- nxt->tuner_type = TUNER_TYPE_SP5730;
- nxt->clock_inversion = 0;
+static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
+{
+ struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
+ int result;
- dprintk("nxt6000: detected SP5730 tuner at 0x%02X\n", nxt->tuner_addr);
+ nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
+ state->config->pll_set(fe, param);
+ nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
- } else {
- printk("nxt6000: unable to detect tuner\n");
- continue;
- }
- }
+ if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
+ return result;
+ if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0)
+ return result;
+ if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0)
+ return result;
+ if ((result = nxt6000_set_inversion(state, param->inversion)) < 0)
+ return result;
- if (addr_nr == sizeof(demod_addr_tbl)) {
- kfree(nxt);
- return -ENODEV;
- }
+ return 0;
+}
- nxt->demod_addr = demod_addr_tbl[addr_nr];
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- kfree(nxt);
- return -ENOMEM;
- }
+static void nxt6000_release(struct dvb_frontend* fe)
+{
+ struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv;
+ kfree(state);
+}
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = demod_addr_tbl[addr_nr];
- i2c_set_clientdata(client, (void *) nxt);
+static struct dvb_frontend_ops nxt6000_ops;
- ret = i2c_attach_client(client);
- if (ret)
- goto out;
+struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct nxt6000_state* state = NULL;
- BUG_ON(!nxt->dvb);
+ /* allocate memory for the internal state */
+ state = (struct nxt6000_state*) kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL);
+ if (state == NULL) goto error;
- ret = dvb_register_frontend(nxt6000_ioctl, nxt->dvb, nxt, &nxt6000_info, THIS_MODULE);
- if (ret) {
- i2c_detach_client(client);
- goto out;
- }
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
- ret = 0;
-out:
- kfree(client);
- kfree(nxt);
- return ret;
-}
+ /* check if the demod is there */
+ if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
-static int detach_client(struct i2c_client *client)
-{
- struct nxt6000_config *state = (struct nxt6000_config *) i2c_get_clientdata(client);
- dvb_unregister_frontend(nxt6000_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
- return 0;
-}
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct nxt6000_config *state = (struct nxt6000_config *) i2c_get_clientdata(client);
-
- switch (cmd) {
- case FE_REGISTER:{
- state->dvb = (struct dvb_adapter *) arg;
- break;
- }
- case FE_UNREGISTER:{
- state->dvb = NULL;
- break;
- }
- default:
- return -EOPNOTSUPP;
- }
- return 0;
+error:
+ if (state) kfree(state);
+ return NULL;
}
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = "nxt6000",
- .id = I2C_DRIVERID_DVBFE_NXT6000,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
+static struct dvb_frontend_ops nxt6000_ops = {
+
+ .info = {
+ .name = "NxtWave NXT6000 DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 0,
+ .frequency_max = 863250000,
+ .frequency_stepsize = 62500,
+ /*.frequency_tolerance = *//* FIXME: 12% of SR */
+ .symbol_rate_min = 0, /* FIXME */
+ .symbol_rate_max = 9360000, /* FIXME */
+ .symbol_rate_tolerance = 4000,
+ .caps = 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_8_9 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = nxt6000_release,
+
+ .init = nxt6000_init,
+
+ .set_frontend = nxt6000_set_frontend,
+
+ .read_status = nxt6000_read_status,
};
-static struct i2c_client client_template = {
- I2C_DEVNAME("nxt6000"),
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-static __init int nxt6000_init(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static __exit void nxt6000_exit(void)
-{
- if (i2c_del_driver(&driver))
- printk("nxt6000: driver deregistration failed\n");
-}
+MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver");
+MODULE_AUTHOR("Florian Schirmer");
+MODULE_LICENSE("GPL");
-module_init(nxt6000_init);
-module_exit(nxt6000_exit);
+EXPORT_SYMBOL(nxt6000_attach);
diff --git a/linux/drivers/media/dvb/frontends/nxt6000.h b/linux/drivers/media/dvb/frontends/nxt6000.h
index 64b1a89b2..b7d9bead3 100644
--- a/linux/drivers/media/dvb/frontends/nxt6000.h
+++ b/linux/drivers/media/dvb/frontends/nxt6000.h
@@ -1,265 +1,43 @@
/*
- * Public Include File for DRV6000 users
- * (ie. NxtWave Communications - NXT6000 demodulator driver)
- *
- * Copyright (C) 2001 NxtWave Communications, Inc.
- *
- */
+ NxtWave Communications - NXT6000 demodulator driver
-/* Nxt6000 Register Addresses and Bit Masks */
+ Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org>
+ Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au>
-/* Maximum Register Number */
-#define MAXNXT6000REG (0x9A)
+ 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.
-/* 0x1B A_VIT_BER_0 aka 0x3A */
-#define A_VIT_BER_0 (0x1B)
+ 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.
-/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */
-#define A_VIT_BER_TIMER_0 (0x1D)
+ 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.
+*/
-/* 0x21 RS_COR_STAT */
-#define RS_COR_STAT (0x21)
-#define RSCORESTATUS (0x03)
+#ifndef NXT6000_H
+#define NXT6000_H
-/* 0x22 RS_COR_INTEN */
-#define RS_COR_INTEN (0x22)
+#include <linux/dvb/frontend.h>
-/* 0x23 RS_COR_INSTAT */
-#define RS_COR_INSTAT (0x23)
-#define INSTAT_ERROR (0x04)
-#define LOCK_LOSS_BITS (0x03)
+struct nxt6000_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
-/* 0x24 RS_COR_SYNC_PARAM */
-#define RS_COR_SYNC_PARAM (0x24)
-#define SYNC_PARAM (0x03)
+ /* should clock inversion be used? */
+ u8 clock_inversion:1;
-/* 0x25 BER_CTRL */
-#define BER_CTRL (0x25)
-#define BER_ENABLE (0x02)
-#define BER_RESET (0x01)
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
-/* 0x26 BER_PAY */
-#define BER_PAY (0x26)
+extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+ struct i2c_adapter* i2c);
-/* 0x27 BER_PKT_L */
-#define BER_PKT_L (0x27)
-#define BER_PKTOVERFLOW (0x80)
-
-/* 0x30 VIT_COR_CTL */
-#define VIT_COR_CTL (0x30)
-#define BER_CONTROL (0x02)
-#define VIT_COR_MASK (0x82)
-#define VIT_COR_RESYNC (0x80)
-
-
-/* 0x32 VIT_SYNC_STATUS */
-#define VIT_SYNC_STATUS (0x32)
-#define VITINSYNC (0x80)
-
-/* 0x33 VIT_COR_INTEN */
-#define VIT_COR_INTEN (0x33)
-#define GLOBAL_ENABLE (0x80)
-
-/* 0x34 VIT_COR_INTSTAT */
-#define VIT_COR_INTSTAT (0x34)
-#define BER_DONE (0x08)
-#define BER_OVERFLOW (0x10)
-
- /* 0x38 OFDM_BERTimer *//* Use the alias registers */
-#define A_VIT_BER_TIMER_0 (0x1D)
-
- /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */
-#define A_VIT_BER_0 (0x1B)
-
-/* 0x40 OFDM_COR_CTL */
-#define OFDM_COR_CTL (0x40)
-#define COREACT (0x20)
-#define HOLDSM (0x10)
-#define WAIT_AGC (0x02)
-#define WAIT_SYR (0x03)
-
-/* 0x41 OFDM_COR_STAT */
-#define OFDM_COR_STAT (0x41)
-#define COR_STATUS (0x0F)
-#define MONITOR_TPS (0x06)
-#define TPSLOCKED (0x40)
-#define AGCLOCKED (0x10)
-
-/* 0x42 OFDM_COR_INTEN */
-#define OFDM_COR_INTEN (0x42)
-#define TPSRCVBAD (0x04)
-#define TPSRCVCHANGED (0x02)
-#define TPSRCVUPDATE (0x01)
-
-/* 0x43 OFDM_COR_INSTAT */
-#define OFDM_COR_INSTAT (0x43)
-
-/* 0x44 OFDM_COR_MODEGUARD */
-#define OFDM_COR_MODEGUARD (0x44)
-#define FORCEMODE (0x08)
-#define FORCEMODE8K (0x04)
-
-/* 0x45 OFDM_AGC_CTL */
-#define OFDM_AGC_CTL (0x45)
-#define INITIAL_AGC_BW (0x08)
-#define AGCNEG (0x02)
-#define AGCLAST (0x10)
-
-/* 0x48 OFDM_AGC_TARGET */
-#define OFDM_AGC_TARGET (0x48)
-#define OFDM_AGC_TARGET_DEFAULT (0x28)
-#define OFDM_AGC_TARGET_IMPULSE (0x38)
-
-/* 0x49 OFDM_AGC_GAIN_1 */
-#define OFDM_AGC_GAIN_1 (0x49)
-
-/* 0x4B OFDM_ITB_CTL */
-#define OFDM_ITB_CTL (0x4B)
-#define ITBINV (0x01)
-
-/* 0x4C OFDM_ITB_FREQ_1 */
-#define OFDM_ITB_FREQ_1 (0x4C)
-
-/* 0x4D OFDM_ITB_FREQ_2 */
-#define OFDM_ITB_FREQ_2 (0x4D)
-
-/* 0x4E OFDM_CAS_CTL */
-#define OFDM_CAS_CTL (0x4E)
-#define ACSDIS (0x40)
-#define CCSEN (0x80)
-
-/* 0x4F CAS_FREQ */
-#define CAS_FREQ (0x4F)
-
-/* 0x51 OFDM_SYR_CTL */
-#define OFDM_SYR_CTL (0x51)
-#define SIXTH_ENABLE (0x80)
-#define SYR_TRACKING_DISABLE (0x01)
-
-/* 0x52 OFDM_SYR_STAT */
-#define OFDM_SYR_STAT (0x52)
-#define GI14_2K_SYR_LOCK (0x13)
-#define GI14_8K_SYR_LOCK (0x17)
-#define GI14_SYR_LOCK (0x10)
-
-/* 0x55 OFDM_SYR_OFFSET_1 */
-#define OFDM_SYR_OFFSET_1 (0x55)
-
-/* 0x56 OFDM_SYR_OFFSET_2 */
-#define OFDM_SYR_OFFSET_2 (0x56)
-
-/* 0x58 OFDM_SCR_CTL */
-#define OFDM_SCR_CTL (0x58)
-#define SYR_ADJ_DECAY_MASK (0x70)
-#define SYR_ADJ_DECAY (0x30)
-
-/* 0x59 OFDM_PPM_CTL_1 */
-#define OFDM_PPM_CTL_1 (0x59)
-#define PPMMAX_MASK (0x30)
-#define PPM256 (0x30)
-
-/* 0x5B OFDM_TRL_NOMINALRATE_1 */
-#define OFDM_TRL_NOMINALRATE_1 (0x5B)
-
-/* 0x5C OFDM_TRL_NOMINALRATE_2 */
-#define OFDM_TRL_NOMINALRATE_2 (0x5C)
-
-/* 0x5D OFDM_TRL_TIME_1 */
-#define OFDM_TRL_TIME_1 (0x5D)
-
-/* 0x60 OFDM_CRL_FREQ_1 */
-#define OFDM_CRL_FREQ_1 (0x60)
-
-/* 0x63 OFDM_CHC_CTL_1 */
-#define OFDM_CHC_CTL_1 (0x63)
-#define MANMEAN1 (0xF0);
-#define CHCFIR (0x01)
-
-/* 0x64 OFDM_CHC_SNR */
-#define OFDM_CHC_SNR (0x64)
-
-/* 0x65 OFDM_BDI_CTL */
-#define OFDM_BDI_CTL (0x65)
-#define LP_SELECT (0x02)
-
-/* 0x67 OFDM_TPS_RCVD_1 */
-#define OFDM_TPS_RCVD_1 (0x67)
-#define TPSFRAME (0x03)
-
-/* 0x68 OFDM_TPS_RCVD_2 */
-#define OFDM_TPS_RCVD_2 (0x68)
-
-/* 0x69 OFDM_TPS_RCVD_3 */
-#define OFDM_TPS_RCVD_3 (0x69)
-
-/* 0x6A OFDM_TPS_RCVD_4 */
-#define OFDM_TPS_RCVD_4 (0x6A)
-
-/* 0x6B OFDM_TPS_RESERVED_1 */
-#define OFDM_TPS_RESERVED_1 (0x6B)
-
-/* 0x6C OFDM_TPS_RESERVED_2 */
-#define OFDM_TPS_RESERVED_2 (0x6C)
-
-/* 0x73 OFDM_MSC_REV */
-#define OFDM_MSC_REV (0x73)
-
-/* 0x76 OFDM_SNR_CARRIER_2 */
-#define OFDM_SNR_CARRIER_2 (0x76)
-#define MEAN_MASK (0x80)
-#define MEANBIT (0x80)
-
-/* 0x80 ANALOG_CONTROL_0 */
-#define ANALOG_CONTROL_0 (0x80)
-#define POWER_DOWN_ADC (0x40)
-
-/* 0x81 ENABLE_TUNER_IIC */
-#define ENABLE_TUNER_IIC (0x81)
-#define ENABLE_TUNER_BIT (0x01)
-
-/* 0x82 EN_DMD_RACQ */
-#define EN_DMD_RACQ (0x82)
-#define EN_DMD_RACQ_REG_VAL (0x81)
-#define EN_DMD_RACQ_REG_VAL_14 (0x01)
-
-/* 0x84 SNR_COMMAND */
-#define SNR_COMMAND (0x84)
-#define SNRStat (0x80)
-
-/* 0x85 SNRCARRIERNUMBER_LSB */
-#define SNRCARRIERNUMBER_LSB (0x85)
-
-/* 0x87 SNRMINTHRESHOLD_LSB */
-#define SNRMINTHRESHOLD_LSB (0x87)
-
-/* 0x89 SNR_PER_CARRIER_LSB */
-#define SNR_PER_CARRIER_LSB (0x89)
-
-/* 0x8B SNRBELOWTHRESHOLD_LSB */
-#define SNRBELOWTHRESHOLD_LSB (0x8B)
-
-/* 0x91 RF_AGC_VAL_1 */
-#define RF_AGC_VAL_1 (0x91)
-
-/* 0x92 RF_AGC_STATUS */
-#define RF_AGC_STATUS (0x92)
-
-/* 0x98 DIAG_CONFIG */
-#define DIAG_CONFIG (0x98)
-#define DIAG_MASK (0x70)
-#define TB_SET (0x10)
-#define TRAN_SELECT (0x07)
-#define SERIAL_SELECT (0x01)
-
-/* 0x99 SUB_DIAG_MODE_SEL */
-#define SUB_DIAG_MODE_SEL (0x99)
-#define CLKINVERSION (0x01)
-
-/* 0x9A TS_FORMAT */
-#define TS_FORMAT (0x9A)
-#define ERROR_SENSE (0x08)
-#define VALID_SENSE (0x04)
-#define SYNC_SENSE (0x02)
-#define GATED_CLOCK (0x01)
-
-#define NXT6000ASICDEVICE (0x0b)
+#endif // NXT6000_H
diff --git a/linux/drivers/media/dvb/frontends/nxt6000_priv.h b/linux/drivers/media/dvb/frontends/nxt6000_priv.h
new file mode 100644
index 000000000..64b1a89b2
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/nxt6000_priv.h
@@ -0,0 +1,265 @@
+/*
+ * Public Include File for DRV6000 users
+ * (ie. NxtWave Communications - NXT6000 demodulator driver)
+ *
+ * Copyright (C) 2001 NxtWave Communications, Inc.
+ *
+ */
+
+/* Nxt6000 Register Addresses and Bit Masks */
+
+/* Maximum Register Number */
+#define MAXNXT6000REG (0x9A)
+
+/* 0x1B A_VIT_BER_0 aka 0x3A */
+#define A_VIT_BER_0 (0x1B)
+
+/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */
+#define A_VIT_BER_TIMER_0 (0x1D)
+
+/* 0x21 RS_COR_STAT */
+#define RS_COR_STAT (0x21)
+#define RSCORESTATUS (0x03)
+
+/* 0x22 RS_COR_INTEN */
+#define RS_COR_INTEN (0x22)
+
+/* 0x23 RS_COR_INSTAT */
+#define RS_COR_INSTAT (0x23)
+#define INSTAT_ERROR (0x04)
+#define LOCK_LOSS_BITS (0x03)
+
+/* 0x24 RS_COR_SYNC_PARAM */
+#define RS_COR_SYNC_PARAM (0x24)
+#define SYNC_PARAM (0x03)
+
+/* 0x25 BER_CTRL */
+#define BER_CTRL (0x25)
+#define BER_ENABLE (0x02)
+#define BER_RESET (0x01)
+
+/* 0x26 BER_PAY */
+#define BER_PAY (0x26)
+
+/* 0x27 BER_PKT_L */
+#define BER_PKT_L (0x27)
+#define BER_PKTOVERFLOW (0x80)
+
+/* 0x30 VIT_COR_CTL */
+#define VIT_COR_CTL (0x30)
+#define BER_CONTROL (0x02)
+#define VIT_COR_MASK (0x82)
+#define VIT_COR_RESYNC (0x80)
+
+
+/* 0x32 VIT_SYNC_STATUS */
+#define VIT_SYNC_STATUS (0x32)
+#define VITINSYNC (0x80)
+
+/* 0x33 VIT_COR_INTEN */
+#define VIT_COR_INTEN (0x33)
+#define GLOBAL_ENABLE (0x80)
+
+/* 0x34 VIT_COR_INTSTAT */
+#define VIT_COR_INTSTAT (0x34)
+#define BER_DONE (0x08)
+#define BER_OVERFLOW (0x10)
+
+ /* 0x38 OFDM_BERTimer *//* Use the alias registers */
+#define A_VIT_BER_TIMER_0 (0x1D)
+
+ /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */
+#define A_VIT_BER_0 (0x1B)
+
+/* 0x40 OFDM_COR_CTL */
+#define OFDM_COR_CTL (0x40)
+#define COREACT (0x20)
+#define HOLDSM (0x10)
+#define WAIT_AGC (0x02)
+#define WAIT_SYR (0x03)
+
+/* 0x41 OFDM_COR_STAT */
+#define OFDM_COR_STAT (0x41)
+#define COR_STATUS (0x0F)
+#define MONITOR_TPS (0x06)
+#define TPSLOCKED (0x40)
+#define AGCLOCKED (0x10)
+
+/* 0x42 OFDM_COR_INTEN */
+#define OFDM_COR_INTEN (0x42)
+#define TPSRCVBAD (0x04)
+#define TPSRCVCHANGED (0x02)
+#define TPSRCVUPDATE (0x01)
+
+/* 0x43 OFDM_COR_INSTAT */
+#define OFDM_COR_INSTAT (0x43)
+
+/* 0x44 OFDM_COR_MODEGUARD */
+#define OFDM_COR_MODEGUARD (0x44)
+#define FORCEMODE (0x08)
+#define FORCEMODE8K (0x04)
+
+/* 0x45 OFDM_AGC_CTL */
+#define OFDM_AGC_CTL (0x45)
+#define INITIAL_AGC_BW (0x08)
+#define AGCNEG (0x02)
+#define AGCLAST (0x10)
+
+/* 0x48 OFDM_AGC_TARGET */
+#define OFDM_AGC_TARGET (0x48)
+#define OFDM_AGC_TARGET_DEFAULT (0x28)
+#define OFDM_AGC_TARGET_IMPULSE (0x38)
+
+/* 0x49 OFDM_AGC_GAIN_1 */
+#define OFDM_AGC_GAIN_1 (0x49)
+
+/* 0x4B OFDM_ITB_CTL */
+#define OFDM_ITB_CTL (0x4B)
+#define ITBINV (0x01)
+
+/* 0x4C OFDM_ITB_FREQ_1 */
+#define OFDM_ITB_FREQ_1 (0x4C)
+
+/* 0x4D OFDM_ITB_FREQ_2 */
+#define OFDM_ITB_FREQ_2 (0x4D)
+
+/* 0x4E OFDM_CAS_CTL */
+#define OFDM_CAS_CTL (0x4E)
+#define ACSDIS (0x40)
+#define CCSEN (0x80)
+
+/* 0x4F CAS_FREQ */
+#define CAS_FREQ (0x4F)
+
+/* 0x51 OFDM_SYR_CTL */
+#define OFDM_SYR_CTL (0x51)
+#define SIXTH_ENABLE (0x80)
+#define SYR_TRACKING_DISABLE (0x01)
+
+/* 0x52 OFDM_SYR_STAT */
+#define OFDM_SYR_STAT (0x52)
+#define GI14_2K_SYR_LOCK (0x13)
+#define GI14_8K_SYR_LOCK (0x17)
+#define GI14_SYR_LOCK (0x10)
+
+/* 0x55 OFDM_SYR_OFFSET_1 */
+#define OFDM_SYR_OFFSET_1 (0x55)
+
+/* 0x56 OFDM_SYR_OFFSET_2 */
+#define OFDM_SYR_OFFSET_2 (0x56)
+
+/* 0x58 OFDM_SCR_CTL */
+#define OFDM_SCR_CTL (0x58)
+#define SYR_ADJ_DECAY_MASK (0x70)
+#define SYR_ADJ_DECAY (0x30)
+
+/* 0x59 OFDM_PPM_CTL_1 */
+#define OFDM_PPM_CTL_1 (0x59)
+#define PPMMAX_MASK (0x30)
+#define PPM256 (0x30)
+
+/* 0x5B OFDM_TRL_NOMINALRATE_1 */
+#define OFDM_TRL_NOMINALRATE_1 (0x5B)
+
+/* 0x5C OFDM_TRL_NOMINALRATE_2 */
+#define OFDM_TRL_NOMINALRATE_2 (0x5C)
+
+/* 0x5D OFDM_TRL_TIME_1 */
+#define OFDM_TRL_TIME_1 (0x5D)
+
+/* 0x60 OFDM_CRL_FREQ_1 */
+#define OFDM_CRL_FREQ_1 (0x60)
+
+/* 0x63 OFDM_CHC_CTL_1 */
+#define OFDM_CHC_CTL_1 (0x63)
+#define MANMEAN1 (0xF0);
+#define CHCFIR (0x01)
+
+/* 0x64 OFDM_CHC_SNR */
+#define OFDM_CHC_SNR (0x64)
+
+/* 0x65 OFDM_BDI_CTL */
+#define OFDM_BDI_CTL (0x65)
+#define LP_SELECT (0x02)
+
+/* 0x67 OFDM_TPS_RCVD_1 */
+#define OFDM_TPS_RCVD_1 (0x67)
+#define TPSFRAME (0x03)
+
+/* 0x68 OFDM_TPS_RCVD_2 */
+#define OFDM_TPS_RCVD_2 (0x68)
+
+/* 0x69 OFDM_TPS_RCVD_3 */
+#define OFDM_TPS_RCVD_3 (0x69)
+
+/* 0x6A OFDM_TPS_RCVD_4 */
+#define OFDM_TPS_RCVD_4 (0x6A)
+
+/* 0x6B OFDM_TPS_RESERVED_1 */
+#define OFDM_TPS_RESERVED_1 (0x6B)
+
+/* 0x6C OFDM_TPS_RESERVED_2 */
+#define OFDM_TPS_RESERVED_2 (0x6C)
+
+/* 0x73 OFDM_MSC_REV */
+#define OFDM_MSC_REV (0x73)
+
+/* 0x76 OFDM_SNR_CARRIER_2 */
+#define OFDM_SNR_CARRIER_2 (0x76)
+#define MEAN_MASK (0x80)
+#define MEANBIT (0x80)
+
+/* 0x80 ANALOG_CONTROL_0 */
+#define ANALOG_CONTROL_0 (0x80)
+#define POWER_DOWN_ADC (0x40)
+
+/* 0x81 ENABLE_TUNER_IIC */
+#define ENABLE_TUNER_IIC (0x81)
+#define ENABLE_TUNER_BIT (0x01)
+
+/* 0x82 EN_DMD_RACQ */
+#define EN_DMD_RACQ (0x82)
+#define EN_DMD_RACQ_REG_VAL (0x81)
+#define EN_DMD_RACQ_REG_VAL_14 (0x01)
+
+/* 0x84 SNR_COMMAND */
+#define SNR_COMMAND (0x84)
+#define SNRStat (0x80)
+
+/* 0x85 SNRCARRIERNUMBER_LSB */
+#define SNRCARRIERNUMBER_LSB (0x85)
+
+/* 0x87 SNRMINTHRESHOLD_LSB */
+#define SNRMINTHRESHOLD_LSB (0x87)
+
+/* 0x89 SNR_PER_CARRIER_LSB */
+#define SNR_PER_CARRIER_LSB (0x89)
+
+/* 0x8B SNRBELOWTHRESHOLD_LSB */
+#define SNRBELOWTHRESHOLD_LSB (0x8B)
+
+/* 0x91 RF_AGC_VAL_1 */
+#define RF_AGC_VAL_1 (0x91)
+
+/* 0x92 RF_AGC_STATUS */
+#define RF_AGC_STATUS (0x92)
+
+/* 0x98 DIAG_CONFIG */
+#define DIAG_CONFIG (0x98)
+#define DIAG_MASK (0x70)
+#define TB_SET (0x10)
+#define TRAN_SELECT (0x07)
+#define SERIAL_SELECT (0x01)
+
+/* 0x99 SUB_DIAG_MODE_SEL */
+#define SUB_DIAG_MODE_SEL (0x99)
+#define CLKINVERSION (0x01)
+
+/* 0x9A TS_FORMAT */
+#define TS_FORMAT (0x9A)
+#define ERROR_SENSE (0x08)
+#define VALID_SENSE (0x04)
+#define SYNC_SENSE (0x02)
+#define GATED_CLOCK (0x01)
+
+#define NXT6000ASICDEVICE (0x0b)
diff --git a/linux/drivers/media/dvb/frontends/sp8870.c b/linux/drivers/media/dvb/frontends/sp8870.c
new file mode 100644
index 000000000..4a8178d56
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/sp8870.c
@@ -0,0 +1,613 @@
+/*
+ Driver for Spase SP8870 demodulator
+
+ Copyright (C) 1999 Juergen Peitz
+
+ 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.
+
+*/
+/*
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ */
+#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "sp8870.h"
+
+
+struct sp8870_state {
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ const struct sp8870_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* demodulator private data */
+ u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "sp8870: " args); \
+ } while (0)
+
+/* firmware size for sp8870 */
+#define SP8870_FIRMWARE_SIZE 16382
+
+/* starting point for firmware in file 'Sc_main.mc' */
+#define SP8870_FIRMWARE_OFFSET 0x0A
+
+static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data)
+{
+ u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 };
+ int err;
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int sp8870_readreg (struct sp8870_state* state, u16 reg)
+{
+ int ret;
+ u8 b0 [] = { reg >> 8 , reg & 0xff };
+ u8 b1 [] = { 0, 0 };
+ struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
+
+ ret = i2c_transfer (state->i2c, msg, 2);
+
+ if (ret != 2) {
+ dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+ return -1;
+ }
+
+ return (b1[0] << 8 | b1[1]);
+}
+
+static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw)
+{
+ struct i2c_msg msg;
+ char *fw_buf = fw->data;
+ int fw_pos;
+ u8 tx_buf[255];
+ int tx_len;
+ int err = 0;
+
+ dprintk ("%s: ...\n", __FUNCTION__);
+
+ if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
+ return -EINVAL;
+
+ // system controller stop
+ sp8870_writereg(state, 0x0F00, 0x0000);
+
+ // instruction RAM register hiword
+ sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
+
+ // instruction RAM MWR
+ sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
+
+ // do firmware upload
+ fw_pos = SP8870_FIRMWARE_OFFSET;
+ while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
+ tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
+ // write register 0xCF0A
+ tx_buf[0] = 0xCF;
+ tx_buf[1] = 0x0A;
+ memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.buf = tx_buf;
+ msg.len = tx_len + 2;
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ printk("%s: firmware upload failed!\n", __FUNCTION__);
+ printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
+ return err;
+ }
+ fw_pos += tx_len;
+ }
+
+ dprintk ("%s: done!\n", __FUNCTION__);
+ return 0;
+};
+
+static void sp8870_microcontroller_stop (struct sp8870_state* state)
+{
+ sp8870_writereg(state, 0x0F08, 0x000);
+ sp8870_writereg(state, 0x0F09, 0x000);
+
+ // microcontroller STOP
+ sp8870_writereg(state, 0x0F00, 0x000);
+}
+
+static void sp8870_microcontroller_start (struct sp8870_state* state)
+{
+ sp8870_writereg(state, 0x0F08, 0x000);
+ sp8870_writereg(state, 0x0F09, 0x000);
+
+ // microcontroller START
+ sp8870_writereg(state, 0x0F00, 0x001);
+ // not documented but if we don't read 0x0D01 out here
+ // we don't get a correct data valid signal
+ sp8870_readreg(state, 0x0D01);
+}
+
+static int sp8870_read_data_valid_signal(struct sp8870_state* state)
+{
+ return (sp8870_readreg(state, 0x0D02) > 0);
+}
+
+static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+{
+ int known_parameters = 1;
+
+ *reg0xc05 = 0x000;
+
+ switch (p->u.ofdm.constellation) {
+ case QPSK:
+ break;
+ case QAM_16:
+ *reg0xc05 |= (1 << 10);
+ break;
+ case QAM_64:
+ *reg0xc05 |= (2 << 10);
+ break;
+ case QAM_AUTO:
+ known_parameters = 0;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ switch (p->u.ofdm.hierarchy_information) {
+ case HIERARCHY_NONE:
+ break;
+ case HIERARCHY_1:
+ *reg0xc05 |= (1 << 7);
+ break;
+ case HIERARCHY_2:
+ *reg0xc05 |= (2 << 7);
+ break;
+ case HIERARCHY_4:
+ *reg0xc05 |= (3 << 7);
+ break;
+ case HIERARCHY_AUTO:
+ known_parameters = 0;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ switch (p->u.ofdm.code_rate_HP) {
+ case FEC_1_2:
+ break;
+ case FEC_2_3:
+ *reg0xc05 |= (1 << 3);
+ break;
+ case FEC_3_4:
+ *reg0xc05 |= (2 << 3);
+ break;
+ case FEC_5_6:
+ *reg0xc05 |= (3 << 3);
+ break;
+ case FEC_7_8:
+ *reg0xc05 |= (4 << 3);
+ break;
+ case FEC_AUTO:
+ known_parameters = 0;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ if (known_parameters)
+ *reg0xc05 |= (2 << 1); /* use specified parameters */
+ else
+ *reg0xc05 |= (1 << 1); /* enable autoprobing */
+
+ return 0;
+}
+
+static int sp8870_wake_up(struct sp8870_state* state)
+{
+ // enable TS output and interface pins
+ return sp8870_writereg(state, 0xC18, 0x00D);
+}
+
+static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+ int err;
+ u16 reg0xc05;
+
+ if ((err = configure_reg0xc05(p, &reg0xc05)))
+ return err;
+
+ // system controller stop
+ sp8870_microcontroller_stop(state);
+
+ // set tuner parameters
+ sp8870_writereg(state, 0x206, 0x001);
+ state->config->pll_set(fe, p);
+ sp8870_writereg(state, 0x206, 0x000);
+
+ // sample rate correction bit [23..17]
+ sp8870_writereg(state, 0x0319, 0x000A);
+
+ // sample rate correction bit [16..0]
+ sp8870_writereg(state, 0x031A, 0x0AAB);
+
+ // integer carrier offset
+ sp8870_writereg(state, 0x0309, 0x0400);
+
+ // fractional carrier offset
+ sp8870_writereg(state, 0x030A, 0x0000);
+
+ // filter for 6/7/8 Mhz channel
+ if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+ sp8870_writereg(state, 0x0311, 0x0002);
+ else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+ sp8870_writereg(state, 0x0311, 0x0001);
+ else
+ sp8870_writereg(state, 0x0311, 0x0000);
+
+ // scan order: 2k first = 0x0000, 8k first = 0x0001
+ if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
+ sp8870_writereg(state, 0x0338, 0x0000);
+ else
+ sp8870_writereg(state, 0x0338, 0x0001);
+
+ sp8870_writereg(state, 0xc05, reg0xc05);
+
+ // read status reg in order to clear pending irqs
+ sp8870_readreg(state, 0x200);
+
+ // system controller start
+ sp8870_microcontroller_start(state);
+
+ return 0;
+}
+
+static int sp8870_init (struct dvb_frontend* fe)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+ const struct firmware *fw = NULL;
+
+ sp8870_wake_up(state);
+ if (state->initialised) return 0;
+ state->initialised = 1;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+
+ /* request the firmware, this will block until someone uploads it */
+ printk("sp8870: waiting for firmware upload...\n");
+ if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
+ printk("sp8870: no firmware upload (timeout or file not found?)\n");
+ release_firmware(fw);
+ return -EIO;
+ }
+
+ if (sp8870_firmware_upload(state, fw)) {
+ printk("sp8870: writing firmware to device failed\n");
+ release_firmware(fw);
+ return -EIO;
+ }
+
+ /* enable TS output and interface pins */
+ sp8870_writereg(state, 0xc18, 0x00d);
+
+ // system controller stop
+ sp8870_microcontroller_stop(state);
+
+ // ADC mode
+ sp8870_writereg(state, 0x0301, 0x0003);
+
+ // Reed Solomon parity bytes passed to output
+ sp8870_writereg(state, 0x0C13, 0x0001);
+
+ // MPEG clock is suppressed if no valid data
+ sp8870_writereg(state, 0x0C14, 0x0001);
+
+ /* bit 0x010: enable data valid signal */
+ sp8870_writereg(state, 0x0D00, 0x010);
+ sp8870_writereg(state, 0x0D01, 0x000);
+
+ /* setup PLL */
+ if (state->config->pll_init) {
+ sp8870_writereg(state, 0x206, 0x001);
+ state->config->pll_init(fe);
+ sp8870_writereg(state, 0x206, 0x000);
+ }
+
+ return 0;
+}
+
+static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+ int status;
+ int signal;
+
+ *fe_status = 0;
+
+ status = sp8870_readreg (state, 0x0200);
+ if (status < 0)
+ return -EIO;
+
+ signal = sp8870_readreg (state, 0x0303);
+ if (signal < 0)
+ return -EIO;
+
+ if (signal > 0x0F)
+ *fe_status |= FE_HAS_SIGNAL;
+ if (status & 0x08)
+ *fe_status |= FE_HAS_SYNC;
+ if (status & 0x04)
+ *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
+
+ return 0;
+}
+
+static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+ int ret;
+ u32 tmp;
+
+ *ber = 0;
+
+ ret = sp8870_readreg(state, 0xC08);
+ if (ret < 0)
+ return -EIO;
+
+ tmp = ret & 0x3F;
+
+ ret = sp8870_readreg(state, 0xC07);
+ if (ret < 0)
+ return -EIO;
+
+ tmp = ret << 6;
+
+ if (tmp >= 0x3FFF0)
+ tmp = ~0;
+
+ *ber = tmp;
+
+ return 0;
+}
+
+static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+ int ret;
+ u16 tmp;
+
+ *signal = 0;
+
+ ret = sp8870_readreg (state, 0x306);
+ if (ret < 0)
+ return -EIO;
+
+ tmp = ret << 8;
+
+ ret = sp8870_readreg (state, 0x303);
+ if (ret < 0)
+ return -EIO;
+
+ tmp |= ret;
+
+ if (tmp)
+ *signal = 0xFFFF - tmp;
+
+ return 0;
+}
+
+static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+ int ret;
+
+ *ublocks = 0;
+
+ ret = sp8870_readreg(state, 0xC0C);
+ if (ret < 0)
+ return -EIO;
+
+ if (ret == 0xFFFF)
+ ret = ~0;
+
+ *ublocks = ret;
+
+ return 0;
+}
+
+// number of trials to recover from lockup
+#define MAXTRIALS 5
+// maximum checks for data valid signal
+#define MAXCHECKS 100
+
+// only for debugging: counter for detected lockups
+static int lockups = 0;
+// only for debugging: counter for channel switches
+static int switches = 0;
+
+static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+
+ /*
+ The firmware of the sp8870 sometimes locks up after setting frontend parameters.
+ We try to detect this by checking the data valid signal.
+ If it is not set after MAXCHECKS we try to recover the lockup by setting
+ the frontend parameters again.
+ */
+
+ int err = 0;
+ int valid = 0;
+ int trials = 0;
+ int check_count = 0;
+
+ dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency);
+
+ for (trials = 1; trials <= MAXTRIALS; trials++) {
+
+ if ((err = sp8870_set_frontend_parameters(fe, p)))
+ return err;
+
+ for (check_count = 0; check_count < MAXCHECKS; check_count++) {
+// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
+ valid = sp8870_read_data_valid_signal(state);
+ if (valid) {
+ dprintk("%s: delay = %i usec\n",
+ __FUNCTION__, check_count * 10);
+ break;
+ }
+ udelay(10);
+ }
+ if (valid)
+ break;
+ }
+
+ if (!valid) {
+ printk("%s: firmware crash!!!!!!\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ if (debug) {
+ if (valid) {
+ if (trials > 1) {
+ printk("%s: firmware lockup!!!\n", __FUNCTION__);
+ printk("%s: recovered after %i trial(s))\n", __FUNCTION__, trials - 1);
+ lockups++;
+ }
+ }
+ switches++;
+ printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups);
+ }
+
+ return 0;
+}
+
+static int sp8870_sleep(struct dvb_frontend* fe)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+
+ // tristate TS output and disable interface pins
+ return sp8870_writereg(state, 0xC18, 0x000);
+}
+
+static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+ fesettings->min_delay_ms = 350;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
+static void sp8870_release(struct dvb_frontend* fe)
+{
+ struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops sp8870_ops;
+
+struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct sp8870_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct sp8870_state*) kmalloc(sizeof(struct sp8870_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
+ state->initialised = 0;
+
+ /* check if the demod is there */
+ if (sp8870_readreg(state, 0x0200) < 0) goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops sp8870_ops = {
+
+ .info = {
+ .name = "Spase SP8870 DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 470000000,
+ .frequency_max = 860000000,
+ .frequency_stepsize = 166666,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 |
+ FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER
+ },
+
+ .release = sp8870_release,
+
+ .init = sp8870_init,
+ .sleep = sp8870_sleep,
+
+ .set_frontend = sp8870_set_frontend,
+ .get_tune_settings = sp8870_get_tune_settings,
+
+ .read_status = sp8870_read_status,
+ .read_ber = sp8870_read_ber,
+ .read_signal_strength = sp8870_read_signal_strength,
+ .read_ucblocks = sp8870_read_uncorrected_blocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver");
+MODULE_AUTHOR("Juergen Peitz");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(sp8870_attach);
diff --git a/linux/drivers/media/dvb/frontends/sp8870.h b/linux/drivers/media/dvb/frontends/sp8870.h
new file mode 100644
index 000000000..f3b555dbc
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/sp8870.h
@@ -0,0 +1,45 @@
+/*
+ Driver for Spase SP8870 demodulator
+
+ Copyright (C) 1999 Juergen Peitz
+
+ 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 SP8870_H
+#define SP8870_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct sp8870_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+ /* request firmware for device */
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // SP8870_H
diff --git a/linux/drivers/media/dvb/frontends/sp887x.c b/linux/drivers/media/dvb/frontends/sp887x.c
index 335911f79..33b0b3f66 100644
--- a/linux/drivers/media/dvb/frontends/sp887x.c
+++ b/linux/drivers/media/dvb/frontends/sp887x.c
@@ -1,8 +1,8 @@
/*
- Driver for the Microtune 7202D Frontend
+ Driver for the Spase sp887x demodulator
*/
-/*
+/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
* download/extract it, and then copy it to /usr/lib/hotplug/firmware.
@@ -16,74 +16,50 @@
#include <linux/firmware.h>
#include "dvb_frontend.h"
+#include "sp887x.h"
-#define FRONTEND_NAME "dvbfe_sp887x"
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
+struct sp887x_state {
-static int debug;
+ struct i2c_adapter* i2c;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+ struct dvb_frontend_ops ops;
-#if 0
-#define LOG(dir,addr,buf,len) \
- do { \
- int i; \
- printk("%s (%02x):", dir, addr & 0xff); \
- for (i=0; i<len; i++) \
- printk(" 0x%02x,", buf[i] & 0xff); \
- printk("\n"); \
- } while (0)
-#else
-#define LOG(dir,addr,buf,len)
-#endif
-
-static struct dvb_frontend_info sp887x_info = {
- .name = "Microtune MT7202DTF",
- .type = FE_OFDM,
- .frequency_min = 50500000,
- .frequency_max = 858000000,
- .frequency_stepsize = 166666,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
- FE_CAN_RECOVER
-};
+ const struct sp887x_config* config;
-struct sp887x_state {
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
+ struct dvb_frontend frontend;
+
+ /* demodulator private data */
+ u8 initialised:1;
};
-static int i2c_writebytes (struct i2c_adapter *i2c, u8 addr, u8 *buf, u8 len)
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "sp887x: " args); \
+ } while (0)
+
+static int i2c_writebytes (struct sp887x_state* state, u8 *buf, u8 len)
{
- struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = len };
int err;
- LOG("i2c_writebytes", msg.addr, msg.buf, msg.len);
-
- if ((err = i2c_transfer (i2c, &msg, 1)) != 1) {
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
printk ("%s: i2c write error (addr %02x, err == %i)\n",
- __FUNCTION__, addr, err);
+ __FUNCTION__, state->config->demod_address, err);
return -EREMOTEIO;
}
return 0;
}
-static int sp887x_writereg (struct i2c_adapter *i2c, u16 reg, u16 data)
+static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data)
{
u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff };
- struct i2c_msg msg = { .addr = 0x70, .flags = 0, .buf = b0, .len = 4 };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 4 };
int ret;
- LOG("sp887x_writereg", msg.addr, msg.buf, msg.len);
-
- if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) {
+ if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
/**
* in case of soft reset we ignore ACK errors...
*/
@@ -100,61 +76,60 @@ static int sp887x_writereg (struct i2c_adapter *i2c, u16 reg, u16 data)
return 0;
}
-static u16 sp887x_readreg (struct i2c_adapter *i2c, u16 reg)
+static int sp887x_readreg (struct sp887x_state* state, u16 reg)
{
u8 b0 [] = { reg >> 8 , reg & 0xff };
u8 b1 [2];
int ret;
- struct i2c_msg msg[] = {{ .addr = 0x70, .flags = 0, .buf = b0, .len = 2 },
- { .addr = 0x70, .flags = I2C_M_RD, .buf = b1, .len = 2 }};
+ struct i2c_msg msg[] = {{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }};
- LOG("sp887x_readreg (w)", msg[0].addr, msg[0].buf, msg[0].len);
- LOG("sp887x_readreg (r)", msg[1].addr, msg[1].buf, msg[1].len);
-
- if ((ret = i2c_transfer(i2c, msg, 2)) != 2)
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+ return -1;
+ }
return (((b1[0] << 8) | b1[1]) & 0xfff);
}
-static void sp887x_microcontroller_stop (struct i2c_adapter *fe)
+static void sp887x_microcontroller_stop (struct sp887x_state* state)
{
dprintk("%s\n", __FUNCTION__);
- sp887x_writereg(fe, 0xf08, 0x000);
- sp887x_writereg(fe, 0xf09, 0x000);
+ sp887x_writereg(state, 0xf08, 0x000);
+ sp887x_writereg(state, 0xf09, 0x000);
/* microcontroller STOP */
- sp887x_writereg(fe, 0xf00, 0x000);
+ sp887x_writereg(state, 0xf00, 0x000);
}
-static void sp887x_microcontroller_start (struct i2c_adapter *fe)
+static void sp887x_microcontroller_start (struct sp887x_state* state)
{
dprintk("%s\n", __FUNCTION__);
- sp887x_writereg(fe, 0xf08, 0x000);
- sp887x_writereg(fe, 0xf09, 0x000);
+ sp887x_writereg(state, 0xf08, 0x000);
+ sp887x_writereg(state, 0xf09, 0x000);
/* microcontroller START */
- sp887x_writereg(fe, 0xf00, 0x001);
+ sp887x_writereg(state, 0xf00, 0x001);
}
-static void sp887x_setup_agc (struct i2c_adapter *fe)
+static void sp887x_setup_agc (struct sp887x_state* state)
{
/* setup AGC parameters */
dprintk("%s\n", __FUNCTION__);
- sp887x_writereg(fe, 0x33c, 0x054);
- sp887x_writereg(fe, 0x33b, 0x04c);
- sp887x_writereg(fe, 0x328, 0x000);
- sp887x_writereg(fe, 0x327, 0x005);
- sp887x_writereg(fe, 0x326, 0x001);
- sp887x_writereg(fe, 0x325, 0x001);
- sp887x_writereg(fe, 0x324, 0x001);
- sp887x_writereg(fe, 0x318, 0x050);
- sp887x_writereg(fe, 0x317, 0x3fe);
- sp887x_writereg(fe, 0x316, 0x001);
- sp887x_writereg(fe, 0x313, 0x005);
- sp887x_writereg(fe, 0x312, 0x002);
- sp887x_writereg(fe, 0x306, 0x000);
- sp887x_writereg(fe, 0x303, 0x000);
+ sp887x_writereg(state, 0x33c, 0x054);
+ sp887x_writereg(state, 0x33b, 0x04c);
+ sp887x_writereg(state, 0x328, 0x000);
+ sp887x_writereg(state, 0x327, 0x005);
+ sp887x_writereg(state, 0x326, 0x001);
+ sp887x_writereg(state, 0x325, 0x001);
+ sp887x_writereg(state, 0x324, 0x001);
+ sp887x_writereg(state, 0x318, 0x050);
+ sp887x_writereg(state, 0x317, 0x3fe);
+ sp887x_writereg(state, 0x316, 0x001);
+ sp887x_writereg(state, 0x313, 0x005);
+ sp887x_writereg(state, 0x312, 0x002);
+ sp887x_writereg(state, 0x306, 0x000);
+ sp887x_writereg(state, 0x303, 0x000);
}
#define BLOCKSIZE 30
@@ -162,8 +137,9 @@ static void sp887x_setup_agc (struct i2c_adapter *fe)
/**
* load firmware and setup MPEG interface...
*/
-static int sp887x_initial_setup (struct i2c_adapter *fe, const struct firmware *fw)
+static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw)
{
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
u8 buf [BLOCKSIZE+2];
int i;
int fw_size = fw->size;
@@ -178,18 +154,18 @@ static int sp887x_initial_setup (struct i2c_adapter *fe, const struct firmware *
mem = fw->data + 10;
/* soft reset */
- sp887x_writereg(fe, 0xf1a, 0x000);
+ sp887x_writereg(state, 0xf1a, 0x000);
- sp887x_microcontroller_stop (fe);
+ sp887x_microcontroller_stop (state);
printk ("%s: firmware upload... ", __FUNCTION__);
/* setup write pointer to -1 (end of memory) */
/* bit 0x8000 in address is set to enable 13bit mode */
- sp887x_writereg(fe, 0x8f08, 0x1fff);
+ sp887x_writereg(state, 0x8f08, 0x1fff);
/* dummy write (wrap around to start of memory) */
- sp887x_writereg(fe, 0x8f0a, 0x0000);
+ sp887x_writereg(state, 0x8f0a, 0x0000);
for (i = 0; i < FW_SIZE; i += BLOCKSIZE) {
int c = BLOCKSIZE;
@@ -206,7 +182,7 @@ static int sp887x_initial_setup (struct i2c_adapter *fe, const struct firmware *
memcpy(&buf[2], mem + i, c);
- if ((err = i2c_writebytes (fe, 0x70, buf, c+2)) < 0) {
+ if ((err = i2c_writebytes (state, buf, c+2)) < 0) {
printk ("failed.\n");
printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
return err;
@@ -214,61 +190,37 @@ static int sp887x_initial_setup (struct i2c_adapter *fe, const struct firmware *
}
/* don't write RS bytes between packets */
- sp887x_writereg(fe, 0xc13, 0x001);
+ sp887x_writereg(state, 0xc13, 0x001);
/* suppress clock if (!data_valid) */
- sp887x_writereg(fe, 0xc14, 0x000);
+ sp887x_writereg(state, 0xc14, 0x000);
/* setup MPEG interface... */
- sp887x_writereg(fe, 0xc1a, 0x872);
- sp887x_writereg(fe, 0xc1b, 0x001);
- sp887x_writereg(fe, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
- sp887x_writereg(fe, 0xc1a, 0x871);
+ sp887x_writereg(state, 0xc1a, 0x872);
+ sp887x_writereg(state, 0xc1b, 0x001);
+ sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */
+ sp887x_writereg(state, 0xc1a, 0x871);
/* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */
- sp887x_writereg(fe, 0x301, 0x002);
+ sp887x_writereg(state, 0x301, 0x002);
- sp887x_setup_agc(fe);
+ sp887x_setup_agc(state);
/* bit 0x010: enable data valid signal */
- sp887x_writereg(fe, 0xd00, 0x010);
- sp887x_writereg(fe, 0x0d1, 0x000);
+ sp887x_writereg(state, 0xd00, 0x010);
+ sp887x_writereg(state, 0x0d1, 0x000);
+
+ /* setup the PLL */
+ if (state->config->pll_init) {
+ sp887x_writereg(state, 0x206, 0x001);
+ state->config->pll_init(fe);
+ sp887x_writereg(state, 0x206, 0x000);
+ }
printk ("done.\n");
return 0;
};
-/**
- * returns the actual tuned center frequency which can be used
- * to initialise the AFC registers
- */
-static int tsa5060_setup_pll (struct i2c_adapter *fe, int freq)
-{
- u8 cfg, cpump, band_select;
- u8 buf [4];
- u32 div;
-
- div = (36000000 + freq + 83333) / 166666;
- cfg = 0x88;
-
- cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 :
- freq < 470000000 ? 2 : freq < 750000000 ? 2 : 3;
-
- band_select = freq < 175000000 ? 0x0e : freq < 470000000 ? 0x05 : 0x03;
-
- buf [0] = (div >> 8) & 0x7f;
- buf [1] = div & 0xff;
- buf [2] = ((div >> 10) & 0x60) | cfg;
- buf [3] = cpump | band_select;
-
- /* open i2c gate for PLL message transmission... */
- sp887x_writereg(fe, 0x206, 0x001);
- i2c_writebytes(fe, 0x60, buf, 4);
- sp887x_writereg(fe, 0x206, 0x000);
-
- return (div * 166666 - 36000000);
-}
-
static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
{
int known_parameters = 1;
@@ -362,9 +314,9 @@ static void divide (int n, int d, int *quotient_i, int *quotient_f)
}
}
-static void sp887x_correct_offsets (struct i2c_adapter *fe,
- struct dvb_frontend_parameters *p,
- int actual_freq)
+static void sp887x_correct_offsets (struct sp887x_state* state,
+ struct dvb_frontend_parameters *p,
+ int actual_freq)
{
static const u32 srate_correction [] = { 1879617, 4544878, 8098561 };
int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
@@ -385,17 +337,31 @@ static void sp887x_correct_offsets (struct i2c_adapter *fe,
frequency_shift = -frequency_shift;
/* sample rate correction */
- sp887x_writereg(fe, 0x319, srate_correction[bw_index] >> 12);
- sp887x_writereg(fe, 0x31a, srate_correction[bw_index] & 0xfff);
+ sp887x_writereg(state, 0x319, srate_correction[bw_index] >> 12);
+ sp887x_writereg(state, 0x31a, srate_correction[bw_index] & 0xfff);
/* carrier offset correction */
- sp887x_writereg(fe, 0x309, frequency_shift >> 12);
- sp887x_writereg(fe, 0x30a, frequency_shift & 0xfff);
+ sp887x_writereg(state, 0x309, frequency_shift >> 12);
+ sp887x_writereg(state, 0x30a, frequency_shift & 0xfff);
}
-static int sp887x_setup_frontend_parameters (struct i2c_adapter *fe,
- struct dvb_frontend_parameters *p)
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
{
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
int actual_freq, err;
u16 val, reg0xc05;
@@ -407,14 +373,17 @@ static int sp887x_setup_frontend_parameters (struct i2c_adapter *fe,
if ((err = configure_reg0xc05(p, &reg0xc05)))
return err;
- sp887x_microcontroller_stop(fe);
+ sp887x_microcontroller_stop(state);
- actual_freq = tsa5060_setup_pll(fe, p->frequency);
+ /* setup the PLL */
+ sp887x_writereg(state, 0x206, 0x001);
+ actual_freq = state->config->pll_set(fe, p);
+ sp887x_writereg(state, 0x206, 0x000);
- /* read status reg in order to clear pending irqs */
- sp887x_readreg(fe, 0x200);
+ /* read status reg in order to clear <pending irqs */
+ sp887x_readreg(state, 0x200);
- sp887x_correct_offsets(fe, p, actual_freq);
+ sp887x_correct_offsets(state, p, actual_freq);
/* filter for 6/7/8 Mhz channel */
if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
@@ -424,15 +393,15 @@ static int sp887x_setup_frontend_parameters (struct i2c_adapter *fe,
else
val = 0;
- sp887x_writereg(fe, 0x311, val);
+ sp887x_writereg(state, 0x311, val);
/* scan order: 2k first = 0, 8k first = 1 */
if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
- sp887x_writereg(fe, 0x338, 0x000);
+ sp887x_writereg(state, 0x338, 0x000);
else
- sp887x_writereg(fe, 0x338, 0x001);
+ sp887x_writereg(state, 0x338, 0x001);
- sp887x_writereg(fe, 0xc05, reg0xc05);
+ sp887x_writereg(state, 0xc05, reg0xc05);
if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
val = 2 << 3;
@@ -444,260 +413,210 @@ static int sp887x_setup_frontend_parameters (struct i2c_adapter *fe,
/* enable OFDM and SAW bits as lock indicators in sync register 0xf17,
* optimize algorithm for given bandwidth...
*/
- sp887x_writereg(fe, 0xf14, 0x160 | val);
- sp887x_writereg(fe, 0xf15, 0x000);
+ sp887x_writereg(state, 0xf14, 0x160 | val);
+ sp887x_writereg(state, 0xf15, 0x000);
- sp887x_microcontroller_start(fe);
+ sp887x_microcontroller_start(state);
return 0;
}
-static int sp887x_ioctl(struct dvb_frontend *f, unsigned int cmd, void *arg)
+static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- struct sp887x_state *state = (struct sp887x_state *) f->data;
- struct i2c_adapter *fe = state->i2c;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, &sp887x_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- u16 snr12 = sp887x_readreg(fe, 0xf16);
- u16 sync0x200 = sp887x_readreg(fe, 0x200);
- u16 sync0xf17 = sp887x_readreg(fe, 0xf17);
- fe_status_t *status = arg;
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+ u16 snr12 = sp887x_readreg(state, 0xf16);
+ u16 sync0x200 = sp887x_readreg(state, 0x200);
+ u16 sync0xf17 = sp887x_readreg(state, 0xf17);
- *status = 0;
+ *status = 0;
- if (snr12 > 0x00f)
- *status |= FE_HAS_SIGNAL;
+ if (snr12 > 0x00f)
+ *status |= FE_HAS_SIGNAL;
- //if (sync0x200 & 0x004)
- // *status |= FE_HAS_SYNC | FE_HAS_CARRIER;
+ //if (sync0x200 & 0x004)
+ // *status |= FE_HAS_SYNC | FE_HAS_CARRIER;
- //if (sync0x200 & 0x008)
- // *status |= FE_HAS_VITERBI;
-
- if ((sync0xf17 & 0x00f) == 0x002) {
- *status |= FE_HAS_LOCK;
- *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER;
- }
-
- if (sync0x200 & 0x001) { /* tuner adjustment requested...*/
- int steps = (sync0x200 >> 4) & 0x00f;
- if (steps & 0x008)
- steps = -steps;
- dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n",
- steps);
- }
-
- break;
+ //if (sync0x200 & 0x008)
+ // *status |= FE_HAS_VITERBI;
+ if ((sync0xf17 & 0x00f) == 0x002) {
+ *status |= FE_HAS_LOCK;
+ *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER;
}
- case FE_READ_BER:
- {
- u32* ber = arg;
- *ber = (sp887x_readreg(fe, 0xc08) & 0x3f) |
- (sp887x_readreg(fe, 0xc07) << 6);
- sp887x_writereg(fe, 0xc08, 0x000);
- sp887x_writereg(fe, 0xc07, 0x000);
- if (*ber >= 0x3fff0)
- *ber = ~0;
- break;
-
+ if (sync0x200 & 0x001) { /* tuner adjustment requested...*/
+ int steps = (sync0x200 >> 4) & 0x00f;
+ if (steps & 0x008)
+ steps = -steps;
+ dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n",
+ steps);
}
- case FE_READ_SIGNAL_STRENGTH: // FIXME: correct registers ?
- {
- u16 snr12 = sp887x_readreg(fe, 0xf16);
- u32 signal = 3 * (snr12 << 4);
- *((u16*) arg) = (signal < 0xffff) ? signal : 0xffff;
- break;
- }
+ return 0;
+}
- case FE_READ_SNR:
- {
- u16 snr12 = sp887x_readreg(fe, 0xf16);
- *(u16*) arg = (snr12 << 4) | (snr12 >> 8);
- break;
- }
+static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
- case FE_READ_UNCORRECTED_BLOCKS:
- {
- u32 *ublocks = (u32 *) arg;
- *ublocks = sp887x_readreg(fe, 0xc0c);
- if (*ublocks == 0xfff)
- *ublocks = ~0;
- break;
- }
+ *ber = (sp887x_readreg(state, 0xc08) & 0x3f) |
+ (sp887x_readreg(state, 0xc07) << 6);
+ sp887x_writereg(state, 0xc08, 0x000);
+ sp887x_writereg(state, 0xc07, 0x000);
+ if (*ber >= 0x3fff0)
+ *ber = ~0;
- case FE_SET_FRONTEND:
- return sp887x_setup_frontend_parameters(fe, arg);
+ return 0;
+}
- case FE_GET_FRONTEND: // FIXME: read known values back from Hardware...
- break;
+static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
- case FE_SLEEP:
- /* tristate TS output and disable interface pins */
- sp887x_writereg(fe, 0xc18, 0x000);
- break;
+ u16 snr12 = sp887x_readreg(state, 0xf16);
+ u32 signal = 3 * (snr12 << 4);
+ *strength = (signal < 0xffff) ? signal : 0xffff;
- case FE_INIT:
- /* enable TS output and interface pins */
- sp887x_writereg(fe, 0xc18, 0x00d);
- break;
+ return 0;
+}
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
- fesettings->min_delay_ms = 350;
- fesettings->step_size = 166666*2;
- fesettings->max_drift = (166666*2)+1;
- return 0;
- }
+static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
- default:
- return -EOPNOTSUPP;
- };
+ u16 snr12 = sp887x_readreg(state, 0xf16);
+ *snr = (snr12 << 4) | (snr12 >> 8);
- return 0;
+ return 0;
}
-static struct i2c_client client_template;
-
-static int attach_adapter(struct i2c_adapter *adapter)
+static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
- struct i2c_client *client;
- struct sp887x_state *state;
- const struct firmware *fw;
- int ret;
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
- struct i2c_msg msg = {.addr = 0x70, .flags = 0, .buf = NULL, .len = 0 };
+ *ucblocks = sp887x_readreg(state, 0xc0c);
+ if (*ucblocks == 0xfff)
+ *ucblocks = ~0;
- dprintk ("%s\n", __FUNCTION__);
-
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- return -ENOMEM;
- }
+ return 0;
+}
- if (NULL == (state = kmalloc(sizeof(struct sp887x_state), GFP_KERNEL))) {
- kfree(client);
- return -ENOMEM;
- }
- state->i2c = adapter;
+static int sp887x_sleep(struct dvb_frontend* fe)
+{
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
- if (i2c_transfer (adapter, &msg, 1) != 1) {
- kfree(state);
- kfree(client);
- return -ENODEV;
- }
+ /* tristate TS output and disable interface pins */
+ sp887x_writereg(state, 0xc18, 0x000);
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- i2c_set_clientdata(client, (void*)state);
+ return 0;
+}
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(client);
- kfree(state);
- return ret;
- }
+static int sp887x_init(struct dvb_frontend* fe)
+{
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
+ const struct firmware *fw = NULL;
+ int ret;
- /* request the firmware, this will block until someone uploads it */
- printk("sp887x: waiting for firmware upload...\n");
- ret = request_firmware(&fw, SP887X_DEFAULT_FIRMWARE, &client->dev);
- if (ret) {
- printk("sp887x: no firmware upload (timeout or file not found?)\n");
- goto out;
- }
+ if (!state->initialised) {
+ /* request the firmware, this will block until someone uploads it */
+ printk("sp887x: waiting for firmware upload...\n");
+ ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE);
+ if (ret) {
+ printk("sp887x: no firmware upload (timeout or file not found?)\n");
+ return ret;
+ }
- ret = sp887x_initial_setup(adapter, fw);
- if (ret) {
- printk("sp887x: writing firmware to device failed\n");
- goto out;
+ ret = sp887x_initial_setup(fe, fw);
+ if (ret) {
+ printk("sp887x: writing firmware to device failed\n");
+ release_firmware(fw);
+ return ret;
+ }
+ state->initialised = 1;
}
- ret = dvb_register_frontend(sp887x_ioctl, state->dvb, state,
- &sp887x_info, THIS_MODULE);
- if (ret) {
- printk("sp887x: registering frontend to dvb-core failed.\n");
- goto out;
- }
+ /* enable TS output and interface pins */
+ sp887x_writereg(state, 0xc18, 0x00d);
return 0;
-out:
- release_firmware(fw);
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return ret;
}
-static int detach_client(struct i2c_client *client)
+static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
- struct sp887x_state *state = (struct sp887x_state*)i2c_get_clientdata(client);
-
- dprintk ("%s\n", __FUNCTION__);
+ fesettings->min_delay_ms = 350;
+ fesettings->step_size = 166666*2;
+ fesettings->max_drift = (166666*2)+1;
+ return 0;
+}
- dvb_unregister_frontend (sp887x_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
+static void sp887x_release(struct dvb_frontend* fe)
+{
+ struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv;
kfree(state);
- return 0;
}
-static int command (struct i2c_client *client, unsigned int cmd, void *arg)
+static struct dvb_frontend_ops sp887x_ops;
+
+struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+ struct i2c_adapter* i2c)
{
- struct sp887x_state *state = (struct sp887x_state*)i2c_get_clientdata(client);
+ struct sp887x_state* state = NULL;
- dprintk ("%s\n", __FUNCTION__);
+ /* allocate memory for the internal state */
+ state = (struct sp887x_state*) kmalloc(sizeof(struct sp887x_state), GFP_KERNEL);
+ if (state == NULL) goto error;
- switch (cmd) {
- case FE_REGISTER:
- state->dvb = (struct dvb_adapter*)arg;
- break;
- case FE_UNREGISTER:
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
+ state->initialised = 0;
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_SP887X,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
+ /* check if the demod is there */
+ if (sp887x_readreg(state, 0x0200) < 0) goto error;
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
-static int __init init_sp887x(void)
-{
- return i2c_add_driver(&driver);
+error:
+ if (state) kfree(state);
+ return NULL;
}
-static void __exit exit_sp887x(void)
-{
- if (i2c_del_driver(&driver))
- printk("sp887x: driver deregistration failed\n");
-}
+static struct dvb_frontend_ops sp887x_ops = {
+
+ .info = {
+ .name = "Spase SP887x DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 50500000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166666,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_RECOVER
+ },
+
+ .release = sp887x_release,
+
+ .init = sp887x_init,
+ .sleep = sp887x_sleep,
+
+ .set_frontend = sp887x_setup_frontend_parameters,
+ .get_tune_settings = sp887x_get_tune_settings,
+
+ .read_status = sp887x_read_status,
+ .read_ber = sp887x_read_ber,
+ .read_signal_strength = sp887x_read_signal_strength,
+ .read_snr = sp887x_read_snr,
+ .read_ucblocks = sp887x_read_ucblocks,
+};
-module_init(init_sp887x);
-module_exit(exit_sp887x);
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("sp887x DVB-T demodulator driver");
+MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(sp887x_attach);
diff --git a/linux/drivers/media/dvb/frontends/sp887x.h b/linux/drivers/media/dvb/frontends/sp887x.h
new file mode 100644
index 000000000..6a05d8f8e
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/sp887x.h
@@ -0,0 +1,29 @@
+/*
+ Driver for the Spase sp887x demodulator
+*/
+
+#ifndef SP887X_H
+#define SP887X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct sp887x_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+
+ /* this should return the actual frequency tuned to */
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+ /* request firmware for device */
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // SP887X_H
diff --git a/linux/drivers/media/dvb/frontends/stv0297.c b/linux/drivers/media/dvb/frontends/stv0297.c
new file mode 100644
index 000000000..4ef3adac5
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/stv0297.c
@@ -0,0 +1,479 @@
+/*
+ Driver for STV0297 demodulator
+
+ Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de>
+
+ 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "stv0297.h"
+
+struct stv0297_state {
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ const struct stv0297_config* config;
+
+ struct dvb_frontend frontend;
+};
+
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define STV0297_CLOCK 28900
+
+static u8 init_tab [] = {
+ 0x80, 0x01, /* soft_reset */
+ 0x80, 0x00, /* cleared soft_reset */
+ 0x81, 0x01, /* deinterleaver descrambler reset */
+ 0x81, 0x00, /* cleared deinterleaver descrambler reset */
+ 0x83, 0x10, /* the Reed-Solomon block reset*/
+ 0x83, 0x00, /* cleared the Reed-Solomon block reset */
+ 0x84, 0x2b, /* clears the equalizer and also reinitializes the Reg. 00through 04. */
+ 0x84, 0x2a, /* cleares it .. */
+ 0x03, 0x00,
+ 0x25, 0x88,
+ 0x30, 0x97,
+ 0x31, 0x4C,
+ 0x32, 0xFF,
+ 0x33, 0x55,
+ 0x34, 0x00,
+ 0x35, 0x65,
+ 0x36, 0x80,
+ 0x40, 0x1C,
+ 0x42, 0x3C,
+ 0x43, 0x00,
+ 0x52, 0x28,
+ 0x5A, 0x1E,
+ 0x5B, 0x05,
+ 0x62, 0x06,
+ 0x6A, 0x02,
+ 0x70, 0xFF,
+ 0x71, 0x84,
+ 0x83, 0x10,
+ 0x84, 0x25,
+ 0x85, 0x00,
+ 0x86, 0x78,
+ 0x87, 0x73,
+ 0x88, 0x08,
+ 0x89, 0x00,
+ 0x90, 0x05,
+ 0xA0, 0x00,
+ 0xB0, 0x91,
+ 0xB1, 0x0B,
+ 0xC0, 0x4B,
+ 0xC1, 0x01,
+ 0xC2, 0x00,
+ 0xDE, 0x00,
+ 0xDF, 0x03,
+ 0x87, 0x73
+};
+
+
+static int stv0297_writereg (struct stv0297_state* state, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf [] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+ ret = i2c_transfer (state->i2c, &msg, 1);
+
+ if (ret != 1)
+ dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+ "ret == %i)\n", __FUNCTION__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static int stv0297_writeregs (struct stv0297_state* state, u8 *data, int len)
+{
+ int ret;
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = data, .len = len };
+
+ ret = i2c_transfer (state->i2c, &msg, 1);
+
+ if (ret != 1)
+ dprintk("%s: writeregs error\n ", __FUNCTION__);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static u8 stv0297_readreg (struct stv0297_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)
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+ __FUNCTION__, reg, ret);
+
+ return b1[0];
+}
+
+static int stv0297_readregs (struct stv0297_state* state, u8 reg1, u8 *b, u8 len)
+{
+ int ret;
+ struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
+
+ ret = i2c_transfer (state->i2c, msg, 2);
+
+ if (ret != 2)
+ dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+
+ return ret == 2 ? 0 : ret;
+}
+
+static int stv0297_set_symbolrate (struct stv0297_state* state, u32 srate)
+{
+/*
+ Betanova sniff : 690000
+ stv0297_writereg (i2c, 0x55, 0x4E);
+ stv0297_writereg (i2c, 0x56, 0x00);
+ stv0297_writereg (i2c, 0x57, 0x1F);
+ stv0297_writereg (i2c, 0x58, 0x3D);
+*/
+ long tmp, ExtClk;
+
+ ExtClk = (long)(STV0297_CLOCK) / 4; /* 1/4 = 2^-2 */
+ tmp = 131072L * srate; /* 131072 = 2^17 */
+ tmp = tmp /ExtClk;
+ tmp = tmp * 8192L; /* 8192 = 2^13 */
+
+ stv0297_writereg (state, 0x55,(unsigned char)(tmp & 0xFF));
+ stv0297_writereg (state, 0x56,(unsigned char)(tmp>> 8));
+ stv0297_writereg (state, 0x57,(unsigned char)(tmp>>16));
+ stv0297_writereg (state, 0x58,(unsigned char)(tmp>>24));
+
+ return 0;
+}
+
+void stv0297_set_sweeprate(struct stv0297_state* state, short _FShift, long _SymbolRate)
+{
+ long long_tmp;
+ short FShift ;
+ unsigned char carrier;
+ int RegSymbolRate;
+
+ FShift = _FShift; /* in mS .. +/- 5,100 S von 6975 S */
+ RegSymbolRate = _SymbolRate; //RegGetSRate() ; /* in KHz */
+ if(RegSymbolRate <= 0) return ;
+
+ long_tmp = (long)FShift * 262144L ; // 262144 = 2*18
+ long_tmp /= RegSymbolRate ;
+ long_tmp *= 1024 ; // 1024 = 2*10
+
+ if(long_tmp >= 0)
+ long_tmp += 500000 ;
+ else long_tmp -= 500000 ;
+ long_tmp /= 1000000 ;
+
+ stv0297_writereg (state, 0x60,(unsigned char)(long_tmp & 0xFF));
+
+ carrier = stv0297_readreg(state, 0x69) & ~ 0xF0;
+ carrier |= (unsigned char)((long_tmp>>4) & 0xF0);
+ stv0297_writereg (state, 0x69, carrier);
+
+ return;
+}
+
+void stv0297_set_frequencyoffset(struct stv0297_state* state, long _CarrierOffset)
+{
+ long long_tmp;
+ unsigned char sweep;
+
+ long_tmp = _CarrierOffset * 26844L ; /* (2**28)/10000 */
+ if(long_tmp < 0) long_tmp += 0x10000000 ;
+ long_tmp &= 0x0FFFFFFF ;
+
+ stv0297_writereg (state,0x66,(unsigned char)(long_tmp & 0xFF)); // iphase0
+ stv0297_writereg (state,0x67,(unsigned char)(long_tmp>>8)); // iphase1
+ stv0297_writereg (state,0x68,(unsigned char)(long_tmp>>16)); // iphase2
+
+ sweep = stv0297_readreg(state,0x69) & 0xF0;
+ sweep |= ((unsigned char)(long_tmp>>24) & 0x0F);
+ stv0297_writereg (state,0x69,sweep);
+
+ return;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int stv0297_init (struct dvb_frontend* fe)
+{
+ struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+ int i;
+
+ dprintk("stv0297: init chip\n");
+
+ for (i=0; i<sizeof(init_tab); i+=2) {
+ stv0297_writereg (state, init_tab[i], init_tab[i+1]);
+ }
+
+ return 0;
+}
+
+static int stv0297_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+
+ u8 sync = stv0297_readreg (state, 0xDF);
+
+ *status = 0;
+ if (sync & 0x80)
+ *status |= FE_HAS_SYNC | FE_HAS_SIGNAL;
+ if (sync & 0x80)
+ *status |= FE_HAS_CARRIER;
+ if (sync & 0x80)
+ *status |= FE_HAS_VITERBI;
+ if (sync & 0x80)
+ *status |= FE_HAS_LOCK;
+ return 0;
+}
+
+static int stv0297_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+ u8 BER[3];
+
+ stv0297_writereg (state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes
+ mdelay(25); // Hopefully got 4096 Bytes
+ stv0297_readregs (state, 0xA0, BER, 3);
+ mdelay(25);
+ *ber = (BER[2] << 8 | BER[1]) / ( 8 * 4096);
+
+ return 0;
+}
+
+
+static int stv0297_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+ u8 STRENGTH[2];
+
+ mdelay(25);
+ stv0297_readregs (state, 0x41, STRENGTH, 2);
+ *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];
+
+ return 0;
+}
+
+static int stv0297_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+ u8 SNR[2];
+
+ mdelay(25);
+ stv0297_readregs (state, 0x07, SNR, 2);
+ *snr = SNR[1] << 8 | SNR[0];
+
+ return 0;
+}
+
+static int stv0297_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+
+ *ucblocks = (stv0297_readreg (state, 0xD5) << 8)
+ | stv0297_readreg (state, 0xD4);
+
+ return 0;
+}
+
+static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+{
+ struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+ u8 buf2[] = { 0x83, 0x10, 0x25, 0x00, 0x78, 0x73 };
+ u8 buf3[] = { 0xC0, 0x4B, 0x01, 0x00 };
+ int CarrierOffset = -500;
+ int SweepRate = 1380;
+ int SpectrumInversion = 0;
+
+ if (SpectrumInversion) {
+ SweepRate = -SweepRate ;
+ CarrierOffset = -CarrierOffset ;
+ }
+ else {
+ SweepRate = SweepRate ;
+ CarrierOffset = CarrierOffset ;
+ }
+
+ stv0297_writereg(state, 0x86, 0xF8);
+ state->config->pll_set(fe, p);
+
+ stv0297_writeregs (state, buf2, sizeof(buf2));
+ stv0297_writereg (state, 0x84, 0x24);
+ stv0297_writeregs (state, buf3, sizeof(buf3));
+ stv0297_writereg (state, 0x88, 0x08);
+ stv0297_writereg (state, 0x90, 0x01);
+ stv0297_writereg (state, 0x37, 0x20);
+ stv0297_writereg (state, 0x40, 0x19);
+ stv0297_writereg (state, 0x43, 0x40);
+ stv0297_writereg (state, 0x41, 0xE4);
+ stv0297_writereg (state, 0x42, 0x3C);
+ stv0297_writereg (state, 0x44, 0xFF);
+ stv0297_writereg (state, 0x49, 0x04);
+ stv0297_writereg (state, 0x4A, 0xFF);
+ stv0297_writereg (state, 0x4B, 0xFF);
+ stv0297_writereg (state, 0x71, 0x04);
+ stv0297_writereg (state, 0x53, 0x08);
+ stv0297_writereg (state, 0x5A, 0x3E); //3E forces the direct path to be immediately
+ stv0297_writereg (state, 0x5B, 0x07);
+ stv0297_writereg (state, 0x5B, 0x05);
+
+ stv0297_set_symbolrate (state, p->u.qam.symbol_rate/1000);
+ stv0297_writereg (state, 0x59, 0x08);
+ stv0297_writereg (state, 0x61, 0x49);
+ stv0297_writereg (state, 0x62, 0x0E);
+ stv0297_writereg (state, 0x6A, 0x02);
+ stv0297_writereg (state, 0x00, 0x48); // set qam-64
+
+ stv0297_writereg (state, 0x01, 0x58);
+ stv0297_writereg (state, 0x82, 0x00);
+ stv0297_writereg (state, 0x83, 0x08);
+ stv0297_set_sweeprate(state,SweepRate, p->u.qam.symbol_rate/1000);
+ stv0297_writereg (state, 0x20, 0x00);
+ stv0297_writereg (state, 0x21, 0x40);
+ stv0297_set_frequencyoffset(state,CarrierOffset);
+
+ stv0297_writereg (state, 0x82, 0x00);
+ stv0297_writereg (state, 0x85, 0x04);
+ stv0297_writereg (state, 0x43, 0x10);
+ stv0297_writereg (state, 0x5A, 0x5E);
+
+ stv0297_writereg (state, 0x6A, 0x03);
+
+ stv0297_writereg (state, 0x85, 0x04);
+ stv0297_writereg (state, 0x6B, 0x00);
+ stv0297_writereg (state, 0x4A, 0xFF);
+ stv0297_writereg (state, 0x61, 0x49);
+ stv0297_writereg (state, 0x62, 0x0E);
+ stv0297_writereg (state, 0xDF, 0x02);
+ stv0297_writereg (state, 0xDF, 0x01);
+
+ stv0297_writereg (state, 0xDF, 0x02);
+ stv0297_writereg (state, 0xDF, 0x01);
+
+ stv0297_writereg (state, 0xDF, 0x02);
+ stv0297_writereg (state, 0xDF, 0x01);
+
+ return 0;
+}
+
+static void stv0297_release(struct dvb_frontend* fe)
+{
+ struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops stv0297_ops;
+
+struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct stv0297_state* state = NULL;
+ int id;
+
+ /* allocate memory for the internal state */
+ state = (struct stv0297_state*) kmalloc(sizeof(struct stv0297_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
+
+ /* check if the demod is there */
+ stv0297_writereg(state, 0x02, 0x34); /* standby off */
+ msleep(200);
+ id = stv0297_readreg(state, 0x00);
+
+ /* register 0x00 contains 0xa1 for STV0299 and STV0299B */
+ /* register 0x00 might contain 0x80 when returning from standby */
+ if (id != 0xa1 && id != 0x80) goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops stv0297_ops = {
+
+ .info = {
+ .name = "ST STV0297 DVB-C",
+ .type = FE_QAM,
+ .frequency_min = 64000000,
+ .frequency_max = 1300000000,
+ .frequency_stepsize = 62500,
+ .symbol_rate_min = 870000,
+ .symbol_rate_max = 11700000,
+ .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+ FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO |
+ FE_CAN_RECOVER
+ },
+
+ .release = stv0297_release,
+
+ .init = stv0297_init,
+
+ .set_frontend = stv0297_set_frontend,
+
+ .read_status = stv0297_read_status,
+ .read_ber = stv0297_read_ber,
+ .read_signal_strength = stv0297_read_signal_strength,
+ .read_snr = stv0297_read_snr,
+ .read_ucblocks = stv0297_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver");
+MODULE_AUTHOR("Dennis Noermann");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(stv0297_attach);
diff --git a/linux/drivers/media/dvb/frontends/stv0297.h b/linux/drivers/media/dvb/frontends/stv0297.h
new file mode 100644
index 000000000..cb9aead87
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/stv0297.h
@@ -0,0 +1,40 @@
+/*
+ Driver for STV0297 demodulator
+
+ Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de>
+
+ 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 STV0297_H
+#define STV0297_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0297_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // STV0297_H
diff --git a/linux/drivers/media/dvb/frontends/stv0299.c b/linux/drivers/media/dvb/frontends/stv0299.c
index bfa7b2575..12e45376f 100644
--- a/linux/drivers/media/dvb/frontends/stv0299.c
+++ b/linux/drivers/media/dvb/frontends/stv0299.c
@@ -1,8 +1,5 @@
/*
- Universal driver for STV0299/TDA5059/SL1935 based
- DVB QPSK frontends
-
- Alps BSRU6, LG TDQB-S00x
+ Driver for ST STV0299 demodulator
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
<ralph@convergence.de>,
@@ -54,236 +51,42 @@
#include <asm/div64.h>
#include "dvb_frontend.h"
+#include "stv0299.h"
-#define FRONTEND_NAME "dvbfe_stv0299"
-
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
-
-static int debug;
-static int stv0299_status;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-module_param(stv0299_status, int, 0444);
-MODULE_PARM_DESC(stv0299_status, "Which status value to support "
- "(0 == BER (default), 1 == UCBLOCKS)");
+struct stv0299_state {
-#define STATUS_BER 0
-#define STATUS_UCBLOCKS 1
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
-/* frontend types */
-#define UNKNOWN_FRONTEND -1
-#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5059 synth and datasheet recommended settings
-#define ALPS_BSRU6 1
-#define LG_TDQF_S001F 2
-#define PHILIPS_SU1278_TUA 3 // SU1278 with TUA6100 synth
-#define SAMSUNG_TBMU24112IMB 4
-#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5059 synth and TechnoTrend settings
-#define PHILIPS_SU1278_TSA_TY 6 // SU1278 with TUA5059 synth and Typhoon wiring
-#define PHILIPS_SU1278_TSA_CI 7 // SU1278 with TUA5059 synth and TerraTec Cinergy wiring
-
-/* Master Clock = 88 MHz */
-#define M_CLK (88000000UL)
-
-/* Master Clock for TT cards = 64 MHz */
-#define M_CLK_SU1278_TSA_TT (64000000UL)
-
-static struct dvb_frontend_info uni0299_info = {
- .name = "STV0299/TSA5059/SL1935 based",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = 125, /* kHz for QPSK frontends */
- .frequency_tolerance = M_CLK/2000,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
- .symbol_rate_tolerance = 500, /* ppm */
- .notifier_delay = 0,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_QPSK |
- FE_CAN_FEC_AUTO
-};
+ const struct stv0299_config* config;
+ struct dvb_frontend frontend;
-struct stv0299_state {
- u8 tuner_type;
u8 initialised:1;
u32 tuner_frequency;
u32 symbol_rate;
fe_code_rate_t fec_inner;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
+ int errmode;
};
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
-static u8 init_tab [] = {
- 0x04, 0x7d, /* F22FR = 0x7d */
- /* F22 = f_VCO / 128 / 0x7d = 22 kHz */
-
- /* I2C bus repeater */
- 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
-
- /* general purpose DAC registers */
- 0x06, 0x40, /* DAC not used, set to high impendance mode */
- 0x07, 0x00, /* DAC LSB */
-
- /* DiSEqC registers */
- 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
- 0x09, 0x00, /* FIFO */
-
- /* Input/Output configuration register */
- 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
- /* OP0 ctl = Normal, OP0 val = 1 (18 V) */
- /* Nyquist filter = 00, QPSK reverse = 0 */
-
- /* AGC1 control register */
- 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
-
- /* Timing loop register */
- 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
-
- 0x10, 0x3f, // AGC2 0x3d
-
- 0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
-
- 0x15, 0xc9, // lock detector threshold
-
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
-
- 0x1f, 0x50,
-
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
-
- 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
-
- 0x29, 0x1e, // 1/2 threshold
- 0x2a, 0x14, // 2/3 threshold
- 0x2b, 0x0f, // 3/4 threshold
- 0x2c, 0x09, // 5/6 threshold
- 0x2d, 0x05, // 7/8 threshold
- 0x2e, 0x01,
-
- 0x31, 0x1f, // test all FECs
-
- 0x32, 0x19, // viterbi and synchro search
- 0x33, 0xfc, // rs control
- 0x34, 0x93, // error control
-};
-
-
-static u8 init_tab_samsung [] = {
- 0x01, 0x15,
- 0x02, 0x00,
- 0x03, 0x00,
- 0x04, 0x7D,
- 0x05, 0x35,
- 0x06, 0x02,
- 0x07, 0x00,
- 0x08, 0xC3,
- 0x0C, 0x00,
- 0x0D, 0x81,
- 0x0E, 0x23,
- 0x0F, 0x12,
- 0x10, 0x7E,
- 0x11, 0x84,
- 0x12, 0xB9,
- 0x13, 0x88,
- 0x14, 0x89,
- 0x15, 0xC9,
- 0x16, 0x00,
- 0x17, 0x5C,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1A, 0x00,
- 0x1C, 0x00,
- 0x1D, 0x00,
- 0x1E, 0x00,
- 0x1F, 0x3A,
- 0x20, 0x2E,
- 0x21, 0x80,
- 0x22, 0xFF,
- 0x23, 0xC1,
- 0x28, 0x00,
- 0x29, 0x1E,
- 0x2A, 0x14,
- 0x2B, 0x0F,
- 0x2C, 0x09,
- 0x2D, 0x05,
- 0x31, 0x1F,
- 0x32, 0x19,
- 0x33, 0xFE,
- 0x34, 0x93
-};
-
-
-static u8 init_tab_su1278_tsa_tt [] = {
- 0x01, 0x0f,
- 0x02, 0x30,
- 0x03, 0x00,
- 0x04, 0x5b,
- 0x05, 0x85,
- 0x06, 0x02,
- 0x07, 0x00,
- 0x08, 0x02,
- 0x09, 0x00,
- 0x0C, 0x01,
- 0x0D, 0x81,
- 0x0E, 0x44,
- 0x0f, 0x14,
- 0x10, 0x3c,
- 0x11, 0x84,
- 0x12, 0xda,
- 0x13, 0x97,
- 0x14, 0x95,
- 0x15, 0xc9,
- 0x16, 0x19,
- 0x17, 0x8c,
- 0x18, 0x59,
- 0x19, 0xf8,
- 0x1a, 0xfe,
- 0x1c, 0x7f,
- 0x1d, 0x00,
- 0x1e, 0x00,
- 0x1f, 0x50,
- 0x20, 0x00,
- 0x21, 0x00,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x28, 0x00,
- 0x29, 0x28,
- 0x2a, 0x14,
- 0x2b, 0x0f,
- 0x2c, 0x09,
- 0x2d, 0x09,
- 0x31, 0x1f,
- 0x32, 0x19,
- 0x33, 0xfc,
- 0x34, 0x13
-};
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "stv0299: " args); \
+ } while (0)
-static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec);
-static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type);
-static int stv0299_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
+static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
{
int ret;
u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
- ret = i2c_transfer (i2c, &msg, 1);
+ ret = i2c_transfer (state->i2c, &msg, 1);
if (ret != 1)
dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
@@ -292,16 +95,23 @@ static int stv0299_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
+int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+
+ return stv0299_writeregI(state, reg, data);
+}
+
-static u8 stv0299_readreg (struct i2c_adapter *i2c, u8 reg)
+static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
{
int ret;
u8 b0 [] = { reg };
u8 b1 [] = { 0 };
- struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = b0, .len = 1 },
- { .addr = 0x68, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+ 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 (i2c, msg, 2);
+ ret = i2c_transfer (state->i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
@@ -311,13 +121,13 @@ static u8 stv0299_readreg (struct i2c_adapter *i2c, u8 reg)
}
-static int stv0299_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len)
+static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len)
{
int ret;
- struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = &reg1, .len = 1 },
- { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } };
+ struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
- ret = i2c_transfer (i2c, msg, 2);
+ ret = i2c_transfer (state->i2c, msg, 2);
if (ret != 2)
dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
@@ -326,373 +136,44 @@ static int stv0299_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len)
}
-static int pll_write (struct i2c_adapter *i2c, u8 addr, u8 *data, int len)
-{
- int ret;
- struct i2c_msg msg = { .addr = addr, .buf = data, .len = len };
-
-
- stv0299_writereg(i2c, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
-
- ret = i2c_transfer (i2c, &msg, 1);
-
- stv0299_writereg(i2c, 0x05, 0x35); /* disable i2c repeater on stv0299 */
-
- if (ret != 1)
- dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-
-static int sl1935_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype)
-{
- u8 buf[4];
- u32 div;
-
- div = freq / 125;
-
- dprintk("%s : freq = %i, div = %i\n", __FUNCTION__, freq, div);
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x84; // 0xC4
- buf[3] = 0x08;
-
- if (freq < 1500000) buf[3] |= 0x10;
-
- return pll_write (i2c, 0x61, buf, sizeof(buf));
-}
-
-/**
- * set up the downconverter frequency divisor for a
- * reference clock comparision frequency of 125 kHz.
- */
-static int tsa5059_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate)
-{
- u8 addr;
- u32 div;
- u8 buf[4];
- int divisor, regcode;
-
- dprintk ("%s: freq %i, ftype %i\n", __FUNCTION__, freq, ftype);
-
- if ((freq < 950000) || (freq > 2150000)) return -EINVAL;
-
- if (ftype == PHILIPS_SU1278_TSA_TT) {
- divisor = 500;
- regcode = 2;
- } else {
- divisor = 125;
- regcode = 4;
- }
-
- // setup frequency divisor
- div = (freq + (divisor - 1)) / divisor; // round correctly
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x80 | ((div & 0x18000) >> 10) | regcode;
- buf[3] = 0;
-
- // tuner-specific settings
- switch(ftype) {
- case PHILIPS_SU1278_TSA:
- case PHILIPS_SU1278_TSA_TT:
- case PHILIPS_SU1278_TSA_TY:
- case PHILIPS_SU1278_TSA_CI:
- if (ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI)
- addr = 0x61;
- else
- addr = 0x60;
-
- buf[3] |= 0x20;
-
- if (srate < 4000000) buf[3] |= 1;
-
- if (freq < 1250000) buf[3] |= 0;
- else if (freq < 1550000) buf[3] |= 0x40;
- else if (freq < 2050000) buf[3] |= 0x80;
- else if (freq < 2150000) buf[3] |= 0xC0;
- break;
-
- case ALPS_BSRU6:
- addr = 0x61;
- buf[3] = 0xC4;
- if (freq > 1530000) buf[3] = 0xc0;
- break;
-
- default:
- return -EINVAL;
- }
-
- return pll_write (i2c, addr, buf, sizeof(buf));
-}
-
-
-#define MIN2(a,b) ((a) < (b) ? (a) : (b))
-#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
-
-static int tua6100_set_tv_freq (struct i2c_adapter *i2c, u32 freq,
- int ftype, int srate)
-{
- u8 reg0 [2] = { 0x00, 0x00 };
- u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
- u8 reg2 [3] = { 0x02, 0x00, 0x00 };
- int _fband;
- int first_ZF;
- int R, A, N, P, M;
- int err;
-
- first_ZF = (freq) / 1000;
-
- if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
- abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
- _fband = 2;
- else
- _fband = 3;
-
- if (_fband == 2) {
- if (((first_ZF >= 950) && (first_ZF < 1350)) ||
- ((first_ZF >= 1430) && (first_ZF < 1950)))
- reg0[1] = 0x07;
- else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
- ((first_ZF >= 1950) && (first_ZF < 2150)))
- reg0[1] = 0x0B;
- }
-
- if(_fband == 3) {
- if (((first_ZF >= 950) && (first_ZF < 1350)) ||
- ((first_ZF >= 1455) && (first_ZF < 1950)))
- reg0[1] = 0x07;
- else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
- ((first_ZF >= 1950) && (first_ZF < 2150)))
- reg0[1] = 0x0B;
- else if ((first_ZF >= 1420) && (first_ZF < 1455))
- reg0[1] = 0x0F;
- }
-
- if (first_ZF > 1525)
- reg1[1] |= 0x80;
- else
- reg1[1] &= 0x7F;
-
- if (_fband == 2) {
- if (first_ZF > 1430) { /* 1430MHZ */
- reg1[1] &= 0xCF; /* N2 */
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- } else {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- }
- }
-
- if (_fband == 3) {
- if ((first_ZF >= 1455) &&
- (first_ZF < 1630)) {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- } else {
- if (first_ZF < 1455) {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- } else {
- if (first_ZF >= 1630) {
- reg1[1] &= 0xCF; /* N2 */
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- }
- }
- }
- }
-
- /* set ports, enable P0 for symbol rates > 4Ms/s */
- if (srate >= 4000000)
- reg1[1] |= 0x0c;
- else
- reg1[1] |= 0x04;
-
- reg2[1] |= 0x0c;
-
- R = 64;
- A = 64;
- P = 64; //32
-
- M = (freq * R) / 4; /* in Mhz */
- N = (M - A * 1000) / (P * 1000);
-
- reg1[1] |= (N >> 9) & 0x03;
- reg1[2] = (N >> 1) & 0xff;
- reg1[3] = (N << 7) & 0x80;
-
- reg2[1] |= (R >> 8) & 0x03;
- reg2[2] = R & 0xFF; /* R */
-
- reg1[3] |= A & 0x7f; /* A */
-
- if (P == 64)
- reg1[1] |= 0x40; /* Prescaler 64/65 */
-
- reg0[1] |= 0x03;
-
- if ((err = pll_write(i2c, 0x60, reg0, sizeof(reg0))))
- return err;
-
- if ((err = pll_write(i2c, 0x60, reg1, sizeof(reg1))))
- return err;
-
- if ((err = pll_write(i2c, 0x60, reg2, sizeof(reg2))))
- return err;
-
- return 0;
-}
-
-
-static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate)
-{
- switch(ftype) {
- case SAMSUNG_TBMU24112IMB:
- return sl1935_set_tv_freq(i2c, freq, ftype);
-
- case LG_TDQF_S001F:
- return sl1935_set_tv_freq(i2c, freq, ftype);
-
- case PHILIPS_SU1278_TUA:
- return tua6100_set_tv_freq(i2c, freq, ftype, srate);
-
- default:
- return tsa5059_set_tv_freq(i2c, freq, ftype, srate);
- }
-}
-
-#if 0
-static int tsa5059_read_status (struct i2c_adapter *i2c)
-{
- int ret;
- u8 rpt1 [] = { 0x05, 0xb5 };
- u8 stat [] = { 0 };
-
- struct i2c_msg msg [] = {{ .addr = 0x68, .flags = 0, .buf = rpt1, .len = 2 },
- { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }};
-
- dprintk ("%s\n", __FUNCTION__);
-
- ret = i2c_transfer (i2c, msg, 2);
-
- if (ret != 2)
- dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
-
- return stat[0];
-}
-#endif
-
-
-static int stv0299_init (struct i2c_adapter *i2c, int ftype)
-{
- int i;
-
- dprintk("stv0299: init chip\n");
-
- switch(ftype) {
- case SAMSUNG_TBMU24112IMB:
- dprintk("%s: init stv0299 chip for Samsung TBMU24112IMB\n", __FUNCTION__);
-
- for (i=0; i<sizeof(init_tab_samsung); i+=2)
- {
- dprintk("%s: reg == 0x%02x, val == 0x%02x\n", __FUNCTION__, init_tab_samsung[i], init_tab_samsung[i+1]);
-
- stv0299_writereg (i2c, init_tab_samsung[i], init_tab_samsung[i+1]);
- }
- break;
-
- case PHILIPS_SU1278_TSA_TT:
- for (i=0; i<sizeof(init_tab_su1278_tsa_tt); i+=2) {
- stv0299_writereg (i2c, init_tab_su1278_tsa_tt[i], init_tab_su1278_tsa_tt[i+1]);
- }
- break;
-
- default:
- stv0299_writereg (i2c, 0x01, 0x15);
- stv0299_writereg (i2c, 0x02, ftype == PHILIPS_SU1278_TUA ? 0x00 : 0x30);
- stv0299_writereg (i2c, 0x03, 0x00);
-
- for (i=0; i<sizeof(init_tab); i+=2)
- stv0299_writereg (i2c, init_tab[i], init_tab[i+1]);
-
- /* AGC1 reference register setup */
- if (ftype == PHILIPS_SU1278_TSA || ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI)
- stv0299_writereg (i2c, 0x0f, 0x92); /* Iagc = Inverse, m1 = 18 */
- else if (ftype == PHILIPS_SU1278_TUA)
- stv0299_writereg (i2c, 0x0f, 0x94); /* Iagc = Inverse, m1 = 20 */
- else
- stv0299_writereg (i2c, 0x0f, 0x52); /* Iagc = Normal, m1 = 18 */
- break;
- }
-
- switch(stv0299_status) {
- case STATUS_BER:
- stv0299_writereg(i2c, 0x34, 0x93);
- break;
-
- case STATUS_UCBLOCKS:
- stv0299_writereg(i2c, 0x34, 0xB3);
- break;
- }
-
- return 0;
-}
-
-
-static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec)
+static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
switch (fec) {
case FEC_AUTO:
{
- dprintk ("%s : FEC_AUTO\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x1f);
+ return stv0299_writeregI (state, 0x31, 0x1f);
}
case FEC_1_2:
{
- dprintk ("%s : FEC_1_2\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x01);
+ return stv0299_writeregI (state, 0x31, 0x01);
}
case FEC_2_3:
{
- dprintk ("%s : FEC_2_3\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x02);
+ return stv0299_writeregI (state, 0x31, 0x02);
}
case FEC_3_4:
{
- dprintk ("%s : FEC_3_4\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x04);
+ return stv0299_writeregI (state, 0x31, 0x04);
}
case FEC_5_6:
{
- dprintk ("%s : FEC_5_6\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x08);
+ return stv0299_writeregI (state, 0x31, 0x08);
}
case FEC_7_8:
{
- dprintk ("%s : FEC_7_8\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x31, 0x10);
+ return stv0299_writeregI (state, 0x31, 0x10);
}
default:
{
- dprintk ("%s : FEC invalid\n", __FUNCTION__);
return -EINVAL;
}
}
}
-static fe_code_rate_t stv0299_get_fec (struct i2c_adapter *i2c)
+static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state)
{
static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6,
FEC_7_8, FEC_1_2 };
@@ -700,7 +181,7 @@ static fe_code_rate_t stv0299_get_fec (struct i2c_adapter *i2c)
dprintk ("%s\n", __FUNCTION__);
- index = stv0299_readreg (i2c, 0x1b);
+ index = stv0299_readreg (state, 0x1b);
index &= 0x7;
if (index > 4)
@@ -710,13 +191,13 @@ static fe_code_rate_t stv0299_get_fec (struct i2c_adapter *i2c)
}
-static int stv0299_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout)
+static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout)
{
unsigned long start = jiffies;
dprintk ("%s\n", __FUNCTION__);
- while (stv0299_readreg(i2c, 0x0a) & 1) {
+ while (stv0299_readreg(state, 0x0a) & 1) {
if (jiffies - start > timeout) {
dprintk ("%s: timeout!!\n", __FUNCTION__);
return -ETIMEDOUT;
@@ -728,13 +209,13 @@ static int stv0299_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout)
}
-static int stv0299_wait_diseqc_idle (struct i2c_adapter *i2c, int timeout)
+static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout)
{
unsigned long start = jiffies;
dprintk ("%s\n", __FUNCTION__);
- while ((stv0299_readreg(i2c, 0x0a) & 3) != 2 ) {
+ while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) {
if (jiffies - start > timeout) {
dprintk ("%s: timeout!!\n", __FUNCTION__);
return -ETIMEDOUT;
@@ -745,101 +226,156 @@ static int stv0299_wait_diseqc_idle (struct i2c_adapter *i2c, int timeout)
return 0;
}
+static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ u64 big = srate;
+ u32 ratio;
+
+ // check rate is within limits
+ if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
-static int stv0299_send_diseqc_msg (struct i2c_adapter *i2c,
- struct dvb_diseqc_master_cmd *m)
+ // calculate value to program
+ big = big << 20;
+ big += (state->config->mclk-1); // round correctly
+ do_div(big, state->config->mclk);
+ ratio = big << 4;
+
+ return state->config->set_symbol_rate(fe, srate, ratio);
+}
+
+
+static int stv0299_get_symbolrate (struct stv0299_state* state)
{
+ u32 Mclk = state->config->mclk / 4096L;
+ u32 srate;
+ s32 offset;
+ u8 sfr[3];
+ s8 rtf;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ stv0299_readregs (state, 0x1f, sfr, 3);
+ stv0299_readregs (state, 0x1a, &rtf, 1);
+
+ srate = (sfr[0] << 8) | sfr[1];
+ srate *= Mclk;
+ srate /= 16;
+ srate += (sfr[2] >> 4) * Mclk / 256;
+ offset = (s32) rtf * (srate / 4096L);
+ offset /= 128;
+
+ dprintk ("%s : srate = %i\n", __FUNCTION__, srate);
+ dprintk ("%s : ofset = %i\n", __FUNCTION__, offset);
+
+ srate += offset;
+
+ srate += 1000;
+ srate /= 2000;
+ srate *= 2000;
+
+ return srate;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int stv0299_send_diseqc_msg (struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *m)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
u8 val;
int i;
dprintk ("%s\n", __FUNCTION__);
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
- val = stv0299_readreg (i2c, 0x08);
+ val = stv0299_readreg (state, 0x08);
- if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */
+ if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */
return -EREMOTEIO;
for (i=0; i<m->msg_len; i++) {
- if (stv0299_wait_diseqc_fifo (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_fifo (state, 100) < 0)
return -ETIMEDOUT;
- if (stv0299_writereg (i2c, 0x09, m->msg[i]))
+ if (stv0299_writeregI (state, 0x09, m->msg[i]))
return -EREMOTEIO;
}
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
return 0;
}
-static int stv0299_send_diseqc_burst (struct i2c_adapter *i2c, fe_sec_mini_cmd_t burst)
+static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
u8 val;
dprintk ("%s\n", __FUNCTION__);
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
- val = stv0299_readreg (i2c, 0x08);
+ val = stv0299_readreg (state, 0x08);
- if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x2)) /* burst mode */
+ if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */
return -EREMOTEIO;
- if (stv0299_writereg (i2c, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff))
+ if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff))
return -EREMOTEIO;
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
- if (stv0299_writereg (i2c, 0x08, val))
+ if (stv0299_writeregI (state, 0x08, val))
return -EREMOTEIO;
return 0;
}
-static int stv0299_set_tone (struct i2c_adapter *i2c, fe_sec_tone_mode_t tone)
+static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
u8 val;
- dprintk("%s: %s\n", __FUNCTION__,
- tone == SEC_TONE_ON ? "SEC_TONE_ON" :
- tone == SEC_TONE_OFF ? "SEC_TONE_OFF" : "??");
-
- if (stv0299_wait_diseqc_idle (i2c, 100) < 0)
+ if (stv0299_wait_diseqc_idle (state, 100) < 0)
return -ETIMEDOUT;
- val = stv0299_readreg (i2c, 0x08);
+ val = stv0299_readreg (state, 0x08);
switch (tone) {
case SEC_TONE_ON:
- {
- dprintk("%s: TONE_ON\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x08, val | 0x3);
- }
+ return stv0299_writeregI (state, 0x08, val | 0x3);
+
case SEC_TONE_OFF:
- {
- dprintk("%s: TONE_OFF\n", __FUNCTION__);
- return stv0299_writereg (i2c, 0x08, (val & ~0x3) | 0x02);
- }
+ return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02);
+
default:
- {
- dprintk("%s: TONE INVALID\n", __FUNCTION__);
return -EINVAL;
}
- };
}
-static int stv0299_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage,
- int tuner_type)
+static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
u8 reg0x08;
u8 reg0x0c;
@@ -847,46 +383,37 @@ static int stv0299_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltag
voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
- reg0x08 = stv0299_readreg (i2c, 0x08);
- reg0x0c = stv0299_readreg (i2c, 0x0c);
-
+ reg0x08 = stv0299_readreg (state, 0x08);
+ reg0x0c = stv0299_readreg (state, 0x0c);
+
/**
* H/V switching over OP0, OP1 and OP2 are LNB power enable bits
*/
reg0x0c &= 0x0f;
if (voltage == SEC_VOLTAGE_OFF) {
- stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */
- return stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */
- }
-
- if (tuner_type == PHILIPS_SU1278_TSA_CI)
- {
- stv0299_writereg (i2c, 0x08, reg0x08 & 0xBF); // switch LNB power on OP2/LOCK pin off
- }
- else
- {
- stv0299_writereg (i2c, 0x08, reg0x08 | 0x40);
+ stv0299_writeregI (state, 0x0c, 0x00); /* LNB power off! */
+ return stv0299_writeregI (state, 0x08, 0x00); /* LNB power off! */
}
+ stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
+
switch (voltage) {
case SEC_VOLTAGE_13:
- if (tuner_type == PHILIPS_SU1278_TSA_TY || tuner_type == PHILIPS_SU1278_TSA_CI)
- return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x10);
- else
- return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x40);
+ if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) reg0x0c |= 0x10;
+ else reg0x0c |= 0x40;
- case SEC_VOLTAGE_18:
- return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x50);
+ return stv0299_writeregI(state, 0x0c, reg0x0c);
+ case SEC_VOLTAGE_18:
+ return stv0299_writeregI(state, 0x0c, reg0x0c | 0x50);
default:
return -EINVAL;
};
}
-static int stv0299_send_legacy_dish_cmd(struct i2c_adapter *i2c, u32 cmd,
- int tuner_type)
+static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd)
{
u8 last = 1;
int i;
@@ -901,15 +428,14 @@ static int stv0299_send_legacy_dish_cmd(struct i2c_adapter *i2c, u32 cmd,
cmd = cmd << 1;
dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
- stv0299_set_voltage(i2c,SEC_VOLTAGE_18,tuner_type);
+ stv0299_set_voltage(fe,SEC_VOLTAGE_18);
msleep(32);
for (i=0; i<9; i++) {
if((cmd & 0x01) != last) {
- stv0299_set_voltage(i2c,
+ stv0299_set_voltage(fe,
last ? SEC_VOLTAGE_13 :
- SEC_VOLTAGE_18,
- tuner_type);
+ SEC_VOLTAGE_18);
last = (last) ? 0 : 1;
}
@@ -922,598 +448,316 @@ static int stv0299_send_legacy_dish_cmd(struct i2c_adapter *i2c, u32 cmd,
return 0;
}
-static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type)
+
+static int stv0299_init (struct dvb_frontend* fe)
{
- u64 big = srate;
- u32 ratio;
- u8 aclk = 0;
- u8 bclk = 0;
- u8 m1;
- int Mclk = M_CLK;
-
- // check rate is within limits
- if ((srate < 1000000) || (srate > 45000000)) return -EINVAL;
-
- // calculate value to program
- if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT;
- big = big << 20;
- big += (Mclk-1); // round correctly
- do_div(big, Mclk);
- ratio = big << 4;
-
- // program registers
- switch(tuner_type) {
- case PHILIPS_SU1278_TSA_TT:
- stv0299_writereg (i2c, 0x0e, 0x44);
- if (srate >= 10000000) {
- stv0299_writereg (i2c, 0x13, 0x97);
- stv0299_writereg (i2c, 0x14, 0x95);
- stv0299_writereg (i2c, 0x15, 0xc9);
- stv0299_writereg (i2c, 0x17, 0x8c);
- stv0299_writereg (i2c, 0x1a, 0xfe);
- stv0299_writereg (i2c, 0x1c, 0x7f);
- stv0299_writereg (i2c, 0x2d, 0x09);
- } else {
- stv0299_writereg (i2c, 0x13, 0x99);
- stv0299_writereg (i2c, 0x14, 0x8d);
- stv0299_writereg (i2c, 0x15, 0xce);
- stv0299_writereg (i2c, 0x17, 0x43);
- stv0299_writereg (i2c, 0x1a, 0x1d);
- stv0299_writereg (i2c, 0x1c, 0x12);
- stv0299_writereg (i2c, 0x2d, 0x05);
- }
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ int i;
- stv0299_writereg (i2c, 0x0e, 0x23);
- stv0299_writereg (i2c, 0x0f, 0x94);
- stv0299_writereg (i2c, 0x10, 0x39);
- stv0299_writereg (i2c, 0x15, 0xc9);
-
- stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
- break;
-
- case PHILIPS_SU1278_TSA_TY:
- case PHILIPS_SU1278_TSA_CI:
- case PHILIPS_SU1278_TSA:
- aclk = 0xb5;
- if (srate < 2000000) bclk = 0x86;
- else if (srate < 5000000) bclk = 0x89;
- else if (srate < 15000000) bclk = 0x8f;
- else if (srate < 45000000) bclk = 0x95;
-
- m1 = 0x14;
- if (srate < 4000000) m1 = 0x10;
-
- stv0299_writereg (i2c, 0x13, aclk);
- stv0299_writereg (i2c, 0x14, bclk);
- stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
- stv0299_writereg (i2c, 0x0f, (stv0299_readreg(i2c, 0x0f) & 0xc0) | m1);
- break;
-
- case ALPS_BSRU6:
- default:
- if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
- else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
- else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
- else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
- else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
- else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
- stv0299_writereg (i2c, 0x13, aclk);
- stv0299_writereg (i2c, 0x14, bclk);
- stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0);
- break;
+ dprintk("stv0299: init chip\n");
+
+ for (i=0; state->config->inittab[i] != 0xff && state->config->inittab[i+1] != 0xff; i+=2)
+ stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
+
+ if (state->config->pll_init) {
+ stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
+ state->config->pll_init(fe);
+ stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
}
-
return 0;
}
-static int stv0299_get_symbolrate (struct i2c_adapter *i2c, int tuner_type)
+static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- u32 Mclk = M_CLK / 4096L;
- u32 srate;
- s32 offset;
- u8 sfr[3];
- s8 rtf;
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- dprintk ("%s\n", __FUNCTION__);
+ u8 signal = 0xff - stv0299_readreg (state, 0x18);
+ u8 sync = stv0299_readreg (state, 0x1b);
- if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT / 4096L;
-
- stv0299_readregs (i2c, 0x1f, sfr, 3);
- stv0299_readregs (i2c, 0x1a, &rtf, 1);
+ dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
+ *status = 0;
- srate = (sfr[0] << 8) | sfr[1];
- srate *= Mclk;
- srate /= 16;
- srate += (sfr[2] >> 4) * Mclk / 256;
- offset = (s32) rtf * (srate / 4096L);
- offset /= 128;
+ if (signal > 10)
+ *status |= FE_HAS_SIGNAL;
- dprintk ("%s : srate = %i\n", __FUNCTION__, srate);
- dprintk ("%s : ofset = %i\n", __FUNCTION__, offset);
+ if (sync & 0x80)
+ *status |= FE_HAS_CARRIER;
- srate += offset;
+ if (sync & 0x10)
+ *status |= FE_HAS_VITERBI;
- srate += 1000;
- srate /= 2000;
- srate *= 2000;
+ if (sync & 0x08)
+ *status |= FE_HAS_SYNC;
- return srate;
+ if ((sync & 0x98) == 0x98)
+ *status |= FE_HAS_LOCK;
+
+ return 0;
}
-static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
{
- struct stv0299_state *state = (struct stv0299_state *) fe->data;
- struct i2c_adapter *i2c = state->i2c;
-
- dprintk ("%s\n", __FUNCTION__);
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- switch (cmd) {
- case FE_GET_INFO:
- {
- struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) arg;
- memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info));
-
- if (state->tuner_type == PHILIPS_SU1278_TSA_TT) {
- tmp->frequency_tolerance = M_CLK_SU1278_TSA_TT / 2000;
- }
- break;
- }
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = (fe_status_t *) arg;
- u8 signal = 0xff - stv0299_readreg (i2c, 0x18);
- u8 sync = stv0299_readreg (i2c, 0x1b);
+ if (state->errmode != STATUS_BER) return 0;
+ *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
- dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
-
- *status = 0;
-
- if (signal > 10)
- *status |= FE_HAS_SIGNAL;
-
- if (sync & 0x80)
- *status |= FE_HAS_CARRIER;
-
- if (sync & 0x10)
- *status |= FE_HAS_VITERBI;
-
- if (sync & 0x08)
- *status |= FE_HAS_SYNC;
-
- if ((sync & 0x98) == 0x98)
- *status |= FE_HAS_LOCK;
-
- break;
- }
-
- case FE_READ_BER:
- if (stv0299_status == STATUS_BER) {
- *((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8)
- | stv0299_readreg (i2c, 0x1e);
- } else {
- *((u32*) arg) = 0;
- }
- break;
-
- case FE_READ_SIGNAL_STRENGTH:
- {
- s32 signal = 0xffff - ((stv0299_readreg (i2c, 0x18) << 8)
- | stv0299_readreg (i2c, 0x19));
-
- dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__,
- stv0299_readreg (i2c, 0x18),
- stv0299_readreg (i2c, 0x19), (int) signal);
-
- signal = signal * 5 / 4;
- *((u16*) arg) = (signal > 0xffff) ? 0xffff :
- (signal < 0) ? 0 : signal;
- break;
- }
- case FE_READ_SNR:
- {
- s32 snr = 0xffff - ((stv0299_readreg (i2c, 0x24) << 8)
- | stv0299_readreg (i2c, 0x25));
- snr = 3 * (snr - 0xa100);
- *((u16*) arg) = (snr > 0xffff) ? 0xffff :
- (snr < 0) ? 0 : snr;
- break;
- }
- case FE_READ_UNCORRECTED_BLOCKS:
- if (stv0299_status == STATUS_UCBLOCKS) {
- *((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8)
- | stv0299_readreg (i2c, 0x1e);
- } else {
- *((u32*) arg) = 0;
- }
- break;
-
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- int invval = 0;
-
- dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
-
- // set the inversion
- if (p->inversion == INVERSION_OFF) invval = 0;
- else if (p->inversion == INVERSION_ON) invval = 1;
- else {
- printk("stv0299 does not support auto-inversion\n");
- return -EINVAL;
- }
- if (state->tuner_type == ALPS_BSRU6) invval = (~invval) & 1;
- stv0299_writereg(i2c, 0x0c, (stv0299_readreg(i2c, 0x0c) & 0xfe) | invval);
-
- switch(state->tuner_type) {
- case PHILIPS_SU1278_TSA_TT:
- {
- /* check if we should do a finetune */
- int frequency_delta = p->frequency - state->tuner_frequency;
- int minmax = p->u.qpsk.symbol_rate / 2000;
- if (minmax < 5000) minmax = 5000;
-
- if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
- (state->fec_inner == p->u.qpsk.fec_inner) &&
- (state->symbol_rate == p->u.qpsk.symbol_rate)) {
- int Drot_freq = (frequency_delta << 16) / (M_CLK_SU1278_TSA_TT / 1000);
-
- // zap the derotator registers first
- stv0299_writereg (i2c, 0x22, 0x00);
- stv0299_writereg (i2c, 0x23, 0x00);
-
- // now set them as we want
- stv0299_writereg (i2c, 0x22, Drot_freq >> 8);
- stv0299_writereg (i2c, 0x23, Drot_freq);
- } else {
- /* A "normal" tune is requested */
- pll_set_tv_freq (i2c, p->frequency, state->tuner_type, p->u.qpsk.symbol_rate);
- stv0299_writereg (i2c, 0x32, 0x80);
- stv0299_writereg (i2c, 0x22, 0x00);
- stv0299_writereg (i2c, 0x23, 0x00);
- stv0299_writereg (i2c, 0x32, 0x19);
- stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type);
- stv0299_set_FEC (i2c, p->u.qpsk.fec_inner);
- }
- break;
- }
-
- default:
- pll_set_tv_freq (i2c, p->frequency, state->tuner_type, p->u.qpsk.symbol_rate);
- stv0299_set_FEC (i2c, p->u.qpsk.fec_inner);
- stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type);
- stv0299_writereg (i2c, 0x22, 0x00);
- stv0299_writereg (i2c, 0x23, 0x00);
- stv0299_readreg (i2c, 0x23);
- stv0299_writereg (i2c, 0x12, 0xb9);
- break;
- }
-
- state->tuner_frequency = p->frequency;
- state->fec_inner = p->u.qpsk.fec_inner;
- state->symbol_rate = p->u.qpsk.symbol_rate;
- break;
- }
-
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- s32 derot_freq;
- int Mclk = M_CLK;
- int invval;
-
- if (state->tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT;
-
- derot_freq = (s32)(s16) ((stv0299_readreg (i2c, 0x22) << 8)
- | stv0299_readreg (i2c, 0x23));
-
- derot_freq *= (Mclk >> 16);
- derot_freq += 500;
- derot_freq /= 1000;
-
- p->frequency += derot_freq;
+ return 0;
+}
- invval = stv0299_readreg (i2c, 0x0c) & 1;
- if (state->tuner_type == ALPS_BSRU6) invval = (~invval) & 1;
- p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
+static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- p->u.qpsk.fec_inner = stv0299_get_fec (i2c);
- p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, state->tuner_type);
- break;
- }
+ s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8)
+ | stv0299_readreg (state, 0x19));
- case FE_SLEEP:
- stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */
- stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */
- stv0299_writereg (i2c, 0x02, 0x80);
- state->initialised = 0;
- break;
-
- case FE_INIT:
- switch(state->tuner_type) {
- case PHILIPS_SU1278_TSA_TT:
- state->tuner_frequency = 0;
- if (!state->initialised) {
- state->initialised = 1;
- return stv0299_init (i2c, state->tuner_type);
- }
- break;
-
- default:
- return stv0299_init (i2c, state->tuner_type);
- }
- break;
+ dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__,
+ stv0299_readreg (state, 0x18),
+ stv0299_readreg (state, 0x19), (int) signal);
- case FE_DISEQC_SEND_MASTER_CMD:
- return stv0299_send_diseqc_msg (i2c, arg);
+ signal = signal * 5 / 4;
+ *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
- case FE_DISEQC_SEND_BURST:
- return stv0299_send_diseqc_burst (i2c, (fe_sec_mini_cmd_t) arg);
+ return 0;
+}
- case FE_SET_TONE:
- return stv0299_set_tone (i2c, (fe_sec_tone_mode_t) arg);
+static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- case FE_SET_VOLTAGE:
- return stv0299_set_voltage (i2c, (fe_sec_voltage_t) arg,
- state->tuner_type);
+ s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8)
+ | stv0299_readreg (state, 0x25));
+ xsnr = 3 * (xsnr - 0xa100);
+ *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr;
- case FE_DISHNETWORK_SEND_LEGACY_CMD:
- return stv0299_send_legacy_dish_cmd (i2c, (u32) arg,
- state->tuner_type);
+ return 0;
+}
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
-
- switch(state->tuner_type) {
- case PHILIPS_SU1278_TSA_TT:
- fesettings->min_delay_ms = 50;
- if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
- fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
- fesettings->max_drift = 5000;
- } else {
- fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
- fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
- }
- break;
-
- default:
- fesettings->min_delay_ms = 100;
- if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
- fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
- fesettings->max_drift = 5000;
- } else {
- fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
- fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
- }
- break;
- }
+static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- return 0;
- }
-
- default:
- return -EOPNOTSUPP;
- };
+ if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
+ else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
return 0;
}
-static long probe_tuner (struct i2c_adapter *adapter)
+static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
{
- struct i2c_adapter *i2c = adapter; /* superfluous */
-
- /* read the status register of TSA5059 */
- u8 rpt[] = { 0x05, 0xb5 };
- u8 stat [] = { 0 };
- u8 tda6100_buf [] = { 0, 0 };
- int ret;
- struct i2c_msg msg1 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 },
- { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }};
- struct i2c_msg msg2 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 },
- { .addr = 0x61, .flags = I2C_M_RD, .buf = stat, .len = 1 }};
- struct i2c_msg msg3 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, len: 2 },
- { .addr = 0x60, .flags = 0, .buf = tda6100_buf, .len = 2 }};
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ int invval = 0;
- stv0299_writereg (i2c, 0x01, 0x15);
- stv0299_writereg (i2c, 0x02, 0x30);
- stv0299_writereg (i2c, 0x03, 0x00);
+ dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
+ // set the inversion
+ if (p->inversion == INVERSION_OFF) invval = 0;
+ else if (p->inversion == INVERSION_ON) invval = 1;
+ else {
+ printk("stv0299 does not support auto-inversion\n");
+ return -EINVAL;
+ }
+ if (state->config->invert) invval = (~invval) & 1;
+ stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
- printk("stv0299: try to attach to %s\n", adapter->name);
+ if (state->config->enhanced_tuning) {
+ /* check if we should do a finetune */
+ int frequency_delta = p->frequency - state->tuner_frequency;
+ int minmax = p->u.qpsk.symbol_rate / 2000;
+ if (minmax < 5000) minmax = 5000;
- if (!strcmp(adapter->name, "SkyStar2")) {
- printk ("stv0299: setup for tuner Samsung TBMU24112IMB\n");
- return SAMSUNG_TBMU24112IMB;
- }
+ if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
+ (state->fec_inner == p->u.qpsk.fec_inner) &&
+ (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+ int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000);
- if ((ret = i2c_transfer(i2c, msg1, 2)) == 2) {
- if ( strcmp(adapter->name, "TT-Budget/WinTV-NOVA-CI PCI") == 0 ) {
- // technotrend cards require non-datasheet settings
- printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on TechnoTrend hardware\n");
- return PHILIPS_SU1278_TSA_TT;
- } else {
- // fall back to datasheet-recommended settings
- printk ("stv0299: setup for tuner SU1278 (TSA5059 synth)\n");
- return PHILIPS_SU1278_TSA;
- }
- }
+ // zap the derotator registers first
+ stv0299_writeregI(state, 0x22, 0x00);
+ stv0299_writeregI(state, 0x23, 0x00);
- if ((ret = i2c_transfer(i2c, msg2, 2)) == 2) {
- if ( strcmp(adapter->name, "KNC1 DVB-S") == 0 )
- {
- // Typhoon cards have unusual wiring.
- printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on Typhoon hardware\n");
- return PHILIPS_SU1278_TSA_TY;
- }
- else if ( strcmp(adapter->name, "TerraTec Cinergy 1200 DVB-S") == 0 )
- {
- // Cinergy cards have unusual wiring.
- printk ("%s: setup for tuner SU1278 (TSA5059 synth) on"
- " TerraTec hardware\n", __FILE__);
- return PHILIPS_SU1278_TSA_CI;
- }
- //else if ((stat[0] & 0x3f) == 0) {
- else if (0) {
- printk ("stv0299: setup for tuner TDQF-S001F\n");
- return LG_TDQF_S001F;
+ // now set them as we want
+ stv0299_writeregI(state, 0x22, Drot_freq >> 8);
+ stv0299_writeregI(state, 0x23, Drot_freq);
} else {
- printk ("stv0299: setup for tuner BSRU6, TDQB-S00x\n");
- return ALPS_BSRU6;
+ /* A "normal" tune is requested */
+ stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
+ state->config->pll_set(fe, p);
+ stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
+
+ stv0299_writeregI(state, 0x32, 0x80);
+ stv0299_writeregI(state, 0x22, 0x00);
+ stv0299_writeregI(state, 0x23, 0x00);
+ stv0299_writeregI(state, 0x32, 0x19);
+ stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+ stv0299_set_FEC (state, p->u.qpsk.fec_inner);
}
- }
-
- /**
- * setup i2c timing for SU1278...
- */
- stv0299_writereg (i2c, 0x02, 0x00);
+ } else {
+ stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
+ state->config->pll_set(fe, p);
+ stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
- if ((ret = i2c_transfer(i2c, msg3, 2)) == 2) {
- printk ("stv0299: setup for tuner Philips SU1278 (TUA6100 synth)\n");
- return PHILIPS_SU1278_TUA;
+ stv0299_set_FEC (state, p->u.qpsk.fec_inner);
+ stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+ stv0299_writeregI(state, 0x22, 0x00);
+ stv0299_writeregI(state, 0x23, 0x00);
+ stv0299_readreg (state, 0x23);
+ stv0299_writeregI(state, 0x12, 0xb9);
}
- printk ("stv0299: unknown PLL synthesizer (ret == %i), please report to <linuxdvb@linuxtv.org>!!\n", ret);
+ state->tuner_frequency = p->frequency;
+ state->fec_inner = p->u.qpsk.fec_inner;
+ state->symbol_rate = p->u.qpsk.symbol_rate;
- return UNKNOWN_FRONTEND;
+ return 0;
}
-static struct i2c_client client_template;
-
-static int attach_adapter(struct i2c_adapter *adapter)
+static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
{
- struct i2c_client *client;
- struct stv0299_state* state;
- int tuner_type;
- int ret;
- u8 id;
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ s32 derot_freq;
+ int invval;
- stv0299_writereg(adapter, 0x02, 0x34); /* standby off */
- msleep(200);
- id = stv0299_readreg(adapter, 0x00);
+ derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8)
+ | stv0299_readreg (state, 0x23));
- dprintk ("%s: id == 0x%02x\n", __FUNCTION__, id);
+ derot_freq *= (state->config->mclk >> 16);
+ derot_freq += 500;
+ derot_freq /= 1000;
- /* register 0x00 contains 0xa1 for STV0299 and STV0299B */
- /* register 0x00 might contain 0x80 when returning from standby */
- if (id != 0xa1 && id != 0x80)
- return -ENODEV;
+ p->frequency += derot_freq;
- if ((tuner_type = probe_tuner(adapter)) < 0)
- return -ENODEV;
+ invval = stv0299_readreg (state, 0x0c) & 1;
+ if (state->config->invert) invval = (~invval) & 1;
+ p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
- if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) {
- return -ENOMEM;
- }
+ p->u.qpsk.fec_inner = stv0299_get_fec (state);
+ p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state);
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- kfree(state);
- return -ENOMEM;
- }
-
- state->tuner_type = tuner_type;
- state->tuner_frequency = 0;
- state->initialised = 0;
- state->i2c = adapter;
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = (0x68>>1);
- i2c_set_clientdata(client, (void*)state);
-
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(client);
- kfree(state);
- return -EFAULT;
- }
-
- BUG_ON(!state->dvb);
-
- ret = dvb_register_frontend(uni0299_ioctl, state->dvb, state,
- &uni0299_info, THIS_MODULE);
- if (ret) {
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return -EFAULT;
- }
-
return 0;
}
-static int detach_client(struct i2c_client *client)
+static int stv0299_sleep(struct dvb_frontend* fe)
{
- struct stv0299_state *state = (struct stv0299_state*)i2c_get_clientdata(client);
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+
+ stv0299_writeregI(state, 0x02, 0x80);
+ state->initialised = 0;
- dvb_unregister_frontend (uni0299_ioctl, state->dvb);
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
return 0;
}
-static int command (struct i2c_client *client, unsigned int cmd, void *arg)
+static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
- struct stv0299_state *data = (struct stv0299_state*)i2c_get_clientdata(client);
- dprintk ("%s\n", __FUNCTION__);
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- switch (cmd) {
- case FE_REGISTER: {
- data->dvb = (struct dvb_adapter*)arg;
- break;
- }
- case FE_UNREGISTER: {
- data->dvb = NULL;
- break;
- }
- default:
- return -EOPNOTSUPP;
+ fesettings->min_delay_ms = state->config->min_delay_ms;
+ if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
+ fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
+ fesettings->max_drift = 5000;
+ } else {
+ fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
+ fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
}
return 0;
}
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_STV0299,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
-
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
-
-static int __init init_uni0299 (void)
+static void stv0299_release(struct dvb_frontend* fe)
{
- return i2c_add_driver(&driver);
+ struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ kfree(state);
}
-static void __exit exit_uni0299 (void)
+static struct dvb_frontend_ops stv0299_ops;
+
+struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
+ struct i2c_adapter* i2c)
{
- if (i2c_del_driver(&driver))
- printk("stv0299: driver deregistration failed\n");
+ struct stv0299_state* state = NULL;
+ int id;
+
+ /* allocate memory for the internal state */
+ state = (struct stv0299_state*) kmalloc(sizeof(struct stv0299_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
+ state->initialised = 0;
+ state->tuner_frequency = 0;
+ state->symbol_rate = 0;
+ state->fec_inner = 0;
+ state->errmode = STATUS_BER;
+
+ /* check if the demod is there */
+ stv0299_writeregI(state, 0x02, 0x34); /* standby off */
+ msleep(200);
+ id = stv0299_readreg(state, 0x00);
+
+ /* register 0x00 contains 0xa1 for STV0299 and STV0299B */
+ /* register 0x00 might contain 0x80 when returning from standby */
+ if (id != 0xa1 && id != 0x80) goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init (init_uni0299);
-module_exit (exit_uni0299);
+static struct dvb_frontend_ops stv0299_ops = {
+
+ .info = {
+ .name = "ST STV0299 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125, /* kHz for QPSK frontends */
+ .frequency_tolerance = 0,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500, /* ppm */
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_QPSK |
+ FE_CAN_FEC_AUTO
+ },
+
+ .release = stv0299_release,
+
+ .init = stv0299_init,
+ .sleep = stv0299_sleep,
+
+ .set_frontend = stv0299_set_frontend,
+ .get_frontend = stv0299_get_frontend,
+ .get_tune_settings = stv0299_get_tune_settings,
+
+ .read_status = stv0299_read_status,
+ .read_ber = stv0299_read_ber,
+ .read_signal_strength = stv0299_read_signal_strength,
+ .read_snr = stv0299_read_snr,
+ .read_ucblocks = stv0299_read_ucblocks,
+
+ .diseqc_send_master_cmd = stv0299_send_diseqc_msg,
+ .diseqc_send_burst = stv0299_send_diseqc_burst,
+ .set_tone = stv0299_set_tone,
+ .set_voltage = stv0299_set_voltage,
+ .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver");
+MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
"Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(stv0299_writereg);
+EXPORT_SYMBOL(stv0299_attach);
diff --git a/linux/drivers/media/dvb/frontends/stv0299.h b/linux/drivers/media/dvb/frontends/stv0299.h
new file mode 100644
index 000000000..79457a80a
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/stv0299.h
@@ -0,0 +1,104 @@
+/*
+ Driver for ST STV0299 demodulator
+
+ Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+ <ralph@convergence.de>,
+ <holger@convergence.de>,
+ <js@convergence.de>
+
+
+ Philips SU1278/SH
+
+ Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de>
+
+
+ LG TDQF-S001F
+
+ Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
+ & Andreas Oberritter <obi@linuxtv.org>
+
+
+ Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
+
+ Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
+
+ Support for Philips SU1278 on Technotrend hardware
+
+ Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
+
+ 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 STV0299_H
+#define STV0299_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#define STV0229_LOCKOUTPUT_0 0
+#define STV0229_LOCKOUTPUT_1 1
+#define STV0229_LOCKOUTPUT_CF 2
+#define STV0229_LOCKOUTPUT_LK 3
+
+#define STV0299_VOLT13_OP0 0
+#define STV0299_VOLT13_OP1 1
+
+struct stv0299_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* inittab - array of pairs of values.
+ * First of each pair is the register, second is the value.
+ * List should be terminated with an 0xff, 0xff pair.
+ */
+ u8* inittab;
+
+ /* master clock to use */
+ u32 mclk;
+
+ /* does the inversion require inversion? */
+ u8 invert:1;
+
+ /* Should the enhanced tuning code be used? */
+ u8 enhanced_tuning:1;
+
+ /* Skip reinitialisation? */
+ u8 skip_reinit:1;
+
+ /* LOCK OUTPUT setting */
+ u8 lock_output:2;
+
+ /* Is 13v controlled by OP0 or OP1? */
+ u8 volt13_op0_op1:1;
+
+ /* minimum delay before retuning */
+ int min_delay_ms;
+
+ /* Set the symbol rate */
+ int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
+
+extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // STV0299_H
diff --git a/linux/drivers/media/dvb/frontends/tda10021.c b/linux/drivers/media/dvb/frontends/tda10021.c
new file mode 100644
index 000000000..324bb2c0d
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda10021.c
@@ -0,0 +1,483 @@
+/*
+ TDA10021 - Single Chip Cable Channel Receiver driver module
+ used on the the Siemens DVB-C cards
+
+ Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+ Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+ Suppport for TDA10021
+
+ 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/config.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda10021.h"
+
+
+struct tda10021_state {
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct tda10021_config* config;
+
+ struct dvb_frontend frontend;
+
+ u8 pwm;
+ u8 reg0;
+};
+
+
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+static int verbose;
+
+#define XIN 57840000UL
+#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0)
+#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0)
+#define HAS_INVERSION(reg0) (!(reg0 & 0x20))
+
+#define FIN (XIN >> 4)
+
+int tda10021_inittab_size = 0x40;
+static u8 tda10021_inittab[0x40]=
+{
+ 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
+ 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
+ 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
+ 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
+ 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00,
+ 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
+};
+
+static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+ int ret;
+
+ ret = i2c_transfer (state->i2c, &msg, 1);
+ if (ret != 1)
+ printk("DVB: TDA10021(%d): %s, writereg error "
+ "(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+ state->frontend.dvb->num, __FUNCTION__, reg, data, ret);
+
+ msleep(10);
+ return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+
+static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
+{
+ 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 } };
+ int ret;
+
+ ret = i2c_transfer (state->i2c, msg, 2);
+ if (ret != 2)
+ printk("DVB: TDA10021(%d): %s: readreg error (ret == %i)\n",
+ state->frontend.dvb->num, __FUNCTION__, ret);
+ return b1[0];
+}
+
+//get access to tuner
+static int lock_tuner(struct tda10021_state* state)
+{
+ u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 };
+ struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+ if(i2c_transfer(state->i2c, &msg, 1) != 1)
+ {
+ printk("tda10021: lock tuner fails\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+//release access from tuner
+static int unlock_tuner(struct tda10021_state* state)
+{
+ u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f };
+ struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+ if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
+ {
+ printk("tda10021: unlock tuner fails\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0,
+ fe_spectral_inversion_t inversion)
+{
+ reg0 |= state->reg0 & 0x63;
+
+ if (INVERSION_ON == inversion)
+ ENABLE_INVERSION(reg0);
+ else if (INVERSION_OFF == inversion)
+ DISABLE_INVERSION(reg0);
+
+ tda10021_writereg (state, 0x00, reg0 & 0xfe);
+ tda10021_writereg (state, 0x00, reg0 | 0x01);
+
+ state->reg0 = reg0;
+ return 0;
+}
+
+static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate)
+{
+ s32 BDR;
+ s32 BDRI;
+ s16 SFIL=0;
+ u16 NDEC = 0;
+ u32 tmp, ratio;
+
+ if (symbolrate > XIN/2)
+ symbolrate = XIN/2;
+ if (symbolrate < 500000)
+ symbolrate = 500000;
+
+ if (symbolrate < XIN/16) NDEC = 1;
+ if (symbolrate < XIN/32) NDEC = 2;
+ if (symbolrate < XIN/64) NDEC = 3;
+
+ if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
+ if (symbolrate < (u32)(XIN/16)) SFIL = 0;
+ if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
+ if (symbolrate < (u32)(XIN/32)) SFIL = 0;
+ if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
+ if (symbolrate < (u32)(XIN/64)) SFIL = 0;
+ if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
+
+ symbolrate <<= NDEC;
+ ratio = (symbolrate << 4) / FIN;
+ tmp = ((symbolrate << 4) % FIN) << 8;
+ ratio = (ratio << 8) + tmp / FIN;
+ tmp = (tmp % FIN) << 8;
+ ratio = (ratio << 8) + (tmp + FIN/2) / FIN;
+
+ BDR = ratio;
+ BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
+
+ if (BDRI > 0xFF)
+ BDRI = 0xFF;
+
+ SFIL = (SFIL << 4) | tda10021_inittab[0x0E];
+
+ NDEC = (NDEC << 6) | tda10021_inittab[0x03];
+
+ tda10021_writereg (state, 0x03, NDEC);
+ tda10021_writereg (state, 0x0a, BDR&0xff);
+ tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
+ tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
+
+ tda10021_writereg (state, 0x0d, BDRI);
+ tda10021_writereg (state, 0x0e, SFIL);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+static int tda10021_init (struct dvb_frontend *fe)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+ int i;
+
+ dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
+
+ //tda10021_writereg (fe, 0, 0);
+
+ for (i=0; i<tda10021_inittab_size; i++)
+ tda10021_writereg (state, i, tda10021_inittab[i]);
+
+ tda10021_writereg (state, 0x34, state->pwm);
+
+ //Comment by markus
+ //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
+ //0x2A[4] == BYPPLL -> Power down mode (default 1)
+ //0x2A[5] == LCK -> PLL Lock Flag
+ //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
+
+ //Activate PLL
+ tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
+
+ if (state->config->pll_init) {
+ lock_tuner(state);
+ state->config->pll_init(fe);
+ unlock_tuner(state);
+ }
+
+ return 0;
+}
+
+static int tda10021_set_parameters (struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+ //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256
+ //CONF
+ static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 };
+ //AGCREF value
+ static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c };
+ //LTHR value
+ static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 };
+ //MSETH
+ static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 };
+ //AREF
+ static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b };
+
+ int qam = p->u.qam.modulation;
+
+ if (qam < 0 || qam > 5)
+ return -EINVAL;
+
+ //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
+
+ lock_tuner(state);
+ state->config->pll_set(fe, p);
+ unlock_tuner(state);
+
+ tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
+ tda10021_writereg (state, 0x34, state->pwm);
+
+ tda10021_writereg (state, 0x01, reg0x01[qam]);
+ tda10021_writereg (state, 0x05, reg0x05[qam]);
+ tda10021_writereg (state, 0x08, reg0x08[qam]);
+ tda10021_writereg (state, 0x09, reg0x09[qam]);
+
+ tda10021_setup_reg0 (state, reg0x00[qam], p->inversion);
+
+ return 0;
+}
+
+static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+ int sync;
+
+ *status = 0;
+ //0x11[0] == EQALGO -> Equalizer algorithms state
+ //0x11[1] == CARLOCK -> Carrier locked
+ //0x11[2] == FSYNC -> Frame synchronisation
+ //0x11[3] == FEL -> Front End locked
+ //0x11[6] == NODVB -> DVB Mode Information
+ sync = tda10021_readreg (state, 0x11);
+
+ if (sync & 2)
+ *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
+
+ if (sync & 4)
+ *status |= FE_HAS_SYNC|FE_HAS_VITERBI;
+
+ if (sync & 8)
+ *status |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+ u32 _ber = tda10021_readreg(state, 0x14) |
+ (tda10021_readreg(state, 0x15) << 8) |
+ ((tda10021_readreg(state, 0x16) & 0x0f) << 16);
+ *ber = 10 * _ber;
+
+ return 0;
+}
+
+static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+ u8 gain = tda10021_readreg(state, 0x17);
+ *strength = (gain << 8) | gain;
+
+ return 0;
+}
+
+static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+ u8 quality = ~tda10021_readreg(state, 0x18);
+ *snr = (quality << 8) | quality;
+
+ return 0;
+}
+
+static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+ *ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
+ if (*ucblocks == 0x7f)
+ *ucblocks = 0xffffffff;
+
+ /* reset uncorrected block counter */
+ tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
+ tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
+
+ return 0;
+}
+
+static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+ int sync;
+ s8 afc = 0;
+
+ sync = tda10021_readreg(state, 0x11);
+ afc = tda10021_readreg(state, 0x19);
+ if (verbose) {
+ /* AFC only valid when carrier has been recovered */
+ printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
+ "DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
+ state->frontend.dvb->num, afc,
+ -((s32)p->u.qam.symbol_rate * afc) >> 10);
+ }
+
+ p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF;
+ p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+
+ p->u.qam.fec_inner = FEC_NONE;
+ p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+
+ if (sync & 2)
+ p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+
+ return 0;
+}
+
+static int tda10021_sleep(struct dvb_frontend* fe)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+ tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */
+ tda10021_writereg (state, 0x00, 0x80); /* standby */
+
+ return 0;
+}
+
+static void tda10021_release(struct dvb_frontend* fe)
+{
+ struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops tda10021_ops;
+
+struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+ struct i2c_adapter* i2c,
+ u8 pwm)
+{
+ struct tda10021_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct tda10021_state*) kmalloc(sizeof(struct tda10021_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
+ state->pwm = pwm;
+ state->reg0 = tda10021_inittab[0];
+
+ /* check if the demod is there */
+ if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops tda10021_ops = {
+
+ .info = {
+ .name = "Philips TDA10021 DVB-C",
+ .type = FE_QAM,
+ .frequency_stepsize = 62500,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */
+ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */
+ #if 0
+ .frequency_tolerance = ???,
+ .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
+ #endif
+ .caps = 0x400 | //FE_CAN_QAM_4
+ FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+ FE_CAN_FEC_AUTO
+ },
+
+ .release = tda10021_release,
+
+ .init = tda10021_init,
+ .sleep = tda10021_sleep,
+
+ .set_frontend = tda10021_set_parameters,
+ .get_frontend = tda10021_get_frontend,
+
+ .read_status = tda10021_read_status,
+ .read_ber = tda10021_read_ber,
+ .read_signal_strength = tda10021_read_signal_strength,
+ .read_snr = tda10021_read_snr,
+ .read_ucblocks = tda10021_read_ucblocks,
+};
+
+MODULE_PARM(verbose, "i");
+MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
+
+MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10021_attach);
diff --git a/linux/drivers/media/dvb/frontends/tda10021.h b/linux/drivers/media/dvb/frontends/tda10021.h
new file mode 100644
index 000000000..1cd74da37
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda10021.h
@@ -0,0 +1,43 @@
+/*
+ TDA10021 - Single Chip Cable Channel Receiver driver module
+ used on the the Siemens DVB-C cards
+
+ Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+ Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+ Suppport for TDA10021
+
+ 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 TDA10021_H
+#define TDA10021_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda10021_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+ struct i2c_adapter* i2c,
+ u8 pwm);
+
+#endif // TDA10021_H
diff --git a/linux/drivers/media/dvb/frontends/tda1004x.c b/linux/drivers/media/dvb/frontends/tda1004x.c
index a5672b35b..39ea5adc6 100644
--- a/linux/drivers/media/dvb/frontends/tda1004x.c
+++ b/linux/drivers/media/dvb/frontends/tda1004x.c
@@ -1,5 +1,5 @@
/*
- Driver for Philips tda1004xh OFDM Frontend
+ Driver for Philips tda1004xh OFDM Demodulator
(c) 2003, 2004 Andrew de Quincey & Robert Schlabbach
@@ -32,23 +32,35 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
-#include <linux/firmware.h>
-
#include "dvb_frontend.h"
+#include "tda1004x.h"
-#define FRONTEND_NAME "dvbfe_tda1004x"
+#define TDA1004X_DEMOD_TDA10045 0
+#define TDA1004X_DEMOD_TDA10046 1
-#define dprintk(args...) \
- do { \
- if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \
- } while (0)
-static int debug;
+struct tda1004x_state
+{
+ struct i2c_adapter* i2c;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+ struct dvb_frontend_ops ops;
-#define MC44BC374_ADDRESS 0x65
+ const struct tda1004x_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* private demod data */
+ u8 initialised:1;
+
+ u8 demod_type;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "tda1004x: " args); \
+ } while (0)
#define TDA1004X_CHIPID 0x00
#define TDA1004X_AUTO 0x01
@@ -128,53 +140,7 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
#define TDA10046H_CODE_IN 0x58
-#define FE_TYPE_TDA10045H 0
-#define FE_TYPE_TDA10046H 1
-
-#define TUNER_TYPE_TD1344 0
-#define TUNER_TYPE_TD1316 1
-
-static struct dvb_frontend_info tda10045h_info = {
- .name = "Philips TDA10045H",
- .type = FE_OFDM,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 166667,
- .caps =
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
-};
-
-static struct dvb_frontend_info tda10046h_info = {
- .name = "Philips TDA10046H",
- .type = FE_OFDM,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 166667,
- .caps =
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
-};
-
-struct tda1004x_state {
- u8 tda1004x_address;
- u8 tuner_address;
- u8 initialised;
- u8 tuner_type;
- u8 fe_type;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
-
- int dspCodeCounterReg;
- int dspCodeInReg;
- int dspVersion;
-};
-
-static int tda1004x_write_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int data)
+static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data)
{
int ret;
u8 buf[] = { reg, data };
@@ -182,8 +148,8 @@ static int tda1004x_write_byte(struct i2c_adapter *i2c, struct tda1004x_state *t
dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
- msg.addr = tda_state->tda1004x_address;
- ret = i2c_transfer(i2c, &msg, 1);
+ msg.addr = state->config->demod_address;
+ ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
@@ -194,7 +160,7 @@ static int tda1004x_write_byte(struct i2c_adapter *i2c, struct tda1004x_state *t
return (ret != 1) ? -1 : 0;
}
-static int tda1004x_read_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg)
+static int tda1004x_read_byte(struct tda1004x_state *state, int reg)
{
int ret;
u8 b0[] = { reg };
@@ -204,9 +170,9 @@ static int tda1004x_read_byte(struct i2c_adapter *i2c, struct tda1004x_state *td
dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
- msg[0].addr = tda_state->tda1004x_address;
- msg[1].addr = tda_state->tda1004x_address;
- ret = i2c_transfer(i2c, msg, 2);
+ msg[0].addr = state->config->demod_address;
+ msg[1].addr = state->config->demod_address;
+ ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
@@ -219,14 +185,14 @@ static int tda1004x_read_byte(struct i2c_adapter *i2c, struct tda1004x_state *td
return b1[0];
}
-static int tda1004x_write_mask(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int mask, int data)
+static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data)
{
int val;
dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,
mask, data);
// read a byte and check
- val = tda1004x_read_byte(i2c, tda_state, reg);
+ val = tda1004x_read_byte(state, reg);
if (val < 0)
return val;
@@ -235,10 +201,10 @@ static int tda1004x_write_mask(struct i2c_adapter *i2c, struct tda1004x_state *t
val |= data & 0xff;
// write it out again
- return tda1004x_write_byte(i2c, tda_state, reg, val);
+ return tda1004x_write_byteI(state, reg, val);
}
-static int tda1004x_write_buf(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, unsigned char *buf, int len)
+static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len)
{
int i;
int result;
@@ -247,7 +213,7 @@ static int tda1004x_write_buf(struct i2c_adapter *i2c, struct tda1004x_state *td
result = 0;
for (i = 0; i < len; i++) {
- result = tda1004x_write_byte(i2c, tda_state, reg + i, buf[i]);
+ result = tda1004x_write_byteI(state, reg + i, buf[i]);
if (result != 0)
break;
}
@@ -255,25 +221,24 @@ static int tda1004x_write_buf(struct i2c_adapter *i2c, struct tda1004x_state *td
return result;
}
-static int tda1004x_enable_tuner_i2c(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
+static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state)
{
int result;
dprintk("%s\n", __FUNCTION__);
- result = tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 2);
+ result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2);
msleep(1);
return result;
}
-static int tda1004x_disable_tuner_i2c(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
+static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
{
dprintk("%s\n", __FUNCTION__);
- return tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 0);
+ return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0);
}
-static int tda10045h_set_bandwidth(struct i2c_adapter *i2c,
- struct tda1004x_state *tda_state,
+static int tda10045h_set_bandwidth(struct tda1004x_state *state,
fe_bandwidth_t bandwidth)
{
static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
@@ -282,31 +247,27 @@ static int tda10045h_set_bandwidth(struct i2c_adapter *i2c,
switch (bandwidth) {
case BANDWIDTH_6_MHZ:
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14);
- tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+ tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
break;
case BANDWIDTH_7_MHZ:
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x80);
- tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+ tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
break;
case BANDWIDTH_8_MHZ:
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14);
- tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+ tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
break;
default:
return -EINVAL;
}
- tda1004x_write_byte(i2c, tda_state, TDA10045H_IOFFSET, 0);
+ tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0);
return 0;
}
-static int tda10046h_set_bandwidth(struct i2c_adapter *i2c,
- struct tda1004x_state *tda_state,
+static int tda10046h_set_bandwidth(struct tda1004x_state *state,
fe_bandwidth_t bandwidth)
{
static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e };
@@ -315,18 +276,15 @@ static int tda10046h_set_bandwidth(struct i2c_adapter *i2c,
switch (bandwidth) {
case BANDWIDTH_6_MHZ:
- tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0);
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
break;
case BANDWIDTH_7_MHZ:
- tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0);
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
break;
case BANDWIDTH_8_MHZ:
- tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
- tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0xFF);
+ tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
break;
default:
@@ -336,7 +294,9 @@ static int tda10046h_set_bandwidth(struct i2c_adapter *i2c,
return 0;
}
-static int tda1004x_do_upload(struct i2c_adapter *i2c, struct tda1004x_state *state, unsigned char *mem, unsigned int len)
+static int tda1004x_do_upload(struct tda1004x_state *state,
+ unsigned char *mem, unsigned int len,
+ u8 dspCodeCounterReg, u8 dspCodeInReg)
{
u8 buf[65];
struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 };
@@ -344,10 +304,10 @@ static int tda1004x_do_upload(struct i2c_adapter *i2c, struct tda1004x_state *st
int pos = 0;
/* clear code counter */
- tda1004x_write_byte(i2c, state, state->dspCodeCounterReg, 0);
- fw_msg.addr = state->tda1004x_address;
+ tda1004x_write_byteI(state, dspCodeCounterReg, 0);
+ fw_msg.addr = state->config->demod_address;
- buf[0] = state->dspCodeInReg;
+ buf[0] = dspCodeInReg;
while (pos != len) {
// work out how much to send this time
@@ -359,7 +319,7 @@ static int tda1004x_do_upload(struct i2c_adapter *i2c, struct tda1004x_state *st
// send the chunk
memcpy(buf + 1, mem + pos, tx_size);
fw_msg.len = tx_size + 1;
- if (i2c_transfer(i2c, &fw_msg, 1) != 1) {
+ if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
printk("tda1004x: Error during firmware upload\n");
return -EIO;
}
@@ -370,18 +330,17 @@ static int tda1004x_do_upload(struct i2c_adapter *i2c, struct tda1004x_state *st
return 0;
}
-static int tda1004x_check_upload_ok(struct i2c_adapter *i2c, struct tda1004x_state *state)
+static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion)
{
u8 data1, data2;
// check upload was OK
- tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
- tda1004x_write_byte(i2c, state, TDA1004X_DSP_CMD, 0x67);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
+ tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67);
- data1 = tda1004x_read_byte(i2c, state, TDA1004X_DSP_DATA1);
- data2 = tda1004x_read_byte(i2c, state, TDA1004X_DSP_DATA2);
- if (data1 != 0x67 || data2 != state->dspVersion) {
- printk("tda1004x: firmware upload failed!\n");
+ data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
+ data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
+ if (data1 != 0x67 || data2 != dspVersion) {
return -EIO;
}
@@ -389,31 +348,34 @@ static int tda1004x_check_upload_ok(struct i2c_adapter *i2c, struct tda1004x_sta
}
-static int tda10045_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, struct i2c_client *client)
+static int tda10045_fwupload(struct dvb_frontend* fe)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
int ret;
const struct firmware *fw;
+
+ /* don't re-upload unless necessary */
+ if (tda1004x_check_upload_ok(state, 0x2c) == 0) return 0;
+
/* request the firmware, this will block until someone uploads it */
printk("tda1004x: waiting for firmware upload...\n");
- ret = request_firmware(&fw, TDA10045_DEFAULT_FIRMWARE, &client->dev);
+ ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
if (ret) {
printk("tda1004x: no firmware upload (timeout or file not found?)\n");
return ret;
}
-
- /* set some valid bandwith parameters before uploading */
/* reset chip */
- tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 0x10, 0);
- tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8);
- tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 0);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
msleep(10);
/* set parameters */
- tda10045h_set_bandwidth(i2c, state, BANDWIDTH_8_MHZ);
+ tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);
- ret = tda1004x_do_upload(i2c, state, fw->data, fw->size);
+ ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
if (ret)
return ret;
@@ -421,49 +383,47 @@ static int tda10045_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *sta
/* DSPREADY doesn't seem to work on the TDA10045H */
msleep(100);
- ret = tda1004x_check_upload_ok(i2c, state);
- if (ret)
- return ret;
-
- return 0;
+ return tda1004x_check_upload_ok(state, 0x2c);
}
-static int tda10046_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, struct i2c_client *client)
+static int tda10046_fwupload(struct dvb_frontend* fe)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
unsigned long timeout;
int ret;
const struct firmware *fw;
+ /* don't re-upload unless necessary */
+ if (tda1004x_check_upload_ok(state, 0x20) == 0) return 0;
+
/* request the firmware, this will block until someone uploads it */
printk("tda1004x: waiting for firmware upload...\n");
- ret = request_firmware(&fw, TDA10046_DEFAULT_FIRMWARE, &client->dev);
+ ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
if (ret) {
printk("tda1004x: no firmware upload (timeout or file not found?)\n");
return ret;
}
- /* set some valid bandwith parameters before uploading */
-
/* reset chip */
- tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 1, 0);
- tda1004x_write_mask(i2c, state, TDA10046H_CONF_TRISTATE1, 1, 0);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0);
+ tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
msleep(10);
/* set parameters */
- tda1004x_write_byte(i2c, state, TDA10046H_CONFPLL2, 10);
- tda1004x_write_byte(i2c, state, TDA10046H_CONFPLL3, 0);
- tda1004x_write_byte(i2c, state, TDA10046H_FREQ_OFFSET, 99);
- tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
- tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
- tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
-
- ret = tda1004x_do_upload(i2c, state, fw->data, fw->size);
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10);
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+
+ ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
if (ret)
return ret;
/* wait for DSP to initialise */
timeout = jiffies + HZ;
- while(!(tda1004x_read_byte(i2c, state, TDA1004X_STATUS_CD) & 0x20)) {
+ while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
if (time_after(jiffies, timeout)) {
printk("tda1004x: DSP failed to initialised.\n");
return -EIO;
@@ -471,95 +431,7 @@ static int tda10046_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *sta
msleep(1);
}
- ret = tda1004x_check_upload_ok(i2c, state);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int tda10045h_init(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
-{
- struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 };
- static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
-
- dprintk("%s\n", __FUNCTION__);
-
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
-
- // Disable the MC44BC374C
- tda1004x_enable_tuner_i2c(i2c, tda_state);
- tuner_msg.addr = MC44BC374_ADDRESS;
- tuner_msg.buf = disable_mc44BC374c;
- tuner_msg.len = sizeof(disable_mc44BC374c);
- if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
- i2c_transfer(i2c, &tuner_msg, 1);
- }
- tda1004x_disable_tuner_i2c(i2c, tda_state);
-
- // tda setup
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); // select HP stream
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0); // no frequency inversion
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
- tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
- tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
- tda1004x_write_mask(i2c, tda_state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
- tda1004x_write_byte(i2c, tda_state, TDA1004X_CONFADC1, 0x2e);
-
- return 0;
-}
-
-static int tda10046h_init(struct i2c_adapter *i2c, struct tda1004x_state *tda_state)
-{
- struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 };
- static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
-
- dprintk("%s\n", __FUNCTION__);
-
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 1, 0); // wake up the chip
-
- // Disable the MC44BC374C
- tda1004x_enable_tuner_i2c(i2c, tda_state);
- tuner_msg.addr = MC44BC374_ADDRESS;
- tuner_msg.buf = disable_mc44BC374c;
- tuner_msg.len = sizeof(disable_mc44BC374c);
- if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
- i2c_transfer(i2c, &tuner_msg, 1);
- }
- tda1004x_disable_tuner_i2c(i2c, tda_state);
-
- // tda setup
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0x40); // TT TDA10046H needs inversion ON
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); // select HP stream
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
- tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL2, 10); // PLL M = 10
- tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
- tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_CONF, 0); // AGC setup
- tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_TUN_MIN, 0); // }
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_IF_MIN, 0); // }
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_IF_MAX, 0xff); // }
- tda1004x_write_mask(i2c, tda_state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits
- tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm
- tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config
- tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN
- tda1004x_write_byte(i2c, tda_state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
- tda1004x_write_byte(i2c, tda_state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
- tda1004x_write_mask(i2c, tda_state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select
- tda10046h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
-
- return 0;
+ return tda1004x_check_upload_ok(state, 0x20);
}
static int tda1004x_encode_fec(int fec)
@@ -602,174 +474,147 @@ static int tda1004x_decode_fec(int tdafec)
return -1;
}
-static int tda1004x_set_frequency(struct i2c_adapter *i2c,
- struct tda1004x_state *tda_state,
- struct dvb_frontend_parameters *fe_params)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data)
{
- u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
- int tuner_frequency = 0;
- u8 band, cp, filter;
- int counter, counter2;
+ struct tda1004x_state* state = fe->demodulator_priv;
- dprintk("%s\n", __FUNCTION__);
+ return tda1004x_write_byteI(state, reg, data);
+}
- // setup the frequency buffer
- switch (tda_state->tuner_type) {
- case TUNER_TYPE_TD1344:
-
- // setup tuner buffer
- // ((Fif+((1000000/6)/2)) + Finput)/(1000000/6)
- tuner_frequency =
- (((fe_params->frequency / 1000) * 6) + 217502) / 1000;
- tuner_buf[0] = tuner_frequency >> 8;
- tuner_buf[1] = tuner_frequency & 0xff;
- tuner_buf[2] = 0x88;
- if (fe_params->frequency < 550000000) {
- tuner_buf[3] = 0xab;
- } else {
- tuner_buf[3] = 0xeb;
- }
+static int tda10045_init(struct dvb_frontend* fe)
+{
+ struct tda1004x_state* state = fe->demodulator_priv;
- // tune it
- tda1004x_enable_tuner_i2c(i2c, tda_state);
- tuner_msg.addr = tda_state->tuner_address;
- tuner_msg.len = 4;
- i2c_transfer(i2c, &tuner_msg, 1);
-
- // wait for it to finish
- tuner_msg.len = 1;
- tuner_msg.flags = I2C_M_RD;
- counter = 0;
- counter2 = 0;
- while (counter++ < 100) {
- if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
- if (tuner_buf[0] & 0x40) {
- counter2++;
- } else {
- counter2 = 0;
- }
- }
-
- if (counter2 > 10) {
- break;
- }
- }
- tda1004x_disable_tuner_i2c(i2c, tda_state);
- break;
+ dprintk("%s\n", __FUNCTION__);
- case TUNER_TYPE_TD1316:
- // determine charge pump
- tuner_frequency = fe_params->frequency + 36130000;
- if (tuner_frequency < 87000000) {
- return -EINVAL;
- } else if (tuner_frequency < 130000000) {
- cp = 3;
- } else if (tuner_frequency < 160000000) {
- cp = 5;
- } else if (tuner_frequency < 200000000) {
- cp = 6;
- } else if (tuner_frequency < 290000000) {
- cp = 3;
- } else if (tuner_frequency < 420000000) {
- cp = 5;
- } else if (tuner_frequency < 480000000) {
- cp = 6;
- } else if (tuner_frequency < 620000000) {
- cp = 3;
- } else if (tuner_frequency < 830000000) {
- cp = 5;
- } else if (tuner_frequency < 895000000) {
- cp = 7;
- } else {
- return -EINVAL;
- }
+ if (state->initialised) return 0;
- // determine band
- if (fe_params->frequency < 49000000) {
- return -EINVAL;
- } else if (fe_params->frequency < 159000000) {
- band = 1;
- } else if (fe_params->frequency < 444000000) {
- band = 2;
- } else if (fe_params->frequency < 861000000) {
- band = 4;
- } else {
- return -EINVAL;
- }
+ if (tda10045_fwupload(fe)) {
+ printk("tda1004x: firmware upload failed\n");
+ return -EIO;
+ }
- // work out filter
- switch (fe_params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
- filter = 0;
- break;
+ tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
- case BANDWIDTH_7_MHZ:
- filter = 0;
- break;
+ // Init the PLL
+ if (state->config->pll_init) {
+ tda1004x_enable_tuner_i2c(state);
+ state->config->pll_init(fe);
+ tda1004x_disable_tuner_i2c(state);
+ }
- case BANDWIDTH_8_MHZ:
- filter = 1;
- break;
+ // tda setup
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
+ tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
+ tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal
+ tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer
+ tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset
+ tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset
+ tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface
+ tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface
+ tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits
+ tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity
+ tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e);
+
+ state->initialised = 1;
+ return 0;
+}
- default:
- return -EINVAL;
- }
+static int tda10046_init(struct dvb_frontend* fe)
+{
+ struct tda1004x_state* state = fe->demodulator_priv;
+ dprintk("%s\n", __FUNCTION__);
- // calculate divisor
- // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
- tuner_frequency =
- (((fe_params->frequency / 1000) * 6) + 217280) / 1000;
-
- // setup tuner buffer
- tuner_buf[0] = tuner_frequency >> 8;
- tuner_buf[1] = tuner_frequency & 0xff;
- tuner_buf[2] = 0xca;
- tuner_buf[3] = (cp << 5) | (filter << 3) | band;
-
- // tune it
- if (tda_state->fe_type == FE_TYPE_TDA10046H) {
- // setup auto offset
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x80, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0);
-
- // disable agc_conf[2]
- tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 0);
- }
- tda1004x_enable_tuner_i2c(i2c, tda_state);
- tuner_msg.addr = tda_state->tuner_address;
- tuner_msg.len = 4;
- if (i2c_transfer(i2c, &tuner_msg, 1) != 1) {
- return -EIO;
- }
- msleep(1);
- tda1004x_disable_tuner_i2c(i2c, tda_state);
- if (tda_state->fe_type == FE_TYPE_TDA10046H)
- tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 4);
- break;
+ if (state->initialised) return 0;
- default:
- return -EINVAL;
+ if (tda10046_fwupload(fe)) {
+ printk("tda1004x: firmware upload failed\n");
+ return -EIO;
}
- dprintk("%s: success\n", __FUNCTION__);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip
+ // Init the PLL
+ if (state->config->pll_init) {
+ tda1004x_enable_tuner_i2c(state);
+ state->config->pll_init(fe);
+ tda1004x_disable_tuner_i2c(state);
+ }
+
+ // tda setup
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
+ tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0x40);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
+ tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
+ tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0); // AGC setup
+ tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities
+ tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // }
+ tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
+ tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // }
+ tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // }
+ tda1004x_write_mask(state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits
+ tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
+ tda1004x_write_mask(state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm
+ tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
+ tda1004x_write_mask(state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config
+ tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN
+ tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
+ tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
+ tda1004x_write_mask(state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select
+ tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
+
+ state->initialised = 1;
return 0;
}
-static int tda1004x_set_fe(struct i2c_adapter *i2c,
- struct tda1004x_state *tda_state,
+static int tda1004x_set_fe(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fe_params)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
int tmp;
int inversion;
dprintk("%s\n", __FUNCTION__);
+ if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
+ // setup auto offset
+ tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0);
+
+ // disable agc_conf[2]
+ tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0);
+ }
+
// set frequency
- if ((tmp = tda1004x_set_frequency(i2c, tda_state, fe_params)) < 0)
- return tmp;
+ tda1004x_enable_tuner_i2c(state);
+ state->config->pll_set(fe, fe_params);
+ tda1004x_disable_tuner_i2c(state);
+
+ if (state->demod_type == TDA1004X_DEMOD_TDA10046)
+ tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 4);
// Hardcoded to use auto as much as possible
// The TDA10045 is very unreliable if AUTO mode is _not_ used. I have not
@@ -783,35 +628,35 @@ static int tda1004x_set_fe(struct i2c_adapter *i2c,
(fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
(fe_params->u.ofdm.constellation == QAM_AUTO) ||
(fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 1, 1); // enable auto
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits
+ tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
+ tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits
} else {
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 1, 0); // disable auto
+ tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto
// set HP FEC
tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP);
if (tmp < 0) return tmp;
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 7, tmp);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
// set LP FEC
tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
if (tmp < 0) return tmp;
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
// set constellation
switch (fe_params->u.ofdm.constellation) {
case QPSK:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 0);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
break;
case QAM_16:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 1);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1);
break;
case QAM_64:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 2);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2);
break;
default:
@@ -821,19 +666,19 @@ static int tda1004x_set_fe(struct i2c_adapter *i2c,
// set hierarchy
switch (fe_params->u.ofdm.hierarchy_information) {
case HIERARCHY_NONE:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
break;
case HIERARCHY_1:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5);
break;
case HIERARCHY_2:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5);
break;
case HIERARCHY_4:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5);
break;
default:
@@ -842,30 +687,26 @@ static int tda1004x_set_fe(struct i2c_adapter *i2c,
}
// set bandwidth
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- tda10045h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth);
+ switch(state->demod_type) {
+ case TDA1004X_DEMOD_TDA10045:
+ tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
break;
- case FE_TYPE_TDA10046H:
- tda10046h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth);
+ case TDA1004X_DEMOD_TDA10046:
+ tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
break;
}
- // need to invert the inversion for TT TDA10046H
- inversion = fe_params->inversion;
- if (tda_state->fe_type == FE_TYPE_TDA10046H) {
- inversion = inversion ? INVERSION_OFF : INVERSION_ON;
- }
-
// set inversion
+ inversion = fe_params->inversion;
+ if (state->config->invert) inversion = inversion ? INVERSION_OFF : INVERSION_ON;
switch (inversion) {
case INVERSION_OFF:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0);
+ tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0);
break;
case INVERSION_ON:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0x20);
+ tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20);
break;
default:
@@ -875,28 +716,28 @@ static int tda1004x_set_fe(struct i2c_adapter *i2c,
// set guard interval
switch (fe_params->u.ofdm.guard_interval) {
case GUARD_INTERVAL_1_32:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
break;
case GUARD_INTERVAL_1_16:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2);
break;
case GUARD_INTERVAL_1_8:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2);
break;
case GUARD_INTERVAL_1_4:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2);
break;
case GUARD_INTERVAL_AUTO:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 2);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
break;
default:
@@ -906,18 +747,18 @@ static int tda1004x_set_fe(struct i2c_adapter *i2c,
// set transmission mode
switch (fe_params->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
break;
case TRANSMISSION_MODE_8K:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4);
break;
case TRANSMISSION_MODE_AUTO:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 4);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 0);
+ tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4);
+ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0);
break;
default:
@@ -925,15 +766,15 @@ static int tda1004x_set_fe(struct i2c_adapter *i2c,
}
// start the lock
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0);
+ switch(state->demod_type) {
+ case TDA1004X_DEMOD_TDA10045:
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0);
msleep(10);
break;
- case FE_TYPE_TDA10046H:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x40, 0x40);
+ case TDA1004X_DEMOD_TDA10046:
+ tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
msleep(10);
break;
}
@@ -941,25 +782,22 @@ static int tda1004x_set_fe(struct i2c_adapter *i2c,
return 0;
}
-static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, struct dvb_frontend_parameters *fe_params)
+static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
dprintk("%s\n", __FUNCTION__);
// inversion status
fe_params->inversion = INVERSION_OFF;
- if (tda1004x_read_byte(i2c, tda_state, TDA1004X_CONFC1) & 0x20) {
+ if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) {
fe_params->inversion = INVERSION_ON;
}
-
- // need to invert the inversion for TT TDA10046H
- if (tda_state->fe_type == FE_TYPE_TDA10046H) {
- fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
- }
+ if (state->config->invert) fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON;
// bandwidth
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- switch (tda1004x_read_byte(i2c, tda_state, TDA10045H_WREF_LSB)) {
+ switch(state->demod_type) {
+ case TDA1004X_DEMOD_TDA10045:
+ switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
case 0x14:
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
break;
@@ -972,8 +810,8 @@ static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_s
}
break;
- case FE_TYPE_TDA10046H:
- switch (tda1004x_read_byte(i2c, tda_state, TDA10046H_TIME_WREF1)) {
+ case TDA1004X_DEMOD_TDA10046:
+ switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
case 0x60:
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
break;
@@ -989,12 +827,12 @@ static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_s
// FEC
fe_params->u.ofdm.code_rate_HP =
- tda1004x_decode_fec(tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF2) & 7);
+ tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
fe_params->u.ofdm.code_rate_LP =
- tda1004x_decode_fec((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF2) >> 3) & 7);
+ tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
// constellation
- switch (tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 3) {
+ switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
case 0:
fe_params->u.ofdm.constellation = QPSK;
break;
@@ -1008,12 +846,12 @@ static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_s
// transmission mode
fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
- if (tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x10) {
+ if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) {
fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
}
// guard interval
- switch ((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
+ switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
case 0:
fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
break;
@@ -1029,7 +867,7 @@ static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_s
}
// hierarchy
- switch ((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
+ switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
case 0:
fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
break;
@@ -1047,8 +885,9 @@ static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_s
return 0;
}
-static int tda1004x_read_status(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, fe_status_t * fe_status)
+static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
int status;
int cber;
int vber;
@@ -1056,7 +895,7 @@ static int tda1004x_read_status(struct i2c_adapter *i2c, struct tda1004x_state*
dprintk("%s\n", __FUNCTION__);
// read status
- status = tda1004x_read_byte(i2c, tda_state, TDA1004X_STATUS_CD);
+ status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
if (status == -1) {
return -EIO;
}
@@ -1071,12 +910,12 @@ static int tda1004x_read_status(struct i2c_adapter *i2c, struct tda1004x_state*
// is getting anything valid
if (!(*fe_status & FE_HAS_VITERBI)) {
// read the CBER
- cber = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB);
+ cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
if (cber == -1) return -EIO;
- status = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB);
+ status = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
if (status == -1) return -EIO;
cber |= (status << 8);
- tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
+ tda1004x_read_byte(state, TDA1004X_CBER_RESET);
if (cber != 65535) {
*fe_status |= FE_HAS_VITERBI;
@@ -1087,15 +926,15 @@ static int tda1004x_read_status(struct i2c_adapter *i2c, struct tda1004x_state*
// bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid.
if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) {
// read the VBER
- vber = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_LSB);
+ vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB);
if (vber == -1) return -EIO;
- status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MID);
+ status = tda1004x_read_byte(state, TDA1004X_VBER_MID);
if (status == -1) return -EIO;
vber |= (status << 8);
- status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MSB);
+ status = tda1004x_read_byte(state, TDA1004X_VBER_MSB);
if (status == -1) return -EIO;
vber |= ((status << 16) & 0x0f);
- tda1004x_read_byte(i2c, tda_state, TDA1004X_CVBER_LUT);
+ tda1004x_read_byte(state, TDA1004X_CVBER_LUT);
// if RS has passed some valid TS packets, then we must be
// getting some SYNC bytes
@@ -1109,26 +948,27 @@ static int tda1004x_read_status(struct i2c_adapter *i2c, struct tda1004x_state*
return 0;
}
-static int tda1004x_read_signal_strength(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u16 * signal)
+static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
int tmp;
int reg = 0;
dprintk("%s\n", __FUNCTION__);
// determine the register to use
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
+ switch(state->demod_type) {
+ case TDA1004X_DEMOD_TDA10045:
reg = TDA10045H_S_AGC;
break;
- case FE_TYPE_TDA10046H:
+ case TDA1004X_DEMOD_TDA10046:
reg = TDA10046H_AGC_IF_LEVEL;
break;
}
// read it
- tmp = tda1004x_read_byte(i2c, tda_state, reg);
+ tmp = tda1004x_read_byte(state, reg);
if (tmp < 0)
return -EIO;
@@ -1137,14 +977,15 @@ static int tda1004x_read_signal_strength(struct i2c_adapter *i2c, struct tda1004
return 0;
}
-static int tda1004x_read_snr(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u16 * snr)
+static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
int tmp;
dprintk("%s\n", __FUNCTION__);
// read it
- tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_SNR);
+ tmp = tda1004x_read_byte(state, TDA1004X_SNR);
if (tmp < 0)
return -EIO;
if (tmp) {
@@ -1156,8 +997,9 @@ static int tda1004x_read_snr(struct i2c_adapter *i2c, struct tda1004x_state* tda
return 0;
}
-static int tda1004x_read_ucblocks(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u32* ucblocks)
+static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
int tmp;
int tmp2;
int counter;
@@ -1166,16 +1008,16 @@ static int tda1004x_read_ucblocks(struct i2c_adapter *i2c, struct tda1004x_state
// read the UCBLOCKS and reset
counter = 0;
- tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR);
+ tmp = tda1004x_read_byte(state, TDA1004X_UNCOR);
if (tmp < 0)
return -EIO;
tmp &= 0x7f;
while (counter++ < 5) {
- tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0);
- tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0);
+ tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
+ tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
+ tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0);
- tmp2 = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR);
+ tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR);
if (tmp2 < 0)
return -EIO;
tmp2 &= 0x7f;
@@ -1192,373 +1034,187 @@ static int tda1004x_read_ucblocks(struct i2c_adapter *i2c, struct tda1004x_state
return 0;
}
-static int tda1004x_read_ber(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u32* ber)
+static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber)
{
+ struct tda1004x_state* state = fe->demodulator_priv;
int tmp;
dprintk("%s\n", __FUNCTION__);
// read it in
- tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB);
+ tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB);
if (tmp < 0) return -EIO;
*ber = tmp << 1;
- tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB);
+ tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB);
if (tmp < 0) return -EIO;
*ber |= (tmp << 9);
- tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET);
+ tda1004x_read_byte(state, TDA1004X_CBER_RESET);
dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber);
return 0;
}
-static int tda1004x_sleep(struct i2c_adapter *i2c, struct tda1004x_state* tda_state)
+static int tda1004x_sleep(struct dvb_frontend* fe)
{
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFADC1, 0x10, 0x10);
+ struct tda1004x_state* state = fe->demodulator_priv;
+
+ switch(state->demod_type) {
+ case TDA1004X_DEMOD_TDA10045:
+ tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10);
break;
- case FE_TYPE_TDA10046H:
- tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 1, 1);
+ case TDA1004X_DEMOD_TDA10046:
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
break;
}
return 0;
}
-static int tda1004x_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
- struct tda1004x_state *tda_state = (struct tda1004x_state *) fe->data;
- struct i2c_adapter *i2c = tda_state->i2c;
- int status = 0;
-
- dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd);
-
- switch (cmd) {
- case FE_GET_INFO:
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- memcpy(arg, &tda10045h_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_TYPE_TDA10046H:
- memcpy(arg, &tda10046h_info, sizeof(struct dvb_frontend_info));
- break;
- }
- break;
-
- case FE_READ_STATUS:
- return tda1004x_read_status(i2c, tda_state, (fe_status_t *) arg);
-
- case FE_READ_BER:
- return tda1004x_read_ber(i2c, tda_state, (u32 *) arg);
-
- case FE_READ_SIGNAL_STRENGTH:
- return tda1004x_read_signal_strength(i2c, tda_state, (u16 *) arg);
-
- case FE_READ_SNR:
- return tda1004x_read_snr(i2c, tda_state, (u16 *) arg);
-
- case FE_READ_UNCORRECTED_BLOCKS:
- return tda1004x_read_ucblocks(i2c, tda_state, (u32 *) arg);
-
- case FE_SET_FRONTEND:
- return tda1004x_set_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg);
-
- case FE_GET_FRONTEND:
- return tda1004x_get_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg);
-
- case FE_SLEEP:
- tda_state->initialised = 0;
- return tda1004x_sleep(i2c, tda_state);
-
- case FE_INIT:
-
- // don't bother reinitialising
- if (tda_state->initialised)
- return 0;
-
- // OK, perform initialisation
- switch(tda_state->fe_type) {
- case FE_TYPE_TDA10045H:
- status = tda10045h_init(i2c, tda_state);
- break;
-
- case FE_TYPE_TDA10046H:
- status = tda10046h_init(i2c, tda_state);
- break;
- }
- if (status == 0)
- tda_state->initialised = 1;
- return status;
-
- case FE_GET_TUNE_SETTINGS:
- {
- struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg;
- fesettings->min_delay_ms = 800;
- fesettings->step_size = 166667;
- fesettings->max_drift = 166667*2;
- return 0;
- }
-
- default:
- return -EOPNOTSUPP;
- }
-
+ fesettings->min_delay_ms = 800;
+ fesettings->step_size = 166667;
+ fesettings->max_drift = 166667*2;
return 0;
}
-static int tda1004x_attach(struct i2c_adapter *i2c, struct tda1004x_state* state)
+static void tda1004x_release(struct dvb_frontend* fe)
{
- int tda1004x_address = -1;
- int tuner_address = -1;
- int fe_type = -1;
- int tuner_type = -1;
- struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=NULL, .len=0 };
- static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab };
- static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
- static u8 td1316_init_tda10046h[] = { 0x0b, 0xf5, 0x80, 0xab };
-
- dprintk("%s\n", __FUNCTION__);
-
- // probe for tda10045h
- if (tda1004x_address == -1) {
- state->tda1004x_address = 0x08;
- if (tda1004x_read_byte(i2c, state, TDA1004X_CHIPID) == 0x25) {
- tda1004x_address = 0x08;
- fe_type = FE_TYPE_TDA10045H;
- printk("tda1004x: Detected Philips TDA10045H.\n");
- }
- }
-
- // probe for tda10046h
- if (tda1004x_address == -1) {
- state->tda1004x_address = 0x08;
- if (tda1004x_read_byte(i2c, state, TDA1004X_CHIPID) == 0x46) {
- tda1004x_address = 0x08;
- fe_type = FE_TYPE_TDA10046H;
- printk("tda1004x: Detected Philips TDA10046H.\n");
- }
- }
-
- // did we find a frontend?
- if (tda1004x_address == -1) {
- return -ENODEV;
- }
-
- // enable access to the tuner
- tda1004x_enable_tuner_i2c(i2c, state);
-
- // check for a TD1344 first
- if (tuner_address == -1) {
- tuner_msg.addr = 0x61;
- tuner_msg.buf = td1344_init;
- tuner_msg.len = sizeof(td1344_init);
- if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
- msleep(1);
- tuner_address = 0x61;
- tuner_type = TUNER_TYPE_TD1344;
- printk("tda1004x: Detected Philips TD1344 tuner.\n");
- }
- }
-
- // OK, try a TD1316 on address 0x63
- if (tuner_address == -1) {
- tuner_msg.addr = 0x63;
- tuner_msg.buf = td1316_init;
- tuner_msg.len = sizeof(td1316_init);
- if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
- msleep(1);
- tuner_address = 0x63;
- tuner_type = TUNER_TYPE_TD1316;
- printk("tda1004x: Detected Philips TD1316 tuner.\n");
- }
- }
-
- // OK, TD1316 again, on address 0x60 (TDA10046H)
- if (tuner_address == -1) {
- tuner_msg.addr = 0x60;
- tuner_msg.buf = td1316_init_tda10046h;
- tuner_msg.len = sizeof(td1316_init_tda10046h);
- if (i2c_transfer(i2c, &tuner_msg, 1) == 1) {
- msleep(1);
- tuner_address = 0x60;
- tuner_type = TUNER_TYPE_TD1316;
- printk("tda1004x: Detected Philips TD1316 tuner.\n");
- }
- }
- tda1004x_disable_tuner_i2c(i2c, state);
-
- // did we find a tuner?
- if (tuner_address == -1) {
- printk("tda1004x: Detected, but with unknown tuner.\n");
- return -ENODEV;
- }
-
- // create state
- state->tda1004x_address = tda1004x_address;
- state->fe_type = fe_type;
- state->tuner_address = tuner_address;
- state->tuner_type = tuner_type;
- state->initialised = 0;
-
- return 0;
+ struct tda1004x_state* state = (struct tda1004x_state*) fe->demodulator_priv;
+ kfree(state);
}
-static struct i2c_client client_template;
+static struct dvb_frontend_ops tda10045_ops;
-static int attach_adapter(struct i2c_adapter *adapter)
+struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+ struct i2c_adapter* i2c)
{
- struct i2c_client *client;
- struct tda1004x_state *state;
- int ret;
+ struct tda1004x_state* state = NULL;
- dprintk ("%s\n", __FUNCTION__);
+ /* allocate memory for the internal state */
+ state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
+ if (state == NULL) goto error;
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- return -ENOMEM;
- }
-
- if (NULL == (state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL))) {
- kfree(client);
- return -ENOMEM;
- }
- state->i2c = adapter;
-
- ret = tda1004x_attach(adapter, state);
- if (ret) {
- kfree(state);
- kfree(client);
- return -ENODEV;
- }
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = state->tda1004x_address;
- i2c_set_clientdata(client, (void*)state);
-
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(client);
- kfree(state);
- return ret;
- }
-
- // upload firmware
- BUG_ON(!state->dvb);
-
- switch(state->fe_type) {
- case FE_TYPE_TDA10045H:
- state->dspCodeCounterReg = TDA10045H_FWPAGE;
- state->dspCodeInReg = TDA10045H_CODE_IN;
- state->dspVersion = 0x2c;
-
- ret = tda10045_fwupload(adapter, state, client);
- if (ret) {
- printk("tda1004x: firmware upload failed\n");
- goto out;
- }
-
- ret = dvb_register_frontend(tda1004x_ioctl, state->dvb,
- state, &tda10045h_info,
- THIS_MODULE);
- break;
- case FE_TYPE_TDA10046H:
- state->dspCodeCounterReg = TDA10046H_CODE_CPT;
- state->dspCodeInReg = TDA10046H_CODE_IN;
- state->dspVersion = 0x20;
-
- ret = tda10046_fwupload(adapter, state, client);
- if (ret) {
- printk("tda1004x: firmware upload failed\n");
- goto out;
- }
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
+ state->initialised = 0;
+ state->demod_type = TDA1004X_DEMOD_TDA10045;
- ret = dvb_register_frontend(tda1004x_ioctl, state->dvb,
- state, &tda10046h_info,
- THIS_MODULE);
- break;
- default:
- BUG_ON(1);
- }
+ /* check if the demod is there */
+ if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) goto error;
- if (ret) {
- printk("tda1004x: registering frontend failed\n");
- goto out;
- }
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
- return 0;
-out:
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return ret;
+error:
+ if (state) kfree(state);
+ return NULL;
}
-static int detach_client(struct i2c_client *client)
+static struct dvb_frontend_ops tda10046_ops;
+
+struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+ struct i2c_adapter* i2c)
{
- struct tda1004x_state *state = (struct tda1004x_state*)i2c_get_clientdata(client);
+ struct tda1004x_state* state = NULL;
- dprintk ("%s\n", __FUNCTION__);
+ /* allocate memory for the internal state */
+ state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
+ if (state == NULL) goto error;
- dvb_unregister_frontend (tda1004x_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
- return 0;
-}
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
+ state->initialised = 0;
+ state->demod_type = TDA1004X_DEMOD_TDA10046;
-static int command (struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct tda1004x_state *state = (struct tda1004x_state*)i2c_get_clientdata(client);
+ /* check if the demod is there */
+ if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) goto error;
- dprintk ("%s\n", __FUNCTION__);
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
- switch (cmd) {
- case FE_REGISTER:
- state->dvb = (struct dvb_adapter*)arg;
- break;
- case FE_UNREGISTER:
- state->dvb = NULL;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
+error:
+ if (state) kfree(state);
+ return NULL;
}
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = FRONTEND_NAME,
- .id = I2C_DRIVERID_DVBFE_TDA1004X,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
+static struct dvb_frontend_ops tda10045_ops = {
+
+ .info = {
+ .name = "Philips TDA10045H DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166667,
+ .caps =
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+ },
+
+ .release = tda1004x_release,
+
+ .init = tda10045_init,
+ .sleep = tda1004x_sleep,
+
+ .set_frontend = tda1004x_set_fe,
+ .get_frontend = tda1004x_get_fe,
+
+ .read_status = tda1004x_read_status,
+ .read_ber = tda1004x_read_ber,
+ .read_signal_strength = tda1004x_read_signal_strength,
+ .read_snr = tda1004x_read_snr,
+ .read_ucblocks = tda1004x_read_ucblocks,
};
-static struct i2c_client client_template = {
- .name = FRONTEND_NAME,
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
+static struct dvb_frontend_ops tda10046_ops = {
+
+ .info = {
+ .name = "Philips TDA10046H DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166667,
+ .caps =
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+ },
+
+ .release = tda1004x_release,
+
+ .init = tda10046_init,
+ .sleep = tda1004x_sleep,
+
+ .set_frontend = tda1004x_set_fe,
+ .get_frontend = tda1004x_get_fe,
+ .get_tune_settings = tda1004x_get_tune_settings,
+
+ .read_status = tda1004x_read_status,
+ .read_ber = tda1004x_read_ber,
+ .read_signal_strength = tda1004x_read_signal_strength,
+ .read_snr = tda1004x_read_snr,
+ .read_ucblocks = tda1004x_read_ucblocks,
};
-static int __init init_tda1004x(void)
-{
- return i2c_add_driver(&driver);
-}
-
-static void __exit exit_tda1004x(void)
-{
- if (i2c_del_driver(&driver))
- printk("tda1004x: driver deregistration failed\n");
-}
-
-module_init(init_tda1004x);
-module_exit(exit_tda1004x);
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Frontend");
+MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator");
MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(tda10045_attach);
+EXPORT_SYMBOL(tda10046_attach);
+EXPORT_SYMBOL(tda1004x_write_byte);
diff --git a/linux/drivers/media/dvb/frontends/tda1004x.h b/linux/drivers/media/dvb/frontends/tda1004x.h
new file mode 100644
index 000000000..22004e188
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda1004x.h
@@ -0,0 +1,53 @@
+ /*
+ Driver for Philips tda1004xh OFDM Frontend
+
+ (c) 2004 Andrew de Quincey
+
+ 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 TDA1004X_H
+#define TDA1004X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct tda1004x_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* does the "inversion" need inverted? */
+ u8 invert:1;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+ /* request firmware for device */
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+ struct i2c_adapter* i2c);
+
+extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+ struct i2c_adapter* i2c);
+
+extern int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data);
+
+#endif // TDA1004X_H
diff --git a/linux/drivers/media/dvb/frontends/tda8083.c b/linux/drivers/media/dvb/frontends/tda8083.c
new file mode 100644
index 000000000..03c4366e1
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda8083.c
@@ -0,0 +1,490 @@
+/*
+ Driver for Philips TDA8083 based QPSK Demodulator
+
+ Copyright (C) 2001 Convergence Integrated Media GmbH
+
+ written by Ralph Metzler <ralph@convergence.de>
+
+ adoption to the new DVB frontend API and diagnostic ioctl's
+ by Holger Waechtler <holger@convergence.de>
+
+ 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "tda8083.h"
+
+
+struct tda8083_state {
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct tda8083_config* config;
+
+ struct dvb_frontend frontend;
+};
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "tda8083: " args); \
+ } while (0)
+
+
+static u8 tda8083_init_tab [] = {
+ 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea,
+ 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10,
+ 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8,
+ 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00,
+ 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+
+static int tda8083_writereg (struct tda8083_state* state, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf [] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ dprintk ("%s: writereg error (reg %02x, ret == %i)\n",
+ __FUNCTION__, reg, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+
+static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len)
+{
+ int ret;
+ struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ dprintk ("%s: readreg error (reg %02x, ret == %i)\n",
+ __FUNCTION__, reg1, ret);
+
+ return ret == 2 ? 0 : -1;
+}
+
+
+static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg)
+{
+ u8 val;
+
+ tda8083_readregs (state, reg, &val, 1);
+
+ return val;
+}
+
+
+
+static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion)
+{
+ /* XXX FIXME: implement other modes than FEC_AUTO */
+ if (inversion == INVERSION_AUTO)
+ return 0;
+
+ return -EINVAL;
+}
+
+
+static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec)
+{
+ if (fec == FEC_AUTO)
+ return tda8083_writereg (state, 0x07, 0xff);
+
+ if (fec >= FEC_1_2 && fec <= FEC_8_9)
+ return tda8083_writereg (state, 0x07, 1 << (FEC_8_9 - fec));
+
+ return -EINVAL;
+}
+
+
+static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state)
+{
+ u8 index;
+ static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
+ FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 };
+
+ index = tda8083_readreg(state, 0x0e) & 0x07;
+
+ return fec_tab [index];
+}
+
+
+static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate)
+{
+ u32 ratio;
+ u32 tmp;
+ u8 filter;
+
+ if (srate > 32000000)
+ srate = 32000000;
+ if (srate < 500000)
+ srate = 500000;
+
+ filter = 0;
+ if (srate < 24000000)
+ filter = 2;
+ if (srate < 16000000)
+ filter = 3;
+
+ tmp = 31250 << 16;
+ ratio = tmp / srate;
+
+ tmp = (tmp % srate) << 8;
+ ratio = (ratio << 8) + tmp / srate;
+
+ tmp = (tmp % srate) << 8;
+ ratio = (ratio << 8) + tmp / srate;
+
+ dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio);
+
+ tda8083_writereg (state, 0x05, filter);
+ tda8083_writereg (state, 0x02, (ratio >> 16) & 0xff);
+ tda8083_writereg (state, 0x03, (ratio >> 8) & 0xff);
+ tda8083_writereg (state, 0x04, (ratio ) & 0xff);
+
+ tda8083_writereg (state, 0x00, 0x3c);
+ tda8083_writereg (state, 0x00, 0x04);
+
+ return 1;
+}
+
+
+static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout)
+{
+ unsigned long start = jiffies;
+
+ while (jiffies - start < timeout &&
+ !(tda8083_readreg(state, 0x02) & 0x80))
+ {
+ msleep(50);
+ };
+}
+
+static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone)
+{
+ tda8083_writereg (state, 0x26, 0xf1);
+
+ switch (tone) {
+ case SEC_TONE_OFF:
+ return tda8083_writereg (state, 0x29, 0x00);
+ case SEC_TONE_ON:
+ return tda8083_writereg (state, 0x29, 0x80);
+ default:
+ return -EINVAL;
+ };
+}
+
+
+static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage)
+{
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ return tda8083_writereg (state, 0x20, 0x00);
+ case SEC_VOLTAGE_18:
+ return tda8083_writereg (state, 0x20, 0x11);
+ default:
+ return -EINVAL;
+ };
+}
+
+static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst)
+{
+ switch (burst) {
+ case SEC_MINI_A:
+ tda8083_writereg (state, 0x29, (5 << 2)); /* send burst A */
+ break;
+ case SEC_MINI_B:
+ tda8083_writereg (state, 0x29, (7 << 2)); /* send B */
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ tda8083_wait_diseqc_fifo (state, 100);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int tda8083_send_diseqc_msg (struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *m)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+ int i;
+
+ tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */
+
+ for (i=0; i<m->msg_len; i++)
+ tda8083_writereg (state, 0x23 + i, m->msg[i]);
+
+ tda8083_writereg (state, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */
+
+ tda8083_wait_diseqc_fifo (state, 100);
+
+ return 0;
+}
+
+static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ u8 signal = ~tda8083_readreg (state, 0x01);
+ u8 sync = tda8083_readreg (state, 0x02);
+
+ *status = 0;
+
+ if (signal > 10)
+ *status |= FE_HAS_SIGNAL;
+
+ if (sync & 0x01)
+ *status |= FE_HAS_CARRIER;
+
+ if (sync & 0x02)
+ *status |= FE_HAS_VITERBI;
+
+ if (sync & 0x10)
+ *status |= FE_HAS_SYNC;
+
+ if ((sync & 0x1f) == 0x1f)
+ *status |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ u8 signal = ~tda8083_readreg (state, 0x01);
+ *strength = (signal << 8) | signal;
+
+ return 0;
+}
+
+static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ u8 _snr = tda8083_readreg (state, 0x08);
+ *snr = (_snr << 8) | _snr;
+
+ return 0;
+}
+
+static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ state->config->pll_set(fe, p);
+ tda8083_set_inversion (state, p->inversion);
+ tda8083_set_fec (state, p->u.qpsk.fec_inner);
+ tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
+
+ tda8083_writereg (state, 0x00, 0x3c);
+ tda8083_writereg (state, 0x00, 0x04);
+
+ return 0;
+}
+
+static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ /* FIXME: get symbolrate & frequency offset...*/
+ /*p->frequency = ???;*/
+ p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ?
+ INVERSION_ON : INVERSION_OFF;
+ p->u.qpsk.fec_inner = tda8083_get_fec (state);
+ /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/
+
+ return 0;
+}
+
+static int tda8083_sleep(struct dvb_frontend* fe)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ tda8083_writereg (state, 0x00, 0x02);
+ return 0;
+}
+
+static int tda8083_init(struct dvb_frontend* fe)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+ int i;
+
+ for (i=0; i<44; i++)
+ tda8083_writereg (state, i, tda8083_init_tab[i]);
+
+ if (state->config->pll_init) state->config->pll_init(fe);
+
+ tda8083_writereg (state, 0x00, 0x3c);
+ tda8083_writereg (state, 0x00, 0x04);
+
+ return 0;
+}
+
+static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ tda8083_send_diseqc_burst (state, burst);
+ tda8083_writereg (state, 0x00, 0x3c);
+ tda8083_writereg (state, 0x00, 0x04);
+
+ return 0;
+}
+
+static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ tda8083_set_tone (state, tone);
+ tda8083_writereg (state, 0x00, 0x3c);
+ tda8083_writereg (state, 0x00, 0x04);
+
+ return 0;
+}
+
+static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+ tda8083_set_voltage (state, voltage);
+ tda8083_writereg (state, 0x00, 0x3c);
+ tda8083_writereg (state, 0x00, 0x04);
+
+ return 0;
+}
+
+static void tda8083_release(struct dvb_frontend* fe)
+{
+ struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops tda8083_ops;
+
+struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct tda8083_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct tda8083_state*) kmalloc(sizeof(struct tda8083_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
+
+ /* check if the demod is there */
+ if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops tda8083_ops = {
+
+ .info = {
+ .name = "Philips TDA8083 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000, /* FIXME: guessed! */
+ .frequency_max = 1400000, /* FIXME: guessed! */
+ .frequency_stepsize = 125, /* kHz for QPSK frontends */
+ /* .frequency_tolerance = ???,*/
+ .symbol_rate_min = 1000000, /* FIXME: guessed! */
+ .symbol_rate_max = 45000000, /* FIXME: guessed! */
+ /* .symbol_rate_tolerance = ???,*/
+ .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_8_9 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_MUTE_TS
+ },
+
+ .release = tda8083_release,
+
+ .init = tda8083_init,
+ .sleep = tda8083_sleep,
+
+ .set_frontend = tda8083_set_frontend,
+ .get_frontend = tda8083_get_frontend,
+
+ .read_status = tda8083_read_status,
+ .read_signal_strength = tda8083_read_signal_strength,
+ .read_snr = tda8083_read_snr,
+
+ .diseqc_send_master_cmd = tda8083_send_diseqc_msg,
+ .diseqc_send_burst = tda8083_diseqc_send_burst,
+ .set_tone = tda8083_diseqc_set_tone,
+ .set_voltage = tda8083_diseqc_set_voltage,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda8083_attach);
diff --git a/linux/drivers/media/dvb/frontends/tda8083.h b/linux/drivers/media/dvb/frontends/tda8083.h
new file mode 100644
index 000000000..466663307
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda8083.h
@@ -0,0 +1,45 @@
+/*
+ Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend
+
+ Copyright (C) 2001 Convergence Integrated Media GmbH
+
+ written by Ralph Metzler <ralph@convergence.de>
+
+ adoption to the new DVB frontend API and diagnostic ioctl's
+ by Holger Waechtler <holger@convergence.de>
+
+ 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 TDA8083_H
+#define TDA8083_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda8083_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // TDA8083_H
diff --git a/linux/drivers/media/dvb/frontends/tda80xx.c b/linux/drivers/media/dvb/frontends/tda80xx.c
new file mode 100644
index 000000000..29c5b8627
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda80xx.c
@@ -0,0 +1,749 @@
+/*
+ * tda80xx.c
+ *
+ * Philips TDA8044 / TDA8083 QPSK demodulator driver
+ *
+ * Copyright (C) 2001 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2002-2004 Andreas Oberritter <obi@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/config.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "tda80xx.h"
+
+enum {
+ ID_TDA8044 = 0x04,
+ ID_TDA8083 = 0x05,
+};
+
+
+struct tda80xx_state {
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct tda80xx_config* config;
+
+ struct dvb_frontend frontend;
+
+ u32 clk;
+ int afc_loop;
+ struct work_struct worklet;
+ fe_code_rate_t code_rate;
+ fe_spectral_inversion_t spectral_inversion;
+ fe_status_t status;
+ u8 id;
+};
+
+static int debug = 1;
+#define dprintk if (debug) printk
+
+static u8 tda8044_inittab_pre[] = {
+ 0x02, 0x00, 0x6f, 0xb5, 0x86, 0x22, 0x00, 0xea,
+ 0x30, 0x42, 0x98, 0x68, 0x70, 0x42, 0x99, 0x58,
+ 0x95, 0x10, 0xf5, 0xe7, 0x93, 0x0b, 0x15, 0x68,
+ 0x9a, 0x90, 0x61, 0x80, 0x00, 0xe0, 0x40, 0x00,
+ 0x0f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
+
+static u8 tda8044_inittab_post[] = {
+ 0x04, 0x00, 0x6f, 0xb5, 0x86, 0x22, 0x00, 0xea,
+ 0x30, 0x42, 0x98, 0x68, 0x70, 0x42, 0x99, 0x50,
+ 0x95, 0x10, 0xf5, 0xe7, 0x93, 0x0b, 0x15, 0x68,
+ 0x9a, 0x90, 0x61, 0x80, 0x00, 0xe0, 0x40, 0x6c,
+ 0x0f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
+
+static u8 tda8083_inittab[] = {
+ 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea,
+ 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10,
+ 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8,
+ 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00,
+ 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static __inline__ u32 tda80xx_div(u32 a, u32 b)
+{
+ return (a + (b / 2)) / b;
+}
+
+static __inline__ u32 tda80xx_gcd(u32 a, u32 b)
+{
+ u32 r;
+
+ while ((r = a % b)) {
+ a = b;
+ b = r;
+ }
+
+ return b;
+}
+
+static int tda80xx_read(struct tda80xx_state* state, u8 reg, u8 *buf, u8 len)
+{
+ int ret;
+ struct i2c_msg msg[] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ dprintk("%s: readreg error (reg %02x, ret == %i)\n",
+ __FUNCTION__, reg, ret);
+
+ mdelay(10);
+
+ return (ret == 2) ? 0 : -EREMOTEIO;
+}
+
+static int tda80xx_write(struct tda80xx_state* state, u8 reg, const u8 *buf, u8 len)
+{
+ int ret;
+ u8 wbuf[len + 1];
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = wbuf, .len = len + 1 };
+
+ wbuf[0] = reg;
+ memcpy(&wbuf[1], buf, len);
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ dprintk("%s: i2c xfer error (ret == %i)\n", __FUNCTION__, ret);
+
+ mdelay(10);
+
+ return (ret == 1) ? 0 : -EREMOTEIO;
+}
+
+static __inline__ u8 tda80xx_readreg(struct tda80xx_state* state, u8 reg)
+{
+ u8 val;
+
+ tda80xx_read(state, reg, &val, 1);
+
+ return val;
+}
+
+static __inline__ int tda80xx_writereg(struct tda80xx_state* state, u8 reg, u8 data)
+{
+ return tda80xx_write(state, reg, &data, 1);
+}
+
+static int tda80xx_set_parameters(struct tda80xx_state* state,
+ fe_spectral_inversion_t inversion,
+ u32 symbol_rate,
+ fe_code_rate_t fec_inner)
+{
+ u8 buf[15];
+ u64 ratio;
+ u32 clk;
+ u32 k;
+ u32 sr = symbol_rate;
+ u32 gcd;
+ u8 scd;
+
+ if (symbol_rate > (state->clk * 3) / 16)
+ scd = 0;
+ else if (symbol_rate > (state->clk * 3) / 32)
+ scd = 1;
+ else if (symbol_rate > (state->clk * 3) / 64)
+ scd = 2;
+ else
+ scd = 3;
+
+ clk = scd ? (state->clk / (scd * 2)) : state->clk;
+
+ /*
+ * Viterbi decoder:
+ * Differential decoding off
+ * Spectral inversion unknown
+ * QPSK modulation
+ */
+ if (inversion == INVERSION_ON)
+ buf[0] = 0x60;
+ else if (inversion == INVERSION_OFF)
+ buf[0] = 0x20;
+ else
+ buf[0] = 0x00;
+
+ /*
+ * CLK ratio:
+ * system clock frequency is up to 64 or 96 MHz
+ *
+ * formula:
+ * r = k * clk / symbol_rate
+ *
+ * k: 2^21 for caa 0..3,
+ * 2^20 for caa 4..5,
+ * 2^19 for caa 6..7
+ */
+ if (symbol_rate <= (clk * 3) / 32)
+ k = (1 << 19);
+ else if (symbol_rate <= (clk * 3) / 16)
+ k = (1 << 20);
+ else
+ k = (1 << 21);
+
+ gcd = tda80xx_gcd(clk, sr);
+ clk /= gcd;
+ sr /= gcd;
+
+ gcd = tda80xx_gcd(k, sr);
+ k /= gcd;
+ sr /= gcd;
+
+ ratio = (u64)k * (u64)clk;
+ do_div(ratio, sr);
+
+ buf[1] = ratio >> 16;
+ buf[2] = ratio >> 8;
+ buf[3] = ratio;
+
+ /* nyquist filter roll-off factor 35% */
+ buf[4] = 0x20;
+
+ clk = scd ? (state->clk / (scd * 2)) : state->clk;
+
+ /* Anti Alias Filter */
+ if (symbol_rate < (clk * 3) / 64)
+ printk("tda80xx: unsupported symbol rate: %u\n", symbol_rate);
+ else if (symbol_rate <= clk / 16)
+ buf[4] |= 0x07;
+ else if (symbol_rate <= (clk * 3) / 32)
+ buf[4] |= 0x06;
+ else if (symbol_rate <= clk / 8)
+ buf[4] |= 0x05;
+ else if (symbol_rate <= (clk * 3) / 16)
+ buf[4] |= 0x04;
+ else if (symbol_rate <= clk / 4)
+ buf[4] |= 0x03;
+ else if (symbol_rate <= (clk * 3) / 8)
+ buf[4] |= 0x02;
+ else if (symbol_rate <= clk / 2)
+ buf[4] |= 0x01;
+ else
+ buf[4] |= 0x00;
+
+ /* Sigma Delta converter */
+ buf[5] = 0x00;
+
+ /* FEC: Possible puncturing rates */
+ if (fec_inner == FEC_NONE)
+ buf[6] = 0x00;
+ else if ((fec_inner >= FEC_1_2) && (fec_inner <= FEC_8_9))
+ buf[6] = (1 << (8 - fec_inner));
+ else if (fec_inner == FEC_AUTO)
+ buf[6] = 0xff;
+ else
+ return -EINVAL;
+
+ /* carrier lock detector threshold value */
+ buf[7] = 0x30;
+ /* AFC1: proportional part settings */
+ buf[8] = 0x42;
+ /* AFC1: integral part settings */
+ buf[9] = 0x98;
+ /* PD: Leaky integrator SCPC mode */
+ buf[10] = 0x28;
+ /* AFC2, AFC1 controls */
+ buf[11] = 0x30;
+ /* PD: proportional part settings */
+ buf[12] = 0x42;
+ /* PD: integral part settings */
+ buf[13] = 0x99;
+ /* AGC */
+ buf[14] = 0x50 | scd;
+
+ printk("symbol_rate=%u clk=%u\n", symbol_rate, clk);
+
+ return tda80xx_write(state, 0x01, buf, sizeof(buf));
+}
+
+static int tda80xx_set_clk(struct tda80xx_state* state)
+{
+ u8 buf[2];
+
+ /* CLK proportional part */
+ buf[0] = (0x06 << 5) | 0x08; /* CMP[2:0], CSP[4:0] */
+ /* CLK integral part */
+ buf[1] = (0x04 << 5) | 0x1a; /* CMI[2:0], CSI[4:0] */
+
+ return tda80xx_write(state, 0x17, buf, sizeof(buf));
+}
+
+#if 0
+static int tda80xx_set_scpc_freq_offset(struct tda80xx_state* state)
+{
+ /* a constant value is nonsense here imho */
+ return tda80xx_writereg(state, 0x22, 0xf9);
+}
+#endif
+
+static int tda80xx_close_loop(struct tda80xx_state* state)
+{
+ u8 buf[2];
+
+ /* PD: Loop closed, LD: lock detect enable, SCPC: Sweep mode - AFC1 loop closed */
+ buf[0] = 0x68;
+ /* AFC1: Loop closed, CAR Feedback: 8192 */
+ buf[1] = 0x70;
+
+ return tda80xx_write(state, 0x0b, buf, sizeof(buf));
+}
+
+static irqreturn_t tda80xx_irq(int irq, void *priv, struct pt_regs *pt)
+{
+ schedule_work(priv);
+
+ return IRQ_HANDLED;
+}
+
+static void tda80xx_read_status_int(struct tda80xx_state* state)
+{
+ u8 val;
+
+ static const fe_spectral_inversion_t inv_tab[] = {
+ INVERSION_OFF, INVERSION_ON
+ };
+
+ static const fe_code_rate_t fec_tab[] = {
+ FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
+ FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8,
+ };
+
+ val = tda80xx_readreg(state, 0x02);
+
+ state->status = 0;
+
+ if (val & 0x01) /* demodulator lock */
+ state->status |= FE_HAS_SIGNAL;
+ if (val & 0x02) /* clock recovery lock */
+ state->status |= FE_HAS_CARRIER;
+ if (val & 0x04) /* viterbi lock */
+ state->status |= FE_HAS_VITERBI;
+ if (val & 0x08) /* deinterleaver lock (packet sync) */
+ state->status |= FE_HAS_SYNC;
+ if (val & 0x10) /* derandomizer lock (frame sync) */
+ state->status |= FE_HAS_LOCK;
+ if (val & 0x20) /* frontend can not lock */
+ state->status |= FE_TIMEDOUT;
+
+ if ((state->status & (FE_HAS_CARRIER)) && (state->afc_loop)) {
+ printk("tda80xx: closing loop\n");
+ tda80xx_close_loop(state);
+ state->afc_loop = 0;
+ }
+
+ if (state->status & (FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK)) {
+ val = tda80xx_readreg(state, 0x0e);
+ state->code_rate = fec_tab[val & 0x07];
+ if (state->status & (FE_HAS_SYNC | FE_HAS_LOCK))
+ state->spectral_inversion = inv_tab[(val >> 7) & 0x01];
+ else
+ state->spectral_inversion = INVERSION_AUTO;
+ }
+ else {
+ state->code_rate = FEC_AUTO;
+ }
+}
+
+static void tda80xx_worklet(void *priv)
+{
+ struct tda80xx_state *state = priv;
+
+ tda80xx_writereg(state, 0x00, 0x04);
+ enable_irq(state->config->irq);
+
+ tda80xx_read_status_int(state);
+}
+
+static void tda80xx_wait_diseqc_fifo(struct tda80xx_state* state)
+{
+ size_t i;
+
+ for (i = 0; i < 100; i++) {
+ if (tda80xx_readreg(state, 0x02) & 0x80)
+ break;
+ msleep(10);
+ }
+}
+
+static int tda8044_init(struct dvb_frontend* fe)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+ int ret;
+
+ /*
+ * this function is a mess...
+ */
+
+ if ((ret = tda80xx_write(state, 0x00, tda8044_inittab_pre, sizeof(tda8044_inittab_pre))))
+ return ret;
+
+ tda80xx_writereg(state, 0x0f, 0x50);
+#if 1
+ tda80xx_writereg(state, 0x20, 0x8F); /* FIXME */
+ tda80xx_writereg(state, 0x20, state->config->volt18setting); /* FIXME */
+ //tda80xx_writereg(state, 0x00, 0x04);
+ tda80xx_writereg(state, 0x00, 0x0C);
+#endif
+ //tda80xx_writereg(state, 0x00, 0x08); /* Reset AFC1 loop filter */
+
+ tda80xx_write(state, 0x00, tda8044_inittab_post, sizeof(tda8044_inittab_post));
+
+ if (state->config->pll_init) {
+ tda80xx_writereg(state, 0x1c, 0x80);
+ state->config->pll_init(fe);
+ tda80xx_writereg(state, 0x1c, 0x00);
+ }
+
+ return 0;
+}
+
+static int tda8083_init(struct dvb_frontend* fe)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ tda80xx_write(state, 0x00, tda8083_inittab, sizeof(tda8083_inittab));
+
+ if (state->config->pll_init) {
+ tda80xx_writereg(state, 0x1c, 0x80);
+ state->config->pll_init(fe);
+ tda80xx_writereg(state, 0x1c, 0x00);
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int tda80xx_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ return tda80xx_writereg(state, 0x20, state->config->volt13setting);
+ case SEC_VOLTAGE_18:
+ return tda80xx_writereg(state, 0x20, state->config->volt18setting);
+ case SEC_VOLTAGE_OFF:
+ return tda80xx_writereg(state, 0x20, 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tda80xx_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ switch (tone) {
+ case SEC_TONE_OFF:
+ return tda80xx_writereg(state, 0x29, 0x00);
+ case SEC_TONE_ON:
+ return tda80xx_writereg(state, 0x29, 0x80);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tda80xx_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ if (cmd->msg_len > 6)
+ return -EINVAL;
+
+ tda80xx_writereg(state, 0x29, 0x08 | (cmd->msg_len - 3));
+ tda80xx_write(state, 0x23, cmd->msg, cmd->msg_len);
+ tda80xx_writereg(state, 0x29, 0x0c | (cmd->msg_len - 3));
+ tda80xx_wait_diseqc_fifo(state);
+
+ return 0;
+}
+
+static int tda80xx_send_diseqc_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t cmd)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ switch (cmd) {
+ case SEC_MINI_A:
+ tda80xx_writereg(state, 0x29, 0x14);
+ break;
+ case SEC_MINI_B:
+ tda80xx_writereg(state, 0x29, 0x1c);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tda80xx_wait_diseqc_fifo(state);
+
+ return 0;
+}
+
+static int tda80xx_sleep(struct dvb_frontend* fe)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ tda80xx_writereg(state, 0x00, 0x02); /* enter standby */
+
+ return 0;
+}
+
+static int tda80xx_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ tda80xx_writereg(state, 0x1c, 0x80);
+ state->config->pll_set(fe, p);
+ tda80xx_writereg(state, 0x1c, 0x00);
+
+ tda80xx_set_parameters(state, p->inversion, p->u.qpsk.symbol_rate, p->u.qpsk.fec_inner);
+ tda80xx_set_clk(state);
+ //tda80xx_set_scpc_freq_offset(state);
+ state->afc_loop = 1;
+
+ return 0;
+}
+
+static int tda80xx_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ if (!state->config->irq)
+ tda80xx_read_status_int(state);
+
+ p->inversion = state->spectral_inversion;
+ p->u.qpsk.fec_inner = state->code_rate;
+
+ return 0;
+}
+
+static int tda80xx_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ if (!state->config->irq)
+ tda80xx_read_status_int(state);
+ *status = state->status;
+
+ return 0;
+}
+
+static int tda80xx_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+ int ret;
+ u8 buf[3];
+
+ if ((ret = tda80xx_read(state, 0x0b, buf, sizeof(buf))))
+ return ret;
+
+ *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2];
+
+ return 0;
+}
+
+static int tda80xx_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ u8 gain = ~tda80xx_readreg(state, 0x01);
+ *strength = (gain << 8) | gain;
+
+ return 0;
+}
+
+static int tda80xx_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ u8 quality = tda80xx_readreg(state, 0x08);
+ *snr = (quality << 8) | quality;
+
+ return 0;
+}
+
+static int tda80xx_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ *ucblocks = tda80xx_readreg(state, 0x0f);
+ if (*ucblocks == 0xff)
+ *ucblocks = 0xffffffff;
+
+ return 0;
+}
+
+static int tda80xx_init(struct dvb_frontend* fe)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ switch(state->id) {
+ case ID_TDA8044:
+ return tda8044_init(fe);
+
+ case ID_TDA8083:
+ return tda8083_init(fe);
+ }
+ return 0;
+}
+
+static void tda80xx_release(struct dvb_frontend* fe)
+{
+ struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+ if (state->config->irq)
+ free_irq(state->config->irq, &state->worklet);
+
+ kfree(state);
+}
+
+static struct dvb_frontend_ops tda80xx_ops;
+
+struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct tda80xx_state* state = NULL;
+ int ret;
+
+ /* allocate memory for the internal state */
+ state = (struct tda80xx_state*) kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &tda80xx_ops, sizeof(struct dvb_frontend_ops));
+ state->spectral_inversion = INVERSION_AUTO;
+ state->code_rate = FEC_AUTO;
+ state->status = 0;
+ state->afc_loop = 0;
+
+ /* check if the demod is there */
+ if (tda80xx_writereg(state, 0x89, 0x00) < 0) goto error;
+ state->id = tda80xx_readreg(state, 0x00);
+
+ switch (state->id) {
+ case ID_TDA8044:
+ state->clk = 96000000;
+ printk("tda80xx: Detected tda8044\n");
+ break;
+
+ case ID_TDA8083:
+ state->clk = 64000000;
+ printk("tda80xx: Detected tda8083\n");
+ break;
+
+ default:
+ goto error;
+ }
+
+ /* setup IRQ */
+ if (state->config->irq) {
+ INIT_WORK(&state->worklet, tda80xx_worklet, state);
+ if ((ret = request_irq(state->config->irq, tda80xx_irq, SA_ONESHOT, "tda80xx", &state->worklet)) < 0) {
+ printk(KERN_ERR "tda80xx: request_irq failed (%d)\n", ret);
+ goto error;
+ }
+ }
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops tda80xx_ops = {
+
+ .info = {
+ .name = "Philips TDA80xx DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 500000,
+ .frequency_max = 2700000,
+ .frequency_stepsize = 125,
+ .symbol_rate_min = 4500000,
+ .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_8_9 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_MUTE_TS
+ },
+
+ .release = tda80xx_release,
+
+ .init = tda80xx_init,
+ .sleep = tda80xx_sleep,
+
+ .set_frontend = tda80xx_set_frontend,
+ .get_frontend = tda80xx_get_frontend,
+
+ .read_status = tda80xx_read_status,
+ .read_ber = tda80xx_read_ber,
+ .read_signal_strength = tda80xx_read_signal_strength,
+ .read_snr = tda80xx_read_snr,
+ .read_ucblocks = tda80xx_read_ucblocks,
+
+ .diseqc_send_master_cmd = tda80xx_send_diseqc_msg,
+ .diseqc_send_burst = tda80xx_send_diseqc_burst,
+ .set_tone = tda80xx_set_tone,
+ .set_voltage = tda80xx_set_voltage,
+};
+
+MODULE_PARM(debug,"i");
+
+MODULE_DESCRIPTION("Philips TDA8044 / TDA8083 DVB-S Demodulator driver");
+MODULE_AUTHOR("Felix Domke, Andreas Oberritter");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda80xx_attach);
diff --git a/linux/drivers/media/dvb/frontends/tda80xx.h b/linux/drivers/media/dvb/frontends/tda80xx.h
new file mode 100644
index 000000000..cd639a0aa
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda80xx.h
@@ -0,0 +1,51 @@
+/*
+ * tda80xx.c
+ *
+ * Philips TDA8044 / TDA8083 QPSK demodulator driver
+ *
+ * Copyright (C) 2001 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2002-2004 Andreas Oberritter <obi@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 TDA80XX_H
+#define TDA80XX_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda80xx_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* IRQ to use (0=>no IRQ used) */
+ u32 irq;
+
+ /* Register setting to use for 13v */
+ u8 volt13setting;
+
+ /* Register setting to use for 18v */
+ u8 volt18setting;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // TDA80XX_H
diff --git a/linux/drivers/media/dvb/frontends/ves1820.c b/linux/drivers/media/dvb/frontends/ves1820.c
index 8e2a56d33..9ad54f618 100644
--- a/linux/drivers/media/dvb/frontends/ves1820.c
+++ b/linux/drivers/media/dvb/frontends/ves1820.c
@@ -1,6 +1,5 @@
/*
VES1820 - Single Chip Cable Channel Receiver driver module
- used on the the Siemens DVB-C cards
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
@@ -27,68 +26,34 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <asm/div64.h>
#include "dvb_frontend.h"
+#include "ves1820.h"
-/* I2C_DRIVERID_VES1820 is already defined in i2c-id.h */
-#if 0
-static int debug = 0;
-#define dprintk if (debug) printk
-#endif
-
-static int verbose;
struct ves1820_state {
- int pwm;
+
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct ves1820_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* private demodulator data */
u8 reg0;
- int tuner;
- u8 demod_addr;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
+ u8 pwm;
};
-/* possible ves1820 adresses */
-static u8 addr[] = { 0x61, 0x62 };
-
-#if defined(CONFIG_DBOX2)
-#define XIN 69600000UL
-#define DISABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0)
-#define ENABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0)
-#define HAS_INVERSION(reg0) (reg0 & 0x20)
-#else /* PCI cards */
-#define XIN 57840000UL
-#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0)
-#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0)
-#define HAS_INVERSION(reg0) (!(reg0 & 0x20))
-#endif
-
-#define FIN (XIN >> 4)
-
-static struct dvb_frontend_info ves1820_info = {
- .name = "VES1820 based DVB-C frontend",
- .type = FE_QAM,
- .frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
- .symbol_rate_min = (XIN / 2) / 64, /* SACLK/64 == (XIN/2)/64 */
- .symbol_rate_max = (XIN / 2) / 4, /* SACLK/4 */
-#if 0
- .frequency_tolerance = ? ? ?,
- .symbol_rate_tolerance = ? ? ?, /* ppm *//* == 8% (spec p. 5) */
- .notifier_delay = ?,
-#endif
- .caps = FE_CAN_QAM_16 |
- FE_CAN_QAM_32 |
- FE_CAN_QAM_64 |
- FE_CAN_QAM_128 |
- FE_CAN_QAM_256 |
- FE_CAN_FEC_AUTO |
- FE_CAN_INVERSION_AUTO,
-};
+
+static int verbose;
static u8 ves1820_inittab[] = {
- 0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A,
+ 0x69, 0x6A, 0x93, 0x12, 0x12, 0x46, 0x26, 0x1A,
0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
@@ -100,7 +65,7 @@ static u8 ves1820_inittab[] = {
static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
{
u8 buf[] = { 0x00, reg, data };
- struct i2c_msg msg = {.addr = state->demod_addr,.flags = 0,.buf = buf,.len = 3 };
+ struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 };
int ret;
ret = i2c_transfer(state->i2c, &msg, 1);
@@ -118,8 +83,8 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
u8 b0[] = { 0x00, reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
- {.addr = state->demod_addr,.flags = 0,.buf = b0,.len = 2},
- {.addr = state->demod_addr,.flags = I2C_M_RD,.buf = b1,.len = 1}
+ {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2},
+ {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
};
int ret;
@@ -132,147 +97,88 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
return b1[0];
}
-static int tuner_write(struct ves1820_state *state, u8 addr, u8 data[4])
-{
- int ret;
- struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = data,.len = 4 };
-
- ret = i2c_transfer(state->i2c, &msg, 1);
-
- if (ret != 1)
- printk("ves1820: %s(): i/o error (ret == %i)\n", __FUNCTION__, ret);
-
- return (ret != 1) ? -EREMOTEIO : 0;
-}
-/**
- * set up the downconverter frequency divisor for a
- * reference clock comparision frequency of 62.5 kHz.
- */
-static int tuner_set_tv_freq(struct ves1820_state *state, u32 freq)
+static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
{
- u32 div, ifreq;
- static u8 byte3[] = { 0x8e, 0x85 };
- int tuner_type = state->tuner;
- u8 buf[4];
-
- if (tuner_type == 0xff) /* PLL not reachable over i2c ... */
- return 0;
-
- if (strstr(state->i2c->name, "Technotrend")
- || strstr(state->i2c->name, "TT-Budget"))
- ifreq = 35937500;
- else
- ifreq = 36125000;
+ reg0 |= state->reg0 & 0x62;
- div = (freq + ifreq + 31250) / 62500;
+ if (INVERSION_ON == inversion) {
+ if (!state->config->invert) reg0 |= 0x20;
+ else reg0 &= ~0x20;
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = byte3[tuner_type];
+ } else if (INVERSION_OFF == inversion) {
- if (tuner_type == 1) {
- buf[2] |= (div >> 10) & 0x60;
- buf[3] = (freq < 174000000 ? 0x88 : freq < 470000000 ? 0x84 : 0x81);
- } else {
- buf[3] = (freq < 174000000 ? 0xa1 : freq < 454000000 ? 0x92 : 0x34);
+ if (!state->config->invert) reg0 &= ~0x20;
+ else reg0 |= 0x20;
}
- return tuner_write(state, addr[tuner_type], buf);
-}
-
-static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion)
-{
- reg0 |= state->reg0 & 0x62;
-
- if (INVERSION_ON == inversion)
- ENABLE_INVERSION(reg0);
- else if (INVERSION_OFF == inversion)
- DISABLE_INVERSION(reg0);
-
ves1820_writereg(state, 0x00, reg0 & 0xfe);
ves1820_writereg(state, 0x00, reg0 | 0x01);
- /**
- * check lock and toggle inversion bit if required...
- */
- if (INVERSION_AUTO == inversion && !(ves1820_readreg(state, 0x11) & 0x08)) {
- mdelay(50);
- if (!(ves1820_readreg(state, 0x11) & 0x08)) {
- reg0 ^= 0x20;
- ves1820_writereg(state, 0x00, reg0 & 0xfe);
- ves1820_writereg(state, 0x00, reg0 | 0x01);
- }
- }
-
state->reg0 = reg0;
return 0;
}
-static int ves1820_init(struct ves1820_state *state)
-{
- int i;
-
- ves1820_writereg(state, 0, 0);
-
-#if defined(CONFIG_DBOX2)
- ves1820_inittab[2] &= ~0x08;
-#endif
-
- for (i = 0; i < 53; i++)
- ves1820_writereg(state, i, ves1820_inittab[i]);
-
- ves1820_writereg(state, 0x34, state->pwm);
-
- return 0;
-}
-
static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
{
s32 BDR;
s32 BDRI;
s16 SFIL = 0;
u16 NDEC = 0;
- u32 tmp, ratio;
+ u32 ratio;
+ u32 fin;
+ u32 tmp;
+ u64 fptmp;
+ u64 fpxin;
- if (symbolrate > XIN / 2)
- symbolrate = XIN / 2;
+ if (symbolrate > state->config->xin / 2)
+ symbolrate = state->config->xin / 2;
if (symbolrate < 500000)
symbolrate = 500000;
- if (symbolrate < XIN / 16)
+ if (symbolrate < state->config->xin / 16)
NDEC = 1;
- if (symbolrate < XIN / 32)
+ if (symbolrate < state->config->xin / 32)
NDEC = 2;
- if (symbolrate < XIN / 64)
+ if (symbolrate < state->config->xin / 64)
NDEC = 3;
- if (symbolrate < (u32) (XIN / 12.3))
+ /* yeuch! */
+ fpxin = state->config->xin * 10;
+ fptmp = fpxin; do_div(fptmp, 123);
+ if (symbolrate < fptmp);
SFIL = 1;
- if (symbolrate < (u32) (XIN / 16))
+ fptmp = fpxin; do_div(fptmp, 160);
+ if (symbolrate < fptmp);
SFIL = 0;
- if (symbolrate < (u32) (XIN / 24.6))
+ fptmp = fpxin; do_div(fptmp, 246);
+ if (symbolrate < fptmp);
SFIL = 1;
- if (symbolrate < (u32) (XIN / 32))
+ fptmp = fpxin; do_div(fptmp, 320);
+ if (symbolrate < fptmp);
SFIL = 0;
- if (symbolrate < (u32) (XIN / 49.2))
+ fptmp = fpxin; do_div(fptmp, 492);
+ if (symbolrate < fptmp);
SFIL = 1;
- if (symbolrate < (u32) (XIN / 64))
+ fptmp = fpxin; do_div(fptmp, 640);
+ if (symbolrate < fptmp);
SFIL = 0;
- if (symbolrate < (u32) (XIN / 98.4))
+ fptmp = fpxin; do_div(fptmp, 984);
+ if (symbolrate < fptmp);
SFIL = 1;
+ fin = state->config->xin >> 4;
symbolrate <<= NDEC;
- ratio = (symbolrate << 4) / FIN;
- tmp = ((symbolrate << 4) % FIN) << 8;
- ratio = (ratio << 8) + tmp / FIN;
- tmp = (tmp % FIN) << 8;
- ratio = (ratio << 8) + (tmp + FIN / 2) / FIN;
+ ratio = (symbolrate << 4) / fin;
+ tmp = ((symbolrate << 4) % fin) << 8;
+ ratio = (ratio << 8) + tmp / fin;
+ tmp = (tmp % fin) << 8;
+ ratio = (ratio << 8) + (tmp + fin / 2) / fin;
BDR = ratio;
- BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
+ BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
if (BDRI > 0xFF)
BDRI = 0xFF;
@@ -292,8 +198,42 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
return 0;
}
-static int ves1820_set_parameters(struct ves1820_state *state, struct dvb_frontend_parameters *p)
+
+
+
+
+
+
+
+
+
+
+
+
+static int ves1820_init(struct dvb_frontend* fe)
+{
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+ int i;
+ int val;
+
+ ves1820_writereg(state, 0, 0);
+
+ for (i = 0; i < 53; i++) {
+ val = ves1820_inittab[i];
+ if ((i == 2) && (state->config->selagc)) val |= 0x08;
+ ves1820_writereg(state, i, val);
+ }
+
+ ves1820_writereg(state, 0x34, state->pwm);
+
+ if (state->config->pll_init) state->config->pll_init(fe);
+
+ return 0;
+}
+
+static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
@@ -304,7 +244,7 @@ static int ves1820_set_parameters(struct ves1820_state *state, struct dvb_fronte
if (real_qam < 0 || real_qam > 4)
return -EINVAL;
- tuner_set_tv_freq(state, p->frequency);
+ state->config->pll_set(fe, p);
ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
ves1820_writereg(state, 0x34, state->pwm);
@@ -315,327 +255,215 @@ static int ves1820_set_parameters(struct ves1820_state *state, struct dvb_fronte
ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion);
- /* yes, this speeds things up: userspace reports lock in about 8 ms
- instead of 500 to 1200 ms after calling FE_SET_FRONTEND. */
- mdelay(50);
-
return 0;
}
-static int ves1820_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- struct ves1820_state *state = (struct ves1820_state *) fe->data;
-
- switch (cmd) {
- case FE_GET_INFO:
- memcpy(arg, &ves1820_info, sizeof(struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS:
- {
- fe_status_t *status = (fe_status_t *) arg;
- int sync;
-
- *status = 0;
-
- sync = ves1820_readreg(state, 0x11);
-
- if (sync & 1)
- *status |= FE_HAS_SIGNAL;
-
- if (sync & 2)
- *status |= FE_HAS_CARRIER;
-
- if (sync & 2) /* XXX FIXME! */
- *status |= FE_HAS_VITERBI;
-
- if (sync & 4)
- *status |= FE_HAS_SYNC;
-
- if (sync & 8)
- *status |= FE_HAS_LOCK;
-
- break;
- }
-
- case FE_READ_BER:
- {
- u32 ber = ves1820_readreg(state, 0x14) |
- (ves1820_readreg(state, 0x15) << 8) |
- ((ves1820_readreg(state, 0x16) & 0x0f) << 16);
- *((u32 *) arg) = 10 * ber;
- break;
- }
- case FE_READ_SIGNAL_STRENGTH:
- {
- u8 gain = ves1820_readreg(state, 0x17);
- *((u16 *) arg) = (gain << 8) | gain;
- break;
- }
-
- case FE_READ_SNR:
- {
- u8 quality = ~ves1820_readreg(state, 0x18);
- *((u16 *) arg) = (quality << 8) | quality;
- break;
- }
-
- case FE_READ_UNCORRECTED_BLOCKS:
- *((u32 *) arg) = ves1820_readreg(state, 0x13) & 0x7f;
- if (*((u32 *) arg) == 0x7f)
- *((u32 *) arg) = 0xffffffff;
- /* reset uncorrected block counter */
- ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
- ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
- break;
-
- case FE_SET_FRONTEND:
- return ves1820_set_parameters(state, arg);
-
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = (struct dvb_frontend_parameters *) arg;
- int sync;
- s8 afc = 0;
-
- sync = ves1820_readreg(state, 0x11);
- afc = ves1820_readreg(state, 0x19);
- if (verbose) {
- /* AFC only valid when carrier has been recovered */
- printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
- "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
- }
-
- p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF;
- p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
-
- p->u.qam.fec_inner = FEC_NONE;
-
- p->frequency = ((p->frequency + 31250) / 62500) * 62500;
- if (sync & 2)
- p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10;
- break;
- }
- case FE_SLEEP:
- ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */
- ves1820_writereg(state, 0x00, 0x80); /* standby */
- break;
-
- case FE_INIT:
- return ves1820_init(state);
-
- default:
- return -EINVAL;
- }
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+ int sync;
- return 0;
-}
+ *status = 0;
+ sync = ves1820_readreg(state, 0x11);
-static long probe_tuner(struct i2c_adapter *i2c)
-{
- struct i2c_msg msg1 = {.addr = 0x61,.flags = 0,.buf = NULL,.len = 0 };
- struct i2c_msg msg2 = {.addr = 0x62,.flags = 0,.buf = NULL,.len = 0 };
- int type;
-
- if (i2c_transfer(i2c, &msg1, 1) == 1) {
- type = 0;
- printk("ves1820: setup for tuner spXXXX\n");
- } else if (i2c_transfer(i2c, &msg2, 1) == 1) {
- type = 1;
- printk("ves1820: setup for tuner sp5659c\n");
- } else {
- type = -1;
- }
+ if (sync & 1)
+ *status |= FE_HAS_SIGNAL;
- return type;
-}
+ if (sync & 2)
+ *status |= FE_HAS_CARRIER;
-static u8 read_pwm(struct i2c_adapter *i2c)
-{
- u8 b = 0xff;
- u8 pwm;
- struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},
- {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
- };
+ if (sync & 2) /* XXX FIXME! */
+ *status |= FE_HAS_VITERBI;
- if ((i2c_transfer(i2c, msg, 2) != 2) || (pwm == 0xff))
- pwm = 0x48;
+ if (sync & 4)
+ *status |= FE_HAS_SYNC;
- printk("ves1820: pwm=0x%02x\n", pwm);
+ if (sync & 8)
+ *status |= FE_HAS_LOCK;
- return pwm;
+ return 0;
}
-static long probe_demod_addr(struct i2c_adapter *i2c)
+static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber)
{
- u8 b[] = { 0x00, 0x1a };
- u8 id;
- struct i2c_msg msg[] = { {.addr = 0x08,.flags = 0,.buf = b,.len = 2},
- {.addr = 0x08,.flags = I2C_M_RD,.buf = &id,.len = 1}
- };
-
- if (i2c_transfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
- return msg[0].addr;
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
- msg[0].addr = msg[1].addr = 0x09;
+ u32 _ber = ves1820_readreg(state, 0x14) |
+ (ves1820_readreg(state, 0x15) << 8) |
+ ((ves1820_readreg(state, 0x16) & 0x0f) << 16);
+ *ber = 10 * _ber;
- if (i2c_transfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70)
- return msg[0].addr;
-
- return -1;
+ return 0;
}
-static ssize_t attr_read_pwm(struct device *dev, char *buf)
+static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
- return sprintf(buf, "0x%02x\n", state->pwm);
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+
+ u8 gain = ves1820_readreg(state, 0x17);
+ *strength = (gain << 8) | gain;
+
+ return 0;
}
-static ssize_t attr_write_pwm(struct device *dev, const char *buf, size_t count)
+static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
- unsigned long pwm;
- pwm = simple_strtoul(buf, NULL, 0);
- state->pwm = pwm & 0xff;
- return strlen(buf)+1;
-}
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
-static struct device_attribute dev_attr_client_name = {
- .attr = { .name = "pwm", .mode = S_IRUGO|S_IWUGO, .owner = THIS_MODULE },
- .show = &attr_read_pwm,
- .store = &attr_write_pwm,
-};
+ u8 quality = ~ves1820_readreg(state, 0x18);
+ *snr = (quality << 8) | quality;
-static struct i2c_client client_template;
+ return 0;
+}
-static int attach_adapter(struct i2c_adapter *adapter)
+static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
- struct i2c_client *client;
- struct ves1820_state *state;
- long demod_addr;
- int tuner_type;
- int ret;
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
- demod_addr = probe_demod_addr(adapter);
- if (demod_addr < 0)
- return -ENODEV;
+ *ucblocks = ves1820_readreg(state, 0x13) & 0x7f;
+ if (*ucblocks == 0x7f)
+ *ucblocks = 0xffffffff;
- tuner_type = probe_tuner(adapter);
- if (tuner_type < 0) {
- printk("ves1820: demod found, but unknown tuner type.\n");
- return -ENODEV;
- }
+ /* reset uncorrected block counter */
+ ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf);
+ ves1820_writereg(state, 0x10, ves1820_inittab[0x10]);
- if ((state = kmalloc(sizeof(struct ves1820_state), GFP_KERNEL)) == NULL) {
- return -ENOMEM;
- }
+ return 0;
+}
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- kfree(state);
- return -ENOMEM;
+static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+ int sync;
+ s8 afc = 0;
+
+ sync = ves1820_readreg(state, 0x11);
+ afc = ves1820_readreg(state, 0x19);
+ if (verbose) {
+ /* AFC only valid when carrier has been recovered */
+ printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
+ "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
}
- memset(state, 0, sizeof(*state));
- state->i2c = adapter;
- state->tuner = tuner_type;
- state->pwm = read_pwm(adapter);
- state->reg0 = ves1820_inittab[0];
- state->demod_addr = demod_addr;
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = addr[tuner_type];
-
- i2c_set_clientdata(client, (void *) state);
-
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(client);
- kfree(state);
- return ret;
+ if (!state->config->invert) {
+ p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF;
+ } else {
+ p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
}
- BUG_ON(!state->dvb);
+ p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
- device_create_file(&client->dev, &dev_attr_client_name);
+ p->u.qam.fec_inner = FEC_NONE;
- ret = dvb_register_frontend(ves1820_ioctl, state->dvb, state, &ves1820_info, THIS_MODULE);
- if (ret) {
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return ret;
- }
+ p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+ if (sync & 2)
+ p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10;
return 0;
}
-static int detach_client(struct i2c_client *client)
+static int ves1820_sleep(struct dvb_frontend* fe)
{
- struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
- dvb_unregister_frontend(ves1820_ioctl, state->dvb);
- device_remove_file(&client->dev, &dev_attr_client_name);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+
+ ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */
+ ves1820_writereg(state, 0x00, 0x80); /* standby */
+
return 0;
}
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
- struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client);
-
- switch (cmd) {
- case FE_REGISTER:{
- state->dvb = (struct dvb_adapter *) arg;
- break;
- }
- case FE_UNREGISTER:{
- state->dvb = NULL;
- break;
- }
- default:
- return -EOPNOTSUPP;
- }
+
+ fesettings->min_delay_ms = 200;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
return 0;
}
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = "ves1820",
- .id = I2C_DRIVERID_VES1820,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
-
-static struct i2c_client client_template = {
- I2C_DEVNAME("ves1820"),
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
-
-static int __init init_ves1820(void)
+static void ves1820_release(struct dvb_frontend* fe)
{
- return i2c_add_driver(&driver);
+ struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv;
+ kfree(state);
}
-static void __exit exit_ves1820(void)
+static struct dvb_frontend_ops ves1820_ops;
+
+struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+ struct i2c_adapter* i2c,
+ u8 pwm)
{
- if (i2c_del_driver(&driver))
- printk("ves1820: driver deregistration failed\n");
+ struct ves1820_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct ves1820_state*) kmalloc(sizeof(struct ves1820_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+ state->reg0 = ves1820_inittab[0];
+ state->config = config;
+ state->i2c = i2c;
+ state->pwm = pwm;
+
+ /* check if the demod is there */
+ if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70)
+ goto error;
+
+ if (verbose)
+ printk("ves1820: pwm=0x%02x\n", state->pwm);
+
+ state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
+ state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init(init_ves1820);
-module_exit(exit_ves1820);
+static struct dvb_frontend_ops ves1820_ops = {
+
+ .info = {
+ .name = "VLSI VES1820 DVB-C",
+ .type = FE_QAM,
+ .frequency_stepsize = 62500,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .caps = FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_FEC_AUTO
+ },
+
+ .release = ves1820_release,
+
+ .init = ves1820_init,
+ .sleep = ves1820_sleep,
+
+ .set_frontend = ves1820_set_parameters,
+ .get_frontend = ves1820_get_frontend,
+ .get_tune_settings = ves1820_get_tune_settings,
+
+ .read_status = ves1820_read_status,
+ .read_ber = ves1820_read_ber,
+ .read_signal_strength = ves1820_read_signal_strength,
+ .read_snr = ves1820_read_snr,
+ .read_ucblocks = ves1820_read_ucblocks,
+};
MODULE_PARM(verbose, "i");
MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
-MODULE_DESCRIPTION("VES1820 DVB-C frontend driver");
+MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver");
MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ves1820_attach);
diff --git a/linux/drivers/media/dvb/frontends/ves1820.h b/linux/drivers/media/dvb/frontends/ves1820.h
new file mode 100644
index 000000000..8739fec48
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/ves1820.h
@@ -0,0 +1,52 @@
+/*
+ VES1820 - Single Chip Cable Channel Receiver driver module
+
+ Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+
+ 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 VES1820_H
+#define VES1820_H
+
+#include <linux/dvb/frontend.h>
+
+#define VES1820_SELAGC_PWM 0
+#define VES1820_SELAGC_SIGNAMPERR 1
+
+struct ves1820_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* value of XIN to use */
+ u32 xin;
+
+ /* does inversion need inverted? */
+ u8 invert:1;
+
+ /* SELAGC control */
+ u8 selagc:1;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+ struct i2c_adapter* i2c,
+ u8 pwm);
+
+#endif // VES1820_H
diff --git a/linux/drivers/media/dvb/frontends/ves1x93.c b/linux/drivers/media/dvb/frontends/ves1x93.c
index 6e74b25c8..17e5667ae 100644
--- a/linux/drivers/media/dvb/frontends/ves1x93.c
+++ b/linux/drivers/media/dvb/frontends/ves1x93.c
@@ -1,5 +1,5 @@
-/*
- Driver for VES1893 and VES1993 QPSK Frontends
+/*
+ Driver for VES1893 and VES1993 QPSK Demodulators
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
@@ -21,7 +21,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -31,41 +31,33 @@
#include <linux/delay.h>
#include "dvb_frontend.h"
+#include "ves1x93.h"
-static int debug = 0;
-#define dprintk if (debug) printk
-static int board_type = 0;
-#define BOARD_SIEMENS_PCI 0
-#define BOARD_NOKIA_DBOX2 1
-#define BOARD_SAGEM_DBOX2 2
+struct ves1x93_state {
-static int demod_type = 0;
-#define DEMOD_VES1893 0
-#define DEMOD_VES1993 1
+ struct i2c_adapter* i2c;
+
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct ves1x93_config* config;
-static struct dvb_frontend_info ves1x93_info = {
- .name = "VES1x93",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = 125, /* kHz for QPSK frontends */
- .frequency_tolerance = 29500,
- .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
-/* .symbol_rate_tolerance = ???,*/
- .notifier_delay = 50, /* 1/20 s */
- .caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK
+ struct dvb_frontend frontend;
+
+ /* previous uncorrected block counter */
+ fe_spectral_inversion_t inversion;
+ u8 *init_1x93_tab;
+ u8 *init_1x93_wtab;
+ u8 tab_size;
+ u8 demod_type;
};
+static int debug = 0;
+#define dprintk if (debug) printk
-/**
- * nokia dbox2 (ves1893) and sagem dbox2 (ves1993)
- * need bit AGCR[PWMS] set to 1
- */
+#define DEMOD_VES1893 0
+#define DEMOD_VES1993 1
static u8 init_1893_tab [] = {
0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4,
@@ -89,10 +81,6 @@ static u8 init_1993_tab [] = {
0x00, 0x00, 0x0e, 0x80, 0x00
};
-
-static u8 * init_1x93_tab;
-
-
static u8 init_1893_wtab[] =
{
1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
@@ -110,21 +98,13 @@ static u8 init_1993_wtab[] =
1,1,1,0,1,1,1,1, 1,1,1,1,1
};
-struct ves1x93_state {
- fe_spectral_inversion_t inversion;
- struct i2c_adapter *i2c;
- struct dvb_adapter *dvb;
-};
-
-
-
-static int ves1x93_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
+static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data)
{
u8 buf [] = { 0x00, reg, data };
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 3 };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 };
int err;
- if ((err = i2c_transfer (i2c, &msg, 1)) != 1) {
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
return -EREMOTEIO;
}
@@ -133,150 +113,31 @@ static int ves1x93_writereg (struct i2c_adapter *i2c, u8 reg, u8 data)
}
-static u8 ves1x93_readreg (struct i2c_adapter *i2c, u8 reg)
+static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg)
{
int ret;
u8 b0 [] = { 0x00, reg };
u8 b1 [] = { 0 };
- struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b0, .len = 2 },
- { .addr = 0x08, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+ struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
- ret = i2c_transfer (i2c, msg, 2);
+ ret = i2c_transfer (state->i2c, msg, 2);
- if (ret != 2)
- dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+ if (ret != 2) return ret;
return b1[0];
}
-
-static int tuner_write (struct i2c_adapter *i2c, u8 *data, u8 len)
-{
- int ret;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = len };
-
- ves1x93_writereg(i2c, 0x00, 0x11);
- ret = i2c_transfer (i2c, &msg, 1);
- ves1x93_writereg(i2c, 0x00, 0x01);
-
- if (ret != 1)
- printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-
-
-/**
- * set up the downconverter frequency divisor for a
- * reference clock comparision frequency of 125 kHz.
- */
-static int sp5659_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
-{
- u8 pwr = 0;
- u8 buf[4];
- u32 div = (freq + 479500) / 125;
-
- if (freq > 2000000) pwr = 3;
- else if (freq > 1800000) pwr = 2;
- else if (freq > 1600000) pwr = 1;
- else if (freq > 1200000) pwr = 0;
- else if (freq >= 1100000) pwr = 1;
- else pwr = 2;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = ((div & 0x18000) >> 10) | 0x95;
- buf[3] = (pwr << 6) | 0x30;
-
- // NOTE: since we're using a prescaler of 2, we set the
- // divisor frequency to 62.5kHz and divide by 125 above
-
- return tuner_write (i2c, buf, sizeof(buf));
-}
-
-
-static int tsa5059_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
-{
- int ret;
- u8 buf [2];
-
- freq /= 1000;
-
- buf[0] = (freq >> 8) & 0x7F;
- buf[1] = freq & 0xFF;
-
- ret = tuner_write(i2c, buf, sizeof(buf));
-
- return ret;
-}
-
-
-static int tuner_set_tv_freq (struct i2c_adapter *i2c, u32 freq)
-{
- if ((demod_type == DEMOD_VES1893) && (board_type == BOARD_SIEMENS_PCI))
- return sp5659_set_tv_freq (i2c, freq);
- else if (demod_type == DEMOD_VES1993)
- return tsa5059_set_tv_freq (i2c, freq);
-
- return -EINVAL;
-}
-
-
-static int ves1x93_init (struct i2c_adapter *i2c)
-{
- int i;
- int size;
- u8 *init_1x93_wtab;
-
- dprintk("%s: init chip\n", __FUNCTION__);
-
- switch (demod_type) {
- case DEMOD_VES1893:
- init_1x93_tab = init_1893_tab;
- init_1x93_wtab = init_1893_wtab;
- size = sizeof(init_1893_tab);
- if (board_type == BOARD_NOKIA_DBOX2)
- init_1x93_tab[0x05] |= 0x20; /* invert PWM */
- break;
-
- case DEMOD_VES1993:
- init_1x93_tab = init_1993_tab;
- init_1x93_wtab = init_1993_wtab;
- size = sizeof(init_1993_tab);
- if (board_type == BOARD_SAGEM_DBOX2)
- init_1x93_tab[0x05] |= 0x20; /* invert PWM */
- break;
-
- default:
- return -EINVAL;
- }
-
- for (i = 0; i < size; i++)
- if (init_1x93_wtab[i])
- ves1x93_writereg (i2c, i, init_1x93_tab[i]);
-
- if (demod_type == DEMOD_VES1993) {
- if (board_type == BOARD_NOKIA_DBOX2)
- tuner_write(i2c, "\x06\x5c\x83\x60", 4);
- else if (board_type == BOARD_SAGEM_DBOX2)
- tuner_write(i2c, "\x25\x70\x92\x40", 4);
- }
-
- return 0;
-}
-
-
-static int ves1x93_clr_bit (struct i2c_adapter *i2c)
+static int ves1x93_clr_bit (struct ves1x93_state* state)
{
msleep(10);
- ves1x93_writereg (i2c, 0, init_1x93_tab[0] & 0xfe);
- ves1x93_writereg (i2c, 0, init_1x93_tab[0]);
+ ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe);
+ ves1x93_writereg (state, 0, state->init_1x93_tab[0]);
msleep(50);
return 0;
}
-static int ves1x93_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion_t inversion)
+static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion)
{
u8 val;
@@ -299,66 +160,47 @@ static int ves1x93_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion
return -EINVAL;
}
- return ves1x93_writereg (i2c, 0x0c, (init_1x93_tab[0x0c] & 0x3f) | val);
+ return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val);
}
-static int ves1x93_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec)
+static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec)
{
if (fec == FEC_AUTO)
- return ves1x93_writereg (i2c, 0x0d, 0x08);
+ return ves1x93_writereg (state, 0x0d, 0x08);
else if (fec < FEC_1_2 || fec > FEC_8_9)
return -EINVAL;
else
- return ves1x93_writereg (i2c, 0x0d, fec - FEC_1_2);
+ return ves1x93_writereg (state, 0x0d, fec - FEC_1_2);
}
-static fe_code_rate_t ves1x93_get_fec (struct i2c_adapter *i2c)
+static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state)
{
- return FEC_1_2 + ((ves1x93_readreg (i2c, 0x0d) >> 4) & 0x7);
+ return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7);
}
-static int ves1x93_set_symbolrate (struct i2c_adapter *i2c, u32 srate)
+static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
{
u32 BDR;
u32 ratio;
u8 ADCONF, FCONF, FNR;
u32 BDRI;
u32 tmp;
- u32 XIN, FIN;
+ u32 FIN;
dprintk("%s: srate == %d\n", __FUNCTION__, (unsigned int) srate);
- switch (board_type) {
- case BOARD_SIEMENS_PCI:
- XIN = 90100000UL;
- break;
- case BOARD_NOKIA_DBOX2:
- if (demod_type == DEMOD_VES1893)
- XIN = 91000000UL;
- else if (demod_type == DEMOD_VES1993)
- XIN = 96000000UL;
- else
- return -EINVAL;
- break;
- case BOARD_SAGEM_DBOX2:
- XIN = 92160000UL;
- break;
- default:
- return -EINVAL;
- }
-
- if (srate > XIN/2)
- srate = XIN/2;
+ if (srate > state->config->xin/2)
+ srate = state->config->xin/2;
if (srate < 500000)
srate = 500000;
#define MUL (1UL<<26)
- FIN = (XIN + 6000) >> 4;
+ FIN = (state->config->xin + 6000) >> 4;
tmp = srate << 6;
ratio = tmp / FIN;
@@ -403,334 +245,319 @@ static int ves1x93_set_symbolrate (struct i2c_adapter *i2c, u32 srate)
if (BDRI > 0xff)
BDRI = 0xff;
- ves1x93_writereg (i2c, 0x06, 0xff & BDR);
- ves1x93_writereg (i2c, 0x07, 0xff & (BDR >> 8));
- ves1x93_writereg (i2c, 0x08, 0x0f & (BDR >> 16));
+ ves1x93_writereg (state, 0x06, 0xff & BDR);
+ ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8));
+ ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16));
- ves1x93_writereg (i2c, 0x09, BDRI);
- ves1x93_writereg (i2c, 0x20, ADCONF);
- ves1x93_writereg (i2c, 0x21, FCONF);
+ ves1x93_writereg (state, 0x09, BDRI);
+ ves1x93_writereg (state, 0x20, ADCONF);
+ ves1x93_writereg (state, 0x21, FCONF);
- if (srate < 6000000)
- ves1x93_writereg (i2c, 0x05, init_1x93_tab[0x05] | 0x80);
+ if (srate < 6000000)
+ ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] | 0x80);
else
- ves1x93_writereg (i2c, 0x05, init_1x93_tab[0x05] & 0x7f);
+ ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] & 0x7f);
/* ves1993 hates this, will lose lock */
- if (demod_type != DEMOD_VES1993)
- ves1x93_clr_bit (i2c);
+ if (state->demod_type != DEMOD_VES1993)
+ ves1x93_clr_bit (state);
return 0;
}
-static int ves1x93_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage)
-{
- switch (voltage) {
- case SEC_VOLTAGE_13:
- return ves1x93_writereg (i2c, 0x1f, 0x20);
- case SEC_VOLTAGE_18:
- return ves1x93_writereg (i2c, 0x1f, 0x30);
- case SEC_VOLTAGE_OFF:
- return ves1x93_writereg (i2c, 0x1f, 0x00);
- default:
- return -EINVAL;
- }
-}
-static int ves1x93_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct ves1x93_state *state = (struct ves1x93_state *) fe->data;
- struct i2c_adapter *i2c = state->i2c;
- switch (cmd) {
- case FE_GET_INFO:
- memcpy (arg, &ves1x93_info, sizeof(struct dvb_frontend_info));
- break;
- case FE_READ_STATUS:
- {
- fe_status_t *status = arg;
- u8 sync = ves1x93_readreg (i2c, 0x0e);
-
- /*
- * The ves1893 sometimes returns sync values that make no sense,
- * because, e.g., the SIGNAL bit is 0, while some of the higher
- * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
- * Tests showed that the the VITERBI and SYNC bits are returned
- * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
- * If such a case occurs, we read the value again, until we get a
- * valid value.
- */
- int maxtry = 10; /* just for safety - let's not get stuck here */
- while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
- msleep(10);
- sync = ves1x93_readreg (i2c, 0x0e);
- }
- *status = 0;
- if (sync & 1)
- *status |= FE_HAS_SIGNAL;
- if (sync & 2)
- *status |= FE_HAS_CARRIER;
- if (sync & 4)
- *status |= FE_HAS_VITERBI;
- if (sync & 8)
- *status |= FE_HAS_SYNC;
- if ((sync & 0x1f) == 0x1f)
- *status |= FE_HAS_LOCK;
- break;
- }
- case FE_READ_BER:
- {
- u32 *ber = (u32 *) arg;
- *ber = ves1x93_readreg (i2c, 0x15);
- *ber |= (ves1x93_readreg (i2c, 0x16) << 8);
- *ber |= ((ves1x93_readreg (i2c, 0x17) & 0x0F) << 16);
- *ber *= 10;
- break;
- }
- case FE_READ_SIGNAL_STRENGTH:
- {
- u8 signal = ~ves1x93_readreg (i2c, 0x0b);
- *((u16*) arg) = (signal << 8) | signal;
- break;
+static int ves1x93_init (struct dvb_frontend* fe)
+{
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+ int i;
+ int val;
+
+ dprintk("%s: init chip\n", __FUNCTION__);
+
+ for (i = 0; i < state->tab_size; i++) {
+ if (state->init_1x93_wtab[i]) {
+ val = state->init_1x93_tab[i];
+
+ if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */
+ ves1x93_writereg (state, i, val);
+ }
}
- case FE_READ_SNR:
- {
- u8 snr = ~ves1x93_readreg (i2c, 0x1c);
- *(u16*) arg = (snr << 8) | snr;
- break;
+ if (state->config->pll_init) {
+ ves1x93_writereg(state, 0x00, 0x11);
+ state->config->pll_init(fe);
+ ves1x93_writereg(state, 0x00, 0x01);
}
- case FE_READ_UNCORRECTED_BLOCKS:
- {
- *(u32*) arg = ves1x93_readreg (i2c, 0x18) & 0x7f;
+ return 0;
+}
- if (*(u32*) arg == 0x7f)
- *(u32*) arg = 0xffffffff; /* counter overflow... */
-
- ves1x93_writereg (i2c, 0x18, 0x00); /* reset the counter */
- ves1x93_writereg (i2c, 0x18, 0x80); /* dto. */
- break;
+static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ return ves1x93_writereg (state, 0x1f, 0x20);
+ case SEC_VOLTAGE_18:
+ return ves1x93_writereg (state, 0x1f, 0x30);
+ case SEC_VOLTAGE_OFF:
+ return ves1x93_writereg (state, 0x1f, 0x00);
+ default:
+ return -EINVAL;
}
+}
+
+static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
- case FE_SET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
+ u8 sync = ves1x93_readreg (state, 0x0e);
- tuner_set_tv_freq (i2c, p->frequency);
- ves1x93_set_inversion (i2c, p->inversion);
- ves1x93_set_fec (i2c, p->u.qpsk.fec_inner);
- ves1x93_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
- state->inversion = p->inversion;
- break;
+ /*
+ * The ves1893 sometimes returns sync values that make no sense,
+ * because, e.g., the SIGNAL bit is 0, while some of the higher
+ * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
+ * Tests showed that the the VITERBI and SYNC bits are returned
+ * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
+ * If such a case occurs, we read the value again, until we get a
+ * valid value.
+ */
+ int maxtry = 10; /* just for safety - let's not get stuck here */
+ while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
+ msleep(10);
+ sync = ves1x93_readreg (state, 0x0e);
}
- case FE_GET_FRONTEND:
- {
- struct dvb_frontend_parameters *p = arg;
- int afc;
+ *status = 0;
+ if (sync & 1)
+ *status |= FE_HAS_SIGNAL;
- afc = ((int)((char)(ves1x93_readreg (i2c, 0x0a) << 1)))/2;
- afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
+ if (sync & 2)
+ *status |= FE_HAS_CARRIER;
- p->frequency -= afc;
+ if (sync & 4)
+ *status |= FE_HAS_VITERBI;
- /*
- * inversion indicator is only valid
- * if auto inversion was used
- */
- if (state->inversion == INVERSION_AUTO)
- p->inversion = (ves1x93_readreg (i2c, 0x0f) & 2) ?
- INVERSION_OFF : INVERSION_ON;
- p->u.qpsk.fec_inner = ves1x93_get_fec (i2c);
- /* XXX FIXME: timing offset !! */
- break;
- }
+ if (sync & 8)
+ *status |= FE_HAS_SYNC;
+
+ if ((sync & 0x1f) == 0x1f)
+ *status |= FE_HAS_LOCK;
- case FE_SLEEP:
- if (board_type == BOARD_SIEMENS_PCI)
- ves1x93_writereg (i2c, 0x1f, 0x00); /* LNB power off */
- return ves1x93_writereg (i2c, 0x00, 0x08);
+ return 0;
+}
- case FE_INIT:
- return ves1x93_init (i2c);
- case FE_SET_TONE:
- return -EOPNOTSUPP; /* the ves1893 can generate the 22k */
- /* let's implement this when we have */
- /* a box that uses the 22K_0 pin... */
+static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
- case FE_SET_VOLTAGE:
- return ves1x93_set_voltage (i2c, (fe_sec_voltage_t) arg);
+ *ber = ves1x93_readreg (state, 0x15);
+ *ber |= (ves1x93_readreg (state, 0x16) << 8);
+ *ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16);
+ *ber *= 10;
- default:
- return -EOPNOTSUPP;
- };
-
return 0;
-}
+}
-static struct i2c_client client_template;
+static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+
+ u8 signal = ~ves1x93_readreg (state, 0x0b);
+ *strength = (signal << 8) | signal;
-static int attach_adapter(struct i2c_adapter *adapter)
+ return 0;
+}
+
+static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr)
{
- struct i2c_client *client;
- struct ves1x93_state* state;
- u8 identity = ves1x93_readreg(adapter, 0x1e);
- int ret;
-
- switch (identity) {
- case 0xdc: /* VES1893A rev1 */
- printk("ves1x93: Detected ves1893a rev1\n");
- demod_type = DEMOD_VES1893;
- ves1x93_info.name[4] = '8';
- break;
- case 0xdd: /* VES1893A rev2 */
- printk("ves1x93: Detected ves1893a rev2\n");
- demod_type = DEMOD_VES1893;
- ves1x93_info.name[4] = '8';
- break;
- case 0xde: /* VES1993 */
- printk("ves1x93: Detected ves1993\n");
- demod_type = DEMOD_VES1993;
- ves1x93_info.name[4] = '9';
- break;
- default:
- dprintk("VES1x93 not found (identity %02x)\n", identity);
- return -ENODEV;
- }
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
- if ((state = kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL)) == NULL) {
- return -ENOMEM;
- }
+ u8 _snr = ~ves1x93_readreg (state, 0x1c);
+ *snr = (_snr << 8) | _snr;
- if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- kfree(state);
- return -ENOMEM;
- }
+ return 0;
+}
- state->inversion = INVERSION_OFF;
- state->i2c = adapter;
-
- memcpy(client, &client_template, sizeof(struct i2c_client));
- client->adapter = adapter;
- client->addr = (0x08>>1);
- i2c_set_clientdata(client, (void*)state);
-
- ret = i2c_attach_client(client);
- if (ret) {
- kfree(client);
- kfree(state);
- return -EFAULT;
- }
+static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
- BUG_ON(!state->dvb);
+ *ucblocks = ves1x93_readreg (state, 0x18) & 0x7f;
- ret = dvb_register_frontend(ves1x93_ioctl, state->dvb, state,
- &ves1x93_info, THIS_MODULE);
- if (ret) {
- i2c_detach_client(client);
- kfree(client);
- kfree(state);
- return -EFAULT;
- }
+ if (*ucblocks == 0x7f)
+ *ucblocks = 0xffffffff; /* counter overflow... */
+
+ ves1x93_writereg (state, 0x18, 0x00); /* reset the counter */
+ ves1x93_writereg (state, 0x18, 0x80); /* dto. */
return 0;
}
-static int detach_client(struct i2c_client *client)
+static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
- struct ves1x93_state *state = (struct ves1x93_state*)i2c_get_clientdata(client);
- dvb_unregister_frontend(ves1x93_ioctl, state->dvb);
- i2c_detach_client(client);
- BUG_ON(state->dvb);
- kfree(client);
- kfree(state);
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+
+ ves1x93_writereg(state, 0x00, 0x11);
+ state->config->pll_set(fe, p);
+ ves1x93_writereg(state, 0x00, 0x01);
+ ves1x93_set_inversion (state, p->inversion);
+ ves1x93_set_fec (state, p->u.qpsk.fec_inner);
+ ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
+ state->inversion = p->inversion;
+
return 0;
}
-static int command (struct i2c_client *client, unsigned int cmd, void *arg)
+static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
- struct ves1x93_state *state = (struct ves1x93_state*)i2c_get_clientdata(client);
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+ int afc;
- dprintk ("%s\n", __FUNCTION__);
+ afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
+ afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
+
+ p->frequency -= afc;
+
+ /*
+ * inversion indicator is only valid
+ * if auto inversion was used
+ */
+ if (state->inversion == INVERSION_AUTO)
+ p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
+ INVERSION_OFF : INVERSION_ON;
+ p->u.qpsk.fec_inner = ves1x93_get_fec (state);
+ /* XXX FIXME: timing offset !! */
- switch (cmd) {
- case FE_REGISTER: {
- state->dvb = (struct dvb_adapter*)arg;
- break;
- }
- case FE_UNREGISTER: {
- state->dvb = NULL;
- break;
- }
- default:
- return -EOPNOTSUPP;
- }
return 0;
}
-static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = "ves1x93",
- .id = I2C_DRIVERID_DVBFE_VES1X93,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = attach_adapter,
- .detach_client = detach_client,
- .command = command,
-};
+static int ves1x93_sleep(struct dvb_frontend* fe)
+{
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
-static struct i2c_client client_template = {
- I2C_DEVNAME("ves1x93"),
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
-};
+ return ves1x93_writereg (state, 0x00, 0x08);
+}
-static int __init init_ves1x93 (void)
+static void ves1x93_release(struct dvb_frontend* fe)
{
- switch (board_type) {
- case BOARD_NOKIA_DBOX2:
- dprintk("%s: NOKIA_DBOX2\n", __FILE__);
+ struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops ves1x93_ops;
+
+struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct ves1x93_state* state = NULL;
+ u8 identity;
+
+ /* allocate memory for the internal state */
+ state = (struct ves1x93_state*) kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
+ state->inversion = INVERSION_OFF;
+
+ /* check if the demod is there + identify it */
+ identity = ves1x93_readreg(state, 0x1e);
+ switch (identity) {
+ case 0xdc: /* VES1893A rev1 */
+ printk("ves1x93: Detected ves1893a rev1\n");
+ state->demod_type = DEMOD_VES1893;
+ state->init_1x93_tab = init_1893_tab;
+ state->init_1x93_wtab = init_1893_wtab;
+ state->tab_size = sizeof(init_1893_tab);
break;
- case BOARD_SAGEM_DBOX2:
- dprintk("%s: SAGEM_DBOX2\n", __FILE__);
+
+ case 0xdd: /* VES1893A rev2 */
+ printk("ves1x93: Detected ves1893a rev2\n");
+ state->demod_type = DEMOD_VES1893;
+ state->init_1x93_tab = init_1893_tab;
+ state->init_1x93_wtab = init_1893_wtab;
+ state->tab_size = sizeof(init_1893_tab);
break;
- case BOARD_SIEMENS_PCI:
- dprintk("%s: SIEMENS_PCI\n", __FILE__);
+
+ case 0xde: /* VES1993 */
+ printk("ves1x93: Detected ves1993\n");
+ state->demod_type = DEMOD_VES1993;
+ state->init_1x93_tab = init_1993_tab;
+ state->init_1x93_wtab = init_1993_wtab;
+ state->tab_size = sizeof(init_1993_tab);
break;
+
default:
- return -EIO;
+ goto error;
}
- return i2c_add_driver(&driver);
-}
-
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
-static void __exit exit_ves1x93 (void)
-{
- if (i2c_del_driver(&driver))
- printk("vex1x93: driver deregistration failed\n");
+error:
+ if (state) kfree(state);
+ return NULL;
}
-module_init(init_ves1x93);
-module_exit(exit_ves1x93);
+static struct dvb_frontend_ops ves1x93_ops = {
+
+ .info = {
+ .name = "VLSI VES1x93 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125, /* kHz for QPSK frontends */
+ .frequency_tolerance = 29500,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ /* .symbol_rate_tolerance = ???,*/
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK
+ },
+
+ .release = ves1x93_release,
+
+ .init = ves1x93_init,
+ .sleep = ves1x93_sleep,
+
+ .set_frontend = ves1x93_set_frontend,
+ .get_frontend = ves1x93_get_frontend,
+
+ .read_status = ves1x93_read_status,
+ .read_ber = ves1x93_read_ber,
+ .read_signal_strength = ves1x93_read_signal_strength,
+ .read_snr = ves1x93_read_snr,
+ .read_ucblocks = ves1x93_read_ucblocks,
+
+ .set_voltage = ves1x93_set_voltage,
+};
+MODULE_PARM(debug,"i");
-MODULE_DESCRIPTION("VES1x93 DVB-S Frontend");
+MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver");
MODULE_AUTHOR("Ralph Metzler");
MODULE_LICENSE("GPL");
-MODULE_PARM(debug,"i");
-MODULE_PARM(board_type,"i");
+EXPORT_SYMBOL(ves1x93_attach);
diff --git a/linux/drivers/media/dvb/frontends/ves1x93.h b/linux/drivers/media/dvb/frontends/ves1x93.h
new file mode 100644
index 000000000..1627e37c5
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/ves1x93.h
@@ -0,0 +1,50 @@
+/*
+ Driver for VES1893 and VES1993 QPSK Demodulators
+
+ Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+ Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
+ Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
+ Copyright (C) 2002-2003 Andreas Oberritter <obi@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 VES1X93_H
+#define VES1X93_H
+
+#include <linux/dvb/frontend.h>
+
+struct ves1x93_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* value of XIN to use */
+ u32 xin;
+
+ /* should PWM be inverted? */
+ u8 invert_pwm:1;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // VES1X93_H
diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig
index cf84d6633..99a230dc5 100644
--- a/linux/drivers/media/dvb/ttpci/Kconfig
+++ b/linux/drivers/media/dvb/ttpci/Kconfig
@@ -4,6 +4,11 @@ config DVB_AV7110
select FW_LOADER
select VIDEO_DEV
select VIDEO_SAA7146_VV
+ select DVB_VES1820
+ select DVB_VES1X93
+ select DVB_STV0299
+ select DVB_TDA8083
+ select DVB_SP8870
help
Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -53,6 +58,12 @@ config DVB_BUDGET
tristate "Budget cards"
depends on DVB_CORE && PCI
select VIDEO_SAA7146
+ select DVB_STV0299
+ select DVB_VES1X93
+ select DVB_VES1820
+ select DVB_L64781
+ select DVB_TDA8083
+ select DVB_TDA10021
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -67,6 +78,8 @@ config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
depends on DVB_CORE && PCI
select VIDEO_SAA7146
+ select DVB_STV0299
+ select DVB_TDA1004X
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -85,6 +98,7 @@ config DVB_BUDGET_AV
depends on DVB_CORE && PCI
select VIDEO_DEV
select VIDEO_SAA7146_VV
+ select DVB_STV0299
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -99,6 +113,9 @@ config DVB_BUDGET_PATCH
tristate "AV7110 cards with Budget Patch"
depends on DVB_CORE && DVB_BUDGET
select DVB_AV7110
+ select DVB_STV0299
+ select DVB_VES1X93
+ select DVB_TDA8083
help
Support for Budget Patch (full TS) modification on
SAA7146+AV7110 based cards (DVB-S cards). This
diff --git a/linux/drivers/media/dvb/ttpci/Makefile b/linux/drivers/media/dvb/ttpci/Makefile
index 043468a1d..825ab1c38 100644
--- a/linux/drivers/media/dvb/ttpci/Makefile
+++ b/linux/drivers/media/dvb/ttpci/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
hostprogs-y := fdump
diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c
index 13cd71006..a1da2a5b7 100644
--- a/linux/drivers/media/dvb/ttpci/av7110.c
+++ b/linux/drivers/media/dvb/ttpci/av7110.c
@@ -67,6 +67,7 @@
#include "av7110_ca.h"
#include "av7110_ipack.h"
+
int av7110_debug;
static int vidmode = CVBS_RGB_OUT;
@@ -96,6 +97,16 @@ static void restart_feeds(struct av7110 *av7110);
int av7110_num = 0;
+
+#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \
+{\
+ if (fe_func != NULL) { \
+ av7110_copy = fe_func; \
+ fe_func = av7110_func; \
+ } \
+}
+
+
static void init_av7110_av(struct av7110 *av7110)
{
struct saa7146_dev *dev=av7110->dev;
@@ -1090,71 +1101,43 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
* SEC device file operations
******************************************************************************/
-static int av7110_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct av7110 *av7110 = fe->before_after_data;
- dprintk(4, "%p\n", av7110);
+static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
- switch (cmd) {
- case FE_SET_TONE:
- switch ((fe_sec_tone_mode_t) arg) {
- case SEC_TONE_ON:
- Set22K(av7110, 1);
- break;
- case SEC_TONE_OFF:
- Set22K(av7110, 0);
- break;
- default:
- return -EINVAL;
- };
+ switch (tone) {
+ case SEC_TONE_ON:
+ Set22K(av7110, 1);
break;
- case FE_DISEQC_SEND_MASTER_CMD:
- {
- struct dvb_diseqc_master_cmd *cmd = arg;
- av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
- break;
- }
-
- case FE_DISEQC_SEND_BURST:
- av7110_diseqc_send(av7110, 0, NULL, (unsigned long) arg);
+ case SEC_TONE_OFF:
+ Set22K(av7110, 0);
break;
default:
- return -EOPNOTSUPP;
- };
+ return -EINVAL;
+ }
return 0;
}
-
-static void av7110_before_after_tune(fe_status_t s, void *data)
+static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
{
- struct av7110 *av7110 = data;
-
- dprintk(4, "%p\n", av7110);
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
- av7110->fe_synced = (s & FE_HAS_LOCK) ? 1 : 0;
+ av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
- if (av7110->playing)
- return;
+ return 0;
+}
- if (down_interruptible(&av7110->pid_mutex))
- return;
+static int av7110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
- if (av7110->fe_synced) {
- SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
- av7110->pids[DMX_PES_AUDIO],
- av7110->pids[DMX_PES_TELETEXT], 0,
- av7110->pids[DMX_PES_PCR]);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
- } else {
- SetPIDs(av7110, 0, 0, 0, 0, 0);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0);
- }
+ av7110_diseqc_send(av7110, 0, NULL, minicmd);
- up(&av7110->pid_mutex);
+ return 0;
}
@@ -1170,15 +1153,6 @@ static int av7110_register(struct av7110 *av7110)
av7110->registered = 1;
- dvb_add_frontend_notifier (av7110->dvb_adapter,
- av7110_before_after_tune, av7110);
-
- /**
- * init DiSEqC stuff
- */
- dvb_add_frontend_ioctls (av7110->dvb_adapter,
- av7110_diseqc_ioctl, NULL, av7110);
-
dvbdemux->priv = (void *) av7110;
for (i = 0; i < 32; i++)
@@ -1252,11 +1226,7 @@ static void dvb_unregister(struct av7110 *av7110)
dvb_dmxdev_release(&av7110->dmxdev);
dvb_dmx_release(&av7110->demux);
- dvb_remove_frontend_notifier (av7110->dvb_adapter,
- av7110_before_after_tune);
- dvb_remove_frontend_ioctls (av7110->dvb_adapter,
- av7110_diseqc_ioctl, NULL);
-
+ if (av7110->fe != NULL) dvb_unregister_frontend(av7110->fe);
dvb_unregister_device(av7110->osd_dev);
av7110_av_unregister(av7110);
av7110_ca_unregister(av7110);
@@ -1407,28 +1377,470 @@ static int get_firmware(struct av7110* av7110)
#endif
-static int client_register(struct i2c_client *client)
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
- struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
- struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u8 pwr = 0;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ u32 div = (params->frequency + 479500) / 125;
+
+ if (params->frequency > 2000000) pwr = 3;
+ else if (params->frequency > 1800000) pwr = 2;
+ else if (params->frequency > 1600000) pwr = 1;
+ else if (params->frequency > 1200000) pwr = 0;
+ else if (params->frequency >= 1100000) pwr = 1;
+ else pwr = 2;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = ((div & 0x18000) >> 10) | 0x95;
+ buf[3] = (pwr << 6) | 0x30;
+
+ // NOTE: since we're using a prescaler of 2, we set the
+ // divisor frequency to 62.5kHz and divide by 125 above
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config = {
+ .demod_address = 0x08,
+ .xin = 90100000UL,
+ .invert_pwm = 0,
+ .pll_set = alps_bsrv2_pll_set,
+};
+
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
- /* fixme: check for "type" (ie. frontend type) */
- if (client->driver->command)
- return client->driver->command(client, FE_REGISTER, av7110->dvb_adapter);
return 0;
}
-static int client_unregister(struct i2c_client *client)
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
- struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
- struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ int ret;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000))
+ return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ data[3] = 0xC4;
+
+ if (params->frequency > 1530000) data[3] = 0xc0;
+
+ ret = i2c_transfer (&av7110->i2c_adap, &msg, 1);
+ if (ret != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (params->frequency + 35937500 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85 | ((div >> 10) & 0x60);
+ data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+ .pll_set = alps_tdbe2_pll_set,
+};
+
+
+
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = params->frequency / 125;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = 0x00;
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+ .demod_address = 0x68,
+ .pll_set = grundig_29504_451_pll_set,
+};
+
+
+
+static int philips_cd1516_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div;
+ u32 f = params->frequency;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (f + 36125000 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct ves1820_config philips_cd1516_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+ .pll_set = philips_cd1516_pll_set,
+};
+
+
+
+static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div, pwr;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (params->frequency + 36200000) / 166666;
+
+ if (params->frequency <= 782000000)
+ pwr = 1;
+ else
+ pwr = 2;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85;
+ data[3] = pwr << 6;
- /* fixme: check for "type" (ie. frontend type) */
- if (client->driver->command)
- return client->driver->command(client, FE_UNREGISTER, av7110->dvb_adapter);
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
+static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &av7110->dev->pci->dev);
+}
+
+static struct sp8870_config alps_tdlb7_config = {
+
+ .demod_address = 0x71,
+ .pll_set = alps_tdlb7_pll_set,
+ .request_firmware = alps_tdlb7_request_firmware,
+};
+
+
+static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
+{
+ msleep (50);
+
+ av7110->fe_synced = (status & FE_HAS_LOCK) ? 1 : 0;
+
+ if (av7110->playing)
+ return;
+
+ if (down_interruptible(&av7110->pid_mutex))
+ return;
+
+ if (av7110->fe_synced) {
+ SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+ av7110->pids[DMX_PES_AUDIO],
+ av7110->pids[DMX_PES_TELETEXT], 0,
+ av7110->pids[DMX_PES_PCR]);
+ av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ } else {
+ SetPIDs(av7110, 0, 0, 0, 0, 0);
+ av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0);
+ }
+
+ av7110->fe_status = status;
+ up(&av7110->pid_mutex);
+}
+
+static int av7110_fe_init(struct dvb_frontend* fe)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_init(fe);
+}
+
+static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ int ret;
+
+ /* call the real implementation */
+ ret = av7110->fe_read_status(fe, status);
+ if (ret)
+ return ret;
+
+ if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) {
+ av7110_fe_lock_fix(av7110, *status);
+ }
+
+ return 0;
+}
+
+static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_diseqc_reset_overload(fe);
+}
+
+static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_diseqc_send_master_cmd(fe, cmd);
+}
+
+static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_diseqc_send_burst(fe, minicmd);
+}
+
+static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_set_tone(fe, tone);
+}
+
+static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_set_voltage(fe, voltage);
+}
+
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+}
+
+static u8 read_pwm(struct av7110* av7110)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static void frontend_init(struct av7110 *av7110)
+{
+ if (av7110->dev->pci->subsystem_vendor == 0x110a) {
+ switch(av7110->dev->pci->subsystem_device) {
+ case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
+ av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe)
+ break;
+ break;
+ }
+
+ } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) {
+ switch(av7110->dev->pci->subsystem_device) {
+ case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+ case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X
+ case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
+
+ // try the ALPS BSRV2 first of all
+ av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops->set_tone = av7110_set_tone;
+ break;
+ }
+
+ // try the ALPS BSRU6 now
+ av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops->set_tone = av7110_set_tone;
+ break;
+ }
+
+ // Try the grundig 29504-451
+ av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops->set_tone = av7110_set_tone;
+ break;
+ }
+ break;
+
+ case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
+
+ // ALPS TDLB7
+ av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+ if (av7110->fe)
+ break;
+ break;
+
+ case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
+
+ av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe)
+ break;
+ break;
+ }
+ }
+
+ if (av7110->fe == NULL) {
+ printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ av7110->dev->pci->vendor,
+ av7110->dev->pci->device,
+ av7110->dev->pci->subsystem_vendor,
+ av7110->dev->pci->subsystem_device);
+ } else {
+ FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+ FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+ if (dvb_register_frontend(av7110->dvb_adapter, av7110->fe)) {
+ printk("av7110: Frontend registration failed!\n");
+ if (av7110->fe->ops->release)
+ av7110->fe->ops->release(av7110->fe);
+ av7110->fe = NULL;
+ }
+ }
+}
+
static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
{
struct av7110 *av7110 = NULL;
@@ -1454,20 +1866,16 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
}
dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, THIS_MODULE);
-
+
/* the Siemens DVB needs this if you want to have the i2c chips
get recognized before the main driver is fully loaded */
saa7146_write(dev, GPIO_CTRL, 0x500000);
- av7110->i2c_adap = (struct i2c_adapter) {
- .client_register = client_register,
- .client_unregister = client_unregister,
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- .class = I2C_ADAP_CLASS_TV_DIGITAL,
+ av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
#else
- .class = I2C_CLASS_TV_DIGITAL,
+ av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
#endif
- };
strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -1566,6 +1974,9 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
if (ret)
goto err3;
+ av7110->dvb_adapter->priv = av7110;
+ frontend_init(av7110);
+
printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
av7110->device_initialized = 1;
av7110_num++;
@@ -1662,33 +2073,28 @@ static struct saa7146_pci_extension_data x_var = { \
.ext_priv = x_name, \
.ext = &av7110_extension }
-MAKE_AV7110_INFO(fs_1_5, "Siemens cable card PCI rev1.5");
-MAKE_AV7110_INFO(fs_1_3, "Siemens/Technotrend/Hauppauge PCI rev1.3");
-MAKE_AV7110_INFO(tt_1_6, "Technotrend/Hauppauge PCI rev1.3 or 1.6");
-MAKE_AV7110_INFO(tt_2_1, "Technotrend/Hauppauge PCI rev2.1 or 2.2");
-MAKE_AV7110_INFO(tt_t, "Technotrend/Hauppauge PCI DVB-T");
-MAKE_AV7110_INFO(unkwn0, "Technotrend/Hauppauge PCI rev?(unknown0)?");
-MAKE_AV7110_INFO(unkwn1, "Technotrend/Hauppauge PCI rev?(unknown1)?");
-MAKE_AV7110_INFO(unkwn2, "Technotrend/Hauppauge PCI rev?(unknown2)?");
-MAKE_AV7110_INFO(nexus, "Technotrend/Hauppauge Nexus PCI DVB-S");
-MAKE_AV7110_INFO(dvboc11,"Octal/Technotrend DVB-C for iTV");
+MAKE_AV7110_INFO(tts_1_X, "Technotrend/Hauppauge WinTV DVB-S rev1.X");
+MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X");
+MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X");
+MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X");
+MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV Nexus-S rev1.3");
+MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C");
static struct pci_device_id pci_tbl[] = {
- MAKE_EXTENSION_PCI(fs_1_5, 0x110a, 0xffff),
- MAKE_EXTENSION_PCI(fs_1_5, 0x110a, 0x0000),
- MAKE_EXTENSION_PCI(fs_1_3, 0x13c2, 0x0000),
- MAKE_EXTENSION_PCI(unkwn0, 0x13c2, 0x1002),
- MAKE_EXTENSION_PCI(tt_1_6, 0x13c2, 0x0001),
- MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0002),
- MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0003),
- MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0004),
- MAKE_EXTENSION_PCI(tt_1_6, 0x13c2, 0x0006),
- MAKE_EXTENSION_PCI(tt_t, 0x13c2, 0x0008),
- MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x1102),
- MAKE_EXTENSION_PCI(unkwn1, 0xffc2, 0x0000),
- MAKE_EXTENSION_PCI(unkwn2, 0x00a1, 0x00a1),
- MAKE_EXTENSION_PCI(nexus, 0x00a1, 0xa1a0),
- MAKE_EXTENSION_PCI(dvboc11,0x13c2, 0x000a),
+ MAKE_EXTENSION_PCI(tts_1_X, 0x13c2, 0x0000),
+ MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001),
+ MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002),
+ MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003),
+ MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002),
+ MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000),
+
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0006), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-S v????
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */ // TT/Hauppauge WinTV DVB-T v????
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x000a), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
+
{
.vendor = 0,
}
diff --git a/linux/drivers/media/dvb/ttpci/av7110.h b/linux/drivers/media/dvb/ttpci/av7110.h
index abdc8ab8a..5d2da07f8 100644
--- a/linux/drivers/media/dvb/ttpci/av7110.h
+++ b/linux/drivers/media/dvb/ttpci/av7110.h
@@ -24,9 +24,17 @@
#include "dvb_filter.h"
#include "dvb_net.h"
#include "dvb_ringbuffer.h"
+#include "dvb_frontend.h"
+#include "ves1820.h"
+#include "ves1x93.h"
+#include "stv0299.h"
+#include "tda8083.h"
+#include "sp8870.h"
+
#include <media/saa7146_vv.h>
+
extern int av7110_debug;
#define dprintk(level,args...) \
@@ -217,6 +225,17 @@ struct av7110 {
unsigned char *bin_root;
unsigned long size_root;
+
+ struct dvb_frontend* fe;
+ fe_status_t fe_status;
+ int (*fe_init)(struct dvb_frontend* fe);
+ int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
+ int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
+ int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+ int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+ int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+ int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+ int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
};
diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c
index 036442e33..28792962d 100644
--- a/linux/drivers/media/dvb/ttpci/budget-av.c
+++ b/linux/drivers/media/dvb/ttpci/budget-av.c
@@ -31,6 +31,9 @@
*/
#include "budget.h"
+#include "stv0299.h"
+#include "tda10021.h"
+#include "tda1004x.h"
#include <media/saa7146_vv.h>
struct budget_av {
@@ -159,6 +162,328 @@ static int saa7113_setinput (struct budget_av *budget_av, int input)
return 0;
}
+
+static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+ u8 m1;
+
+ aclk = 0xb5;
+ if (srate < 2000000) bclk = 0x86;
+ else if (srate < 5000000) bclk = 0x89;
+ else if (srate < 15000000) bclk = 0x8f;
+ else if (srate < 45000000) bclk = 0x95;
+
+ m1 = 0x14;
+ if (srate < 4000000) m1 = 0x10;
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+ stv0299_writereg (fe, 0x0f, 0x80 | m1);
+
+ return 0;
+}
+
+static int philips_su1278_ty_ci_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_av* budget_av = (struct budget_av*) fe->dvb->priv;
+ u32 div;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ buf[3] = 0x20;
+
+ if (params->u.qpsk.symbol_rate < 4000000) buf[3] |= 1;
+
+ if (params->frequency < 1250000) buf[3] |= 0;
+ else if (params->frequency < 1550000) buf[3] |= 0x40;
+ else if (params->frequency < 2050000) buf[3] |= 0x80;
+ else if (params->frequency < 2150000) buf[3] |= 0xC0;
+
+ if (i2c_transfer (&budget_av->budget.i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static u8 typhoon_cinergy1200s_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x92,
+ 0xff, 0xff
+};
+
+static struct stv0299_config typhoon_config = {
+ .demod_address = 0x68,
+ .inittab = typhoon_cinergy1200s_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+ .pll_set = philips_su1278_ty_ci_pll_set,
+};
+
+
+static struct stv0299_config cinergy_1200s_config = {
+ .demod_address = 0x68,
+ .inittab = typhoon_cinergy1200s_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_0,
+ .volt13_op0_op1 = STV0299_VOLT13_OP0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+ .pll_set = philips_su1278_ty_ci_pll_set,
+};
+
+
+static int philips_cu1216_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 buf[4];
+ struct i2c_msg msg= { .addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf) };
+
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + 36125000 + TUNER_MUL/2) / TUNER_MUL;
+
+ buf[0] = (div>>8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x8e;
+ buf[3] =(params->frequency < 174500000 ? 0xa1 :
+ params->frequency < 454000000 ? 0x92 : 0x34);
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct tda10021_config philips_cu1216_config = {
+ .demod_address = 0x0c,
+ .pll_set = philips_cu1216_pll_set,
+};
+
+
+
+
+static int philips_tu1216_pll_init(struct dvb_frontend* fe)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=tu1216_init, .len=sizeof(tu1216_init) };
+
+ // setup PLL configuration
+ if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+ msleep(1);
+
+ // disable the mc44BC374c (do not check for errors)
+ tuner_msg.addr = 0x65;
+ tuner_msg.buf = disable_mc44BC374c;
+ tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) {
+ i2c_transfer(&budget->i2c_adap, &tuner_msg, 1);
+ }
+
+ return 0;
+}
+
+static int philips_tu1216_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ // determine charge pump
+ tuner_frequency = params->frequency + 36130000;
+ if (tuner_frequency < 87000000) return -EINVAL;
+ else if (tuner_frequency < 130000000) cp = 3;
+ else if (tuner_frequency < 160000000) cp = 5;
+ else if (tuner_frequency < 200000000) cp = 6;
+ else if (tuner_frequency < 290000000) cp = 3;
+ else if (tuner_frequency < 420000000) cp = 5;
+ else if (tuner_frequency < 480000000) cp = 6;
+ else if (tuner_frequency < 620000000) cp = 3;
+ else if (tuner_frequency < 830000000) cp = 5;
+ else if (tuner_frequency < 895000000) cp = 7;
+ else return -EINVAL;
+
+ // determine band
+ if (params->frequency < 49000000) return -EINVAL;
+ else if (params->frequency < 159000000) band = 1;
+ else if (params->frequency < 444000000) band = 2;
+ else if (params->frequency < 861000000) band = 4;
+ else return -EINVAL;
+
+ // setup PLL filter
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0xFF);
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // calculate divisor
+ // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+ tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+
+ // setup tuner buffer
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+
+ msleep(1);
+ return 0;
+}
+
+static int philips_tu1216_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
+struct tda1004x_config philips_tu1216_config = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .pll_init = philips_tu1216_pll_init,
+ .pll_set = philips_tu1216_pll_set,
+ .request_firmware = philips_tu1216_request_firmware,
+};
+
+
+
+
+static u8 read_pwm(struct budget_av* budget_av)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+
+static void frontend_init(struct budget_av *budget_av)
+{
+ switch(budget_av->budget.dev->pci->subsystem_device) {
+ case 0x4f56: // Typhoon/KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059))
+ budget_av->budget.dvb_frontend = stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap);
+ if (budget_av->budget.dvb_frontend != NULL) {
+ break;
+ }
+ break;
+
+ case 0x1154: // TerraTec Cinergy 1200 DVB-S (stv0299/Philips SU1278(tsa5059))
+ budget_av->budget.dvb_frontend = stv0299_attach(&cinergy_1200s_config, &budget_av->budget.i2c_adap);
+ if (budget_av->budget.dvb_frontend != NULL) {
+ break;
+ }
+ break;
+
+ case 0x1156: // Terratec Cinergy 1200 DVB-C (tda10021/Philips CU1216(tua6034))
+ budget_av->budget.dvb_frontend = tda10021_attach(&philips_cu1216_config, &budget_av->budget.i2c_adap, read_pwm(budget_av));
+ if (budget_av->budget.dvb_frontend) {
+ break;
+ }
+ break;
+
+ case 0x1157: // Terratec Cinergy 1200 DVB-T (tda10046/Philips TU1216(tda6651tt))
+ budget_av->budget.dvb_frontend = tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap);
+ if (budget_av->budget.dvb_frontend) {
+ break;
+ }
+ break;
+ }
+
+ if (budget_av->budget.dvb_frontend == NULL) {
+ printk("budget_av: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ budget_av->budget.dev->pci->vendor,
+ budget_av->budget.dev->pci->device,
+ budget_av->budget.dev->pci->subsystem_vendor,
+ budget_av->budget.dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) {
+ printk("budget-av: Frontend registration failed!\n");
+ if (budget_av->budget.dvb_frontend->ops->release)
+ budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+ budget_av->budget.dvb_frontend = NULL;
+ }
+ }
+}
+
+
static int budget_av_detach (struct saa7146_dev *dev)
{
struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
@@ -173,7 +498,7 @@ static int budget_av_detach (struct saa7146_dev *dev)
saa7146_unregister_device (&budget_av->vd, dev);
}
-
+ if (budget_av->budget.dvb_frontend != NULL) dvb_unregister_frontend(budget_av->budget.dvb_frontend);
err = ttpci_budget_deinit (&budget_av->budget);
kfree (budget_av);
@@ -187,16 +512,11 @@ static int budget_av_attach (struct saa7146_dev* dev,
struct saa7146_pci_extension_data *info)
{
struct budget_av *budget_av;
- struct budget_info *bi = info->ext_priv;
u8 *mac;
int err;
dprintk(2, "dev: %p\n", dev);
- if (bi->type != BUDGET_KNC1 && bi->type != BUDGET_CIN1200) {
- return -ENODEV;
- }
-
if (!(budget_av = kmalloc(sizeof(struct budget_av), GFP_KERNEL)))
return -ENOMEM;
@@ -260,6 +580,10 @@ static int budget_av_attach (struct saa7146_dev* dev,
printk("KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
budget_av->budget.dvb_adapter->num,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ budget_av->budget.dvb_adapter->priv = budget_av;
+ frontend_init(budget_av);
+
return 0;
}
@@ -343,11 +667,15 @@ static struct saa7146_ext_vv vv_data = {
static struct saa7146_extension budget_extension;
MAKE_BUDGET_INFO(knc1, "KNC1 DVB-S", BUDGET_KNC1);
-MAKE_BUDGET_INFO(cin1200, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200);
+MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
+MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
+MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
static struct pci_device_id pci_tbl [] = {
MAKE_EXTENSION_PCI(knc1, 0x1131, 0x4f56),
- MAKE_EXTENSION_PCI(cin1200, 0x153b, 0x1154),
+ MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
+ MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
+ MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
{
.vendor = 0,
}
diff --git a/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c
index c2703e558..bbd1dc0a3 100644
--- a/linux/drivers/media/dvb/ttpci/budget-ci.c
+++ b/linux/drivers/media/dvb/ttpci/budget-ci.c
@@ -39,6 +39,8 @@
#include <linux/spinlock.h>
#include "dvb_ca_en50221.h"
+#include "stv0299.h"
+#include "tda1004x.h"
#define DEBIADDR_IR 0x1234
#define DEBIADDR_CICONTROL 0x0000
@@ -503,12 +505,383 @@ static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr)
tasklet_schedule (&budget_ci->ciintf_irq_tasklet);
}
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
+}
+
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+ u8 buf[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ buf[3] = 0xC4;
+
+ if (params->frequency > 1530000) buf[3] = 0xc0;
+
+ if (i2c_transfer (&budget_ci->budget.i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+
+static u8 philips_su1278_tt_inittab[] = {
+ 0x01, 0x0f,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x5b,
+ 0x05, 0x85,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0x02,
+ 0x09, 0x00,
+ 0x0C, 0x01,
+ 0x0D, 0x81,
+ 0x0E, 0x44,
+ 0x0f, 0x14,
+ 0x10, 0x3c,
+ 0x11, 0x84,
+ 0x12, 0xda,
+ 0x13, 0x97,
+ 0x14, 0x95,
+ 0x15, 0xc9,
+ 0x16, 0x19,
+ 0x17, 0x8c,
+ 0x18, 0x59,
+ 0x19, 0xf8,
+ 0x1a, 0xfe,
+ 0x1c, 0x7f,
+ 0x1d, 0x00,
+ 0x1e, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00,
+ 0x29, 0x28,
+ 0x2a, 0x14,
+ 0x2b, 0x0f,
+ 0x2c, 0x09,
+ 0x2d, 0x09,
+ 0x31, 0x1f,
+ 0x32, 0x19,
+ 0x33, 0xfc,
+ 0x34, 0x93,
+ 0xff, 0xff
+};
+
+static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ stv0299_writereg (fe, 0x0e, 0x44);
+ if (srate >= 10000000) {
+ stv0299_writereg (fe, 0x13, 0x97);
+ stv0299_writereg (fe, 0x14, 0x95);
+ stv0299_writereg (fe, 0x15, 0xc9);
+ stv0299_writereg (fe, 0x17, 0x8c);
+ stv0299_writereg (fe, 0x1a, 0xfe);
+ stv0299_writereg (fe, 0x1c, 0x7f);
+ stv0299_writereg (fe, 0x2d, 0x09);
+ } else {
+ stv0299_writereg (fe, 0x13, 0x99);
+ stv0299_writereg (fe, 0x14, 0x8d);
+ stv0299_writereg (fe, 0x15, 0xce);
+ stv0299_writereg (fe, 0x17, 0x43);
+ stv0299_writereg (fe, 0x1a, 0x1d);
+ stv0299_writereg (fe, 0x1c, 0x12);
+ stv0299_writereg (fe, 0x2d, 0x05);
+ }
+ stv0299_writereg (fe, 0x0e, 0x23);
+ stv0299_writereg (fe, 0x0f, 0x94);
+ stv0299_writereg (fe, 0x10, 0x39);
+ stv0299_writereg (fe, 0x15, 0xc9);
+
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
+}
+
+static int philips_su1278_tt_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+ u32 div;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (500 - 1)) / 500; // round correctly
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
+ buf[3] = 0x20;
+
+ if (params->u.qpsk.symbol_rate < 4000000) buf[3] |= 1;
+
+ if (params->frequency < 1250000) buf[3] |= 0;
+ else if (params->frequency < 1550000) buf[3] |= 0x40;
+ else if (params->frequency < 2050000) buf[3] |= 0x80;
+ else if (params->frequency < 2150000) buf[3] |= 0xC0;
+
+ if (i2c_transfer (&budget_ci->budget.i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct stv0299_config philips_su1278_tt_config = {
+
+ .demod_address = 0x68,
+ .inittab = philips_su1278_tt_inittab,
+ .mclk = 64000000UL,
+ .invert = 0,
+ .enhanced_tuning = 1,
+ .skip_reinit = 1,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 50,
+ .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
+ .pll_set = philips_su1278_tt_pll_set,
+};
+
+
+
+static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+ static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ struct i2c_msg tuner_msg = { .addr=0x63, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
+
+ // setup PLL configuration
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+ msleep(1);
+
+ // disable the mc44BC374c (do not check for errors)
+ tuner_msg.addr = 0x65;
+ tuner_msg.buf = disable_mc44BC374c;
+ tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+ i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
+ }
+
+ return 0;
+}
+
+static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr=0x63, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ // determine charge pump
+ tuner_frequency = params->frequency + 36130000;
+ if (tuner_frequency < 87000000) return -EINVAL;
+ else if (tuner_frequency < 130000000) cp = 3;
+ else if (tuner_frequency < 160000000) cp = 5;
+ else if (tuner_frequency < 200000000) cp = 6;
+ else if (tuner_frequency < 290000000) cp = 3;
+ else if (tuner_frequency < 420000000) cp = 5;
+ else if (tuner_frequency < 480000000) cp = 6;
+ else if (tuner_frequency < 620000000) cp = 3;
+ else if (tuner_frequency < 830000000) cp = 5;
+ else if (tuner_frequency < 895000000) cp = 7;
+ else return -EINVAL;
+
+ // determine band
+ if (params->frequency < 49000000) return -EINVAL;
+ else if (params->frequency < 159000000) band = 1;
+ else if (params->frequency < 444000000) band = 2;
+ else if (params->frequency < 861000000) band = 4;
+ else return -EINVAL;
+
+ // setup PLL filter and TDA9889
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0x14);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0x80);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0x14);
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // calculate divisor
+ // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+ tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+
+ // setup tuner buffer
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+
+ msleep(1);
+ return 0;
+}
+
+static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
+}
+
+struct tda1004x_config philips_tdm1316l_config = {
+
+ .demod_address = 0x8,
+ .invert = 0,
+ .pll_init = philips_tdm1316l_pll_init,
+ .pll_set = philips_tdm1316l_pll_set,
+ .request_firmware = philips_tdm1316l_request_firmware,
+};
+
+
+
+static void frontend_init(struct budget_ci *budget_ci)
+{
+ switch(budget_ci->budget.dev->pci->subsystem_device) {
+ case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
+ budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ break;
+ }
+ break;
+
+ case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
+ budget_ci->budget.dvb_frontend = stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ break;
+ }
+ break;
+
+ case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+ budget_ci->budget.dvb_frontend = tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ break;
+ }
+ break;
+ }
+
+ if (budget_ci->budget.dvb_frontend == NULL) {
+ printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ budget_ci->budget.dev->pci->vendor,
+ budget_ci->budget.dev->pci->device,
+ budget_ci->budget.dev->pci->subsystem_vendor,
+ budget_ci->budget.dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
+ printk("budget-ci: Frontend registration failed!\n");
+ if (budget_ci->budget.dvb_frontend->ops->release)
+ budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+ }
+ }
+}
+
static int budget_ci_attach (struct saa7146_dev* dev,
- struct saa7146_pci_extension_data *info)
+ struct saa7146_pci_extension_data *info)
{
struct budget_ci *budget_ci;
int err;
-
+
if (!(budget_ci = kmalloc (sizeof(struct budget_ci), GFP_KERNEL)))
return -ENOMEM;
@@ -531,6 +904,9 @@ static int budget_ci_attach (struct saa7146_dev* dev,
ciintf_init(budget_ci);
+ budget_ci->budget.dvb_adapter->priv = budget_ci;
+ frontend_init(budget_ci);
+
return 0;
}
@@ -541,7 +917,7 @@ static int budget_ci_detach (struct saa7146_dev* dev)
int err;
if (budget_ci->budget.ci_present) ciintf_deinit(budget_ci);
-
+ if (budget_ci->budget.dvb_frontend) dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
err = ttpci_budget_deinit (&budget_ci->budget);
tasklet_kill (&budget_ci->msp430_irq_tasklet);
@@ -578,7 +954,7 @@ static struct saa7146_extension budget_extension = {
.module = THIS_MODULE,
.pci_tbl = &pci_tbl[0],
- .attach = budget_ci_attach,
+ .attach = budget_ci_attach,
.detach = budget_ci_detach,
.irq_mask = MASK_03 | MASK_06 | MASK_10,
diff --git a/linux/drivers/media/dvb/ttpci/budget-core.c b/linux/drivers/media/dvb/ttpci/budget-core.c
index 6bd202b24..7334119a4 100644
--- a/linux/drivers/media/dvb/ttpci/budget-core.c
+++ b/linux/drivers/media/dvb/ttpci/budget-core.c
@@ -257,27 +257,6 @@ static void budget_unregister(struct budget *budget)
dvb_dmx_release(&budget->demux);
}
-/* fixme: can this be unified among all saa7146 based dvb cards? */
-static int client_register(struct i2c_client *client)
-{
- struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
- struct budget *budget = (struct budget*)dev->ext_priv;
-
- if (client->driver->command)
- return client->driver->command(client, FE_REGISTER, budget->dvb_adapter);
- return 0;
-}
-
-static int client_unregister(struct i2c_client *client)
-{
- struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
- struct budget *budget = (struct budget*)dev->ext_priv;
-
- if (client->driver->command)
- return client->driver->command(client, FE_UNREGISTER, budget->dvb_adapter);
- return 0;
-}
-
int ttpci_budget_init (struct budget *budget,
struct saa7146_dev* dev,
struct saa7146_pci_extension_data *info)
@@ -313,15 +292,11 @@ int ttpci_budget_init (struct budget *budget,
if (bi->type != BUDGET_FS_ACTIVY)
saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
- budget->i2c_adap = (struct i2c_adapter) {
- .client_register = client_register,
- .client_unregister = client_unregister,
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- .class = I2C_ADAP_CLASS_TV_DIGITAL,
+ budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
#else
- .class = I2C_CLASS_TV_DIGITAL,
+ budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
#endif
- };
strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
diff --git a/linux/drivers/media/dvb/ttpci/budget-patch.c b/linux/drivers/media/dvb/ttpci/budget-patch.c
index 6cfe90960..f57fc3b90 100644
--- a/linux/drivers/media/dvb/ttpci/budget-patch.c
+++ b/linux/drivers/media/dvb/ttpci/budget-patch.c
@@ -33,6 +33,9 @@
#include "av7110.h"
#include "av7110_hw.h"
#include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "tda8083.h"
#define budget_patch budget
@@ -118,45 +121,259 @@ static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg,
return 0;
}
-int budget_patch_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+
+static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
- struct budget_patch *budget = fe->before_after_data;
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
- dprintk(2, "budget: %p\n", budget);
+ switch (tone) {
+ case SEC_TONE_ON:
+ av7110_set22k (budget, 1);
+ break;
- switch (cmd) {
- case FE_SET_TONE:
- switch ((fe_sec_tone_mode_t) arg) {
- case SEC_TONE_ON:
- av7110_set22k (budget, 1);
- break;
- case SEC_TONE_OFF:
- av7110_set22k (budget, 0);
- break;
- default:
- return -EINVAL;
- }
- break;
-
- case FE_DISEQC_SEND_MASTER_CMD:
- {
- struct dvb_diseqc_master_cmd *cmd = arg;
+ case SEC_TONE_OFF:
+ av7110_set22k (budget, 0);
+ break;
- av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
- break;
- }
+ default:
+ return -EINVAL;
+ }
- case FE_DISEQC_SEND_BURST:
- av7110_send_diseqc_msg (budget, 0, NULL, (int) (long) arg);
- break;
+ return 0;
+}
- default:
- return -EOPNOTSUPP;
- }
+static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
- return 0;
+ av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
+
+ return 0;
+}
+
+static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+
+ av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
+
+ return 0;
+}
+
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+ u8 pwr = 0;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ u32 div = (params->frequency + 479500) / 125;
+
+ if (params->frequency > 2000000) pwr = 3;
+ else if (params->frequency > 1800000) pwr = 2;
+ else if (params->frequency > 1600000) pwr = 1;
+ else if (params->frequency > 1200000) pwr = 0;
+ else if (params->frequency >= 1100000) pwr = 1;
+ else pwr = 2;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = ((div & 0x18000) >> 10) | 0x95;
+ buf[3] = (pwr << 6) | 0x30;
+
+ // NOTE: since we're using a prescaler of 2, we set the
+ // divisor frequency to 62.5kHz and divide by 125 above
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config = {
+ .demod_address = 0x08,
+ .xin = 90100000UL,
+ .invert_pwm = 0,
+ .pll_set = alps_bsrv2_pll_set,
+};
+
+
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
}
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ data[3] = 0xC4;
+
+ if (params->frequency > 1530000) data[3] = 0xc0;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = params->frequency / 125;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = 0x00;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+struct tda8083_config grundig_29504_451_config = {
+ .demod_address = 0x68,
+ .pll_set = grundig_29504_451_pll_set,
+};
+
+
+
+
+
+static void frontend_init(struct budget_patch* budget)
+{
+ switch(budget->dev->pci->subsystem_device) {
+ case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+
+ // try the ALPS BSRV2 first of all
+ budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ break;
+ }
+
+ // try the ALPS BSRU6 now
+ budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ break;
+ }
+
+ // Try the grundig 29504-451
+ budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ break;
+ }
+ break;
+ }
+
+ if (budget->dvb_frontend == NULL) {
+ printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ budget->dev->pci->vendor,
+ budget->dev->pci->device,
+ budget->dev->pci->subsystem_vendor,
+ budget->dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+ printk("budget-av: Frontend registration failed!\n");
+ if (budget->dvb_frontend->ops->release)
+ budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ budget->dvb_frontend = NULL;
+ }
+ }
+}
+
+
static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
struct budget_patch *budget;
@@ -216,11 +433,11 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
// Enable RPS1 (rFC p33)
saa7146_write(dev, MC1, (MASK_13 | MASK_29));
- dvb_add_frontend_ioctls (budget->dvb_adapter,
- budget_patch_diseqc_ioctl, NULL, budget);
-
dev->ext_priv = budget;
+ budget->dvb_adapter->priv = budget;
+ frontend_init(budget);
+
return 0;
}
@@ -229,8 +446,7 @@ static int budget_patch_detach (struct saa7146_dev* dev)
struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
int err;
- dvb_remove_frontend_ioctls (budget->dvb_adapter,
- budget_patch_diseqc_ioctl, NULL);
+ if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
err = ttpci_budget_deinit (budget);
diff --git a/linux/drivers/media/dvb/ttpci/budget.c b/linux/drivers/media/dvb/ttpci/budget.c
index a6a3b973f..dc3ae56c7 100644
--- a/linux/drivers/media/dvb/ttpci/budget.c
+++ b/linux/drivers/media/dvb/ttpci/budget.c
@@ -35,6 +35,11 @@
*/
#include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "ves1820.h"
+#include "l64781.h"
+#include "tda8083.h"
static void Set22K (struct budget *budget, int state)
{
@@ -106,46 +111,6 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
}
-int budget_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct budget *budget = fe->before_after_data;
-
- dprintk(2, "budget: %p\n", budget);
-
- switch (cmd) {
- case FE_SET_TONE:
- switch ((fe_sec_tone_mode_t) arg) {
- case SEC_TONE_ON:
- Set22K (budget, 1);
- break;
- case SEC_TONE_OFF:
- Set22K (budget, 0);
- break;
- default:
- return -EINVAL;
- };
- break;
-
- case FE_DISEQC_SEND_MASTER_CMD:
- {
- struct dvb_diseqc_master_cmd *cmd = arg;
-
- SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
- break;
- }
-
- case FE_DISEQC_SEND_BURST:
- SendDiSEqCMsg (budget, 0, NULL, (unsigned long)arg);
- break;
-
- default:
- return -EOPNOTSUPP;
- };
-
- return 0;
-}
-
-
/*
* Routines for the Fujitsu Siemens Activy budget card
* 22 kHz tone and DiSEqC are handled by the frontend.
@@ -172,22 +137,350 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
}
-static int budget_ioctl_activy (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
- struct budget *budget = fe->before_after_data;
+ struct budget* budget = (struct budget*) fe->dvb->priv;
- dprintk(2, "budget: %p\n", budget);
+ return SetVoltage_Activy (budget, voltage);
+}
- switch (cmd) {
- case FE_SET_VOLTAGE:
- return SetVoltage_Activy (budget, (fe_sec_voltage_t) arg);
- default:
- return -EOPNOTSUPP;
+static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ Set22K (budget, 1);
+ break;
+ case SEC_TONE_OFF:
+ Set22K (budget, 0);
+ break;
}
+ return -EINVAL;
+}
+
+static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
+
return 0;
}
+static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ SendDiSEqCMsg (budget, 0, NULL, minicmd);
+
+ return 0;
+}
+
+
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 pwr = 0;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ u32 div = (params->frequency + 479500) / 125;
+
+ if (params->frequency > 2000000) pwr = 3;
+ else if (params->frequency > 1800000) pwr = 2;
+ else if (params->frequency > 1600000) pwr = 1;
+ else if (params->frequency > 1200000) pwr = 0;
+ else if (params->frequency >= 1100000) pwr = 1;
+ else pwr = 2;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = ((div & 0x18000) >> 10) | 0x95;
+ buf[3] = (pwr << 6) | 0x30;
+
+ // NOTE: since we're using a prescaler of 2, we set the
+ // divisor frequency to 62.5kHz and divide by 125 above
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config =
+{
+ .demod_address = 0x08,
+ .xin = 90100000UL,
+ .invert_pwm = 0,
+ .pll_set = alps_bsrv2_pll_set,
+};
+
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
+}
+
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ data[3] = 0xC4;
+
+ if (params->frequency > 1530000) data[3] = 0xc0;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (params->frequency + 35937500 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85 | ((div >> 10) & 0x60);
+ data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+ .pll_set = alps_tdbe2_pll_set,
+};
+
+
+
+static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u32 div;
+ u8 cfg, cpump, band_select;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (36125000 + params->frequency) / 166666;
+
+ cfg = 0x88;
+
+ if (params->frequency < 175000000) cpump = 2;
+ else if (params->frequency < 390000000) cpump = 1;
+ else if (params->frequency < 470000000) cpump = 2;
+ else if (params->frequency < 750000000) cpump = 1;
+ else cpump = 3;
+
+ if (params->frequency < 175000000) band_select = 0x0e;
+ else if (params->frequency < 470000000) band_select = 0x05;
+ else band_select = 0x03;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = ((div >> 10) & 0x60) | cfg;
+ data[3] = (cpump << 6) | band_select;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct l64781_config grundig_29504_401_config = {
+ .demod_address = 0x55,
+ .pll_set = grundig_29504_401_pll_set,
+};
+
+
+
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = params->frequency / 125;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = 0x00;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+ .demod_address = 0x68,
+ .pll_set = grundig_29504_451_pll_set,
+};
+
+static u8 read_pwm(struct budget* budget)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static void frontend_init(struct budget *budget)
+{
+ switch(budget->dev->pci->subsystem_device) {
+ case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
+
+ // try the ALPS BSRV2 first of all
+ budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ break;
+ }
+
+ // try the ALPS BSRU6 now
+ budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ break;
+ }
+ break;
+
+ case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+
+ budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+ if (budget->dvb_frontend) break;
+ break;
+
+ case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
+
+ budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) break;
+ break;
+
+ case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI (tda8083/Grundig 29504-451(tsa5522))
+
+ // grundig 29504-451
+ budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
+ break;
+ }
+ break;
+ }
+
+ if (budget->dvb_frontend == NULL) {
+ printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ budget->dev->pci->vendor,
+ budget->dev->pci->device,
+ budget->dev->pci->subsystem_vendor,
+ budget->dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+ printk("budget: Frontend registration failed!\n");
+ if (budget->dvb_frontend->ops->release)
+ budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ budget->dvb_frontend = NULL;
+ }
+ }
+}
static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
@@ -209,12 +502,8 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_
return err;
}
- if (budget->card->type == BUDGET_FS_ACTIVY)
- dvb_add_frontend_ioctls (budget->dvb_adapter,
- budget_ioctl_activy, NULL, budget);
- else
- dvb_add_frontend_ioctls (budget->dvb_adapter,
- budget_diseqc_ioctl, NULL, budget);
+ budget->dvb_adapter->priv = budget;
+ frontend_init(budget);
return 0;
}
@@ -225,12 +514,7 @@ static int budget_detach (struct saa7146_dev* dev)
struct budget *budget = (struct budget*) dev->ext_priv;
int err;
- if (budget->card->type == BUDGET_FS_ACTIVY)
- dvb_remove_frontend_ioctls (budget->dvb_adapter,
- budget_ioctl_activy, NULL);
- else
- dvb_remove_frontend_ioctls (budget->dvb_adapter,
- budget_diseqc_ioctl, NULL);
+ if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
err = ttpci_budget_deinit (budget);
@@ -247,18 +531,14 @@ static struct saa7146_extension budget_extension;
MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
+/* MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); UNDEFINED HARDWARE - mail linuxtv.org list */
MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY);
-/* Uncomment for Budget Patch */
-/*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/
static struct pci_device_id pci_tbl[] = {
- /* Uncomment for Budget Patch */
- /*MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000),*/
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
- MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+/* MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), UNDEFINED HARDWARE */
MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61),
{
.vendor = 0,
diff --git a/linux/drivers/media/dvb/ttpci/budget.h b/linux/drivers/media/dvb/ttpci/budget.h
index 70bb39af2..3a8095b29 100644
--- a/linux/drivers/media/dvb/ttpci/budget.h
+++ b/linux/drivers/media/dvb/ttpci/budget.h
@@ -62,6 +62,7 @@ struct budget {
spinlock_t feedlock;
struct dvb_adapter *dvb_adapter;
+ struct dvb_frontend *dvb_frontend;
void *priv;
};
@@ -83,7 +84,9 @@ static struct saa7146_pci_extension_data x_var = { \
#define BUDGET_KNC1 2
#define BUDGET_PATCH 3
#define BUDGET_FS_ACTIVY 4
-#define BUDGET_CIN1200 5
+#define BUDGET_CIN1200S 5
+#define BUDGET_CIN1200C 6
+#define BUDGET_CIN1200T 7
#define BUDGET_VIDEO_PORTA 0
#define BUDGET_VIDEO_PORTB 1
diff --git a/linux/drivers/media/dvb/ttusb-budget/Kconfig b/linux/drivers/media/dvb/ttusb-budget/Kconfig
index c8bbbcc68..1ecad0278 100644
--- a/linux/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/linux/drivers/media/dvb/ttusb-budget/Kconfig
@@ -1,6 +1,8 @@
config DVB_TTUSB_BUDGET
tristate "Technotrend/Hauppauge Nova-USB devices"
depends on DVB_CORE && USB
+ select DVB_CX22700
+ select DVB_TDA1004X
help
Support for external USB adapters designed by Technotrend and
produced by Hauppauge, shipped under the brand name 'Nova-USB'.
diff --git a/linux/drivers/media/dvb/ttusb-budget/Makefile b/linux/drivers/media/dvb/ttusb-budget/Makefile
index a57b9aee6..6ab97f6b5 100644
--- a/linux/drivers/media/dvb/ttusb-budget/Makefile
+++ b/linux/drivers/media/dvb/ttusb-budget/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 3ce423b55..338eeb507 100644
--- a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -24,11 +24,14 @@
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_net.h"
+#include "cx22700.h"
+#include "tda1004x.h"
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
#include <linux/pci.h>
+
/*
TTUSB_HWSECTIONS:
the DSP supports filtering in hardware, however, since the "muxstream"
@@ -132,6 +135,8 @@ struct ttusb {
#if 0
devfs_handle_t stc_devfs_handle;
#endif
+
+ struct dvb_frontend* fe;
};
/* ugly workaround ... don't know why it's neccessary to read */
@@ -461,9 +466,10 @@ static int ttusb_init_controller(struct ttusb *ttusb)
}
#ifdef TTUSB_DISEQC
-static int ttusb_send_diseqc(struct ttusb *ttusb,
- const struct dvb_diseqc_master_cmd *cmd)
+static int ttusb_send_diseqc(struct dvb_frontend* fe,
+ const struct dvb_diseqc_master_cmd *cmd)
{
+ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 b[12] = { 0xaa, ++ttusb->c, 0x18 };
int err;
@@ -501,41 +507,24 @@ static int ttusb_update_lnb(struct ttusb *ttusb)
return err;
}
-static int ttusb_set_voltage(struct ttusb *ttusb, fe_sec_voltage_t voltage)
+static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
+ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+
ttusb->voltage = voltage;
return ttusb_update_lnb(ttusb);
}
#ifdef TTUSB_TONE
-static int ttusb_set_tone(struct ttusb *ttusb, fe_sec_tone_mode_t tone)
+static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
+ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+
ttusb->tone = tone;
return ttusb_update_lnb(ttusb);
}
#endif
-static int ttusb_lnb_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct ttusb *ttusb = fe->before_after_data;
-
- switch (cmd) {
- case FE_SET_VOLTAGE:
- return ttusb_set_voltage(ttusb, (fe_sec_voltage_t) arg);
-#ifdef TTUSB_TONE
- case FE_SET_TONE:
- return ttusb_set_tone(ttusb, (fe_sec_tone_mode_t) arg);
-#endif
-#ifdef TTUSB_DISEQC
- case FE_DISEQC_SEND_MASTER_CMD:
- return ttusb_send_diseqc(ttusb,
- (struct dvb_diseqc_master_cmd *)
- arg);
-#endif
- default:
- return -EOPNOTSUPP;
- };
-}
#if 0
static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq)
@@ -1076,33 +1065,178 @@ u32 functionality(struct i2c_adapter *adapter)
return I2C_FUNC_I2C;
}
-static struct i2c_algorithm ttusb_dec_algo = {
- .name = "ttusb dec i2c algorithm",
- .id = I2C_ALGO_BIT,
- .master_xfer = master_xfer,
- .functionality = functionality,
-};
-static int client_register(struct i2c_client *client)
+
+static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
- struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
+ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+ u8 data[4];
+ struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) };
+ u32 div;
+
+ div = (params->frequency + 36166667) / 166667;
- if (client->driver->command)
- return client->driver->command(client, FE_REGISTER, ttusb->adapter);
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = ((div >> 10) & 0x60) | 0x85;
+ data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
+ if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
-static int client_unregister(struct i2c_client *client)
+struct cx22700_config alps_tdmb7_config = {
+ .demod_address = 0x43,
+ .pll_set = alps_tdmb7_pll_set,
+};
+
+
+
+
+
+static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
{
- struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
+ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+ static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
+
+ // setup PLL configuration
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+ msleep(1);
+
+ // disable the mc44BC374c (do not check for errors)
+ tuner_msg.addr = 0x65;
+ tuner_msg.buf = disable_mc44BC374c;
+ tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+ i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
+ }
- if (client->driver->command)
- return client->driver->command(client, FE_UNREGISTER, ttusb->adapter);
+ return 0;
+}
+static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ // determine charge pump
+ tuner_frequency = params->frequency + 36130000;
+ if (tuner_frequency < 87000000) return -EINVAL;
+ else if (tuner_frequency < 130000000) cp = 3;
+ else if (tuner_frequency < 160000000) cp = 5;
+ else if (tuner_frequency < 200000000) cp = 6;
+ else if (tuner_frequency < 290000000) cp = 3;
+ else if (tuner_frequency < 420000000) cp = 5;
+ else if (tuner_frequency < 480000000) cp = 6;
+ else if (tuner_frequency < 620000000) cp = 3;
+ else if (tuner_frequency < 830000000) cp = 5;
+ else if (tuner_frequency < 895000000) cp = 7;
+ else return -EINVAL;
+
+ // determine band
+ if (params->frequency < 49000000) return -EINVAL;
+ else if (params->frequency < 159000000) band = 1;
+ else if (params->frequency < 444000000) band = 2;
+ else if (params->frequency < 861000000) band = 4;
+ else return -EINVAL;
+
+ // setup PLL filter
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0xFF);
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // calculate divisor
+ // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+ tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+
+ // setup tuner buffer
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+
+ msleep(1);
return 0;
}
+static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &ttusb->dev->dev);
+}
+
+struct tda1004x_config philips_tdm1316l_config = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .pll_init = philips_tdm1316l_pll_init,
+ .pll_set = philips_tdm1316l_pll_set,
+ .request_firmware = philips_tdm1316l_request_firmware,
+};
+
+
+
+static void frontend_init(struct ttusb* ttusb)
+{
+ switch(ttusb->dev->descriptor.idProduct) {
+ case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
+ // try the ALPS TDMB7 first
+ ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) break;
+
+ // Philips td1316
+ ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) break;
+ break;
+ }
+
+ if (ttusb->fe == NULL) {
+ printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n",
+ ttusb->dev->descriptor.idVendor,
+ ttusb->dev->descriptor.idProduct);
+ } else {
+ if (dvb_register_frontend(ttusb->adapter, ttusb->fe)) {
+ printk("dvb-ttusb-budget: Frontend registration failed!\n");
+ if (ttusb->fe->ops->release)
+ ttusb->fe->ops->release(ttusb->fe);
+ ttusb->fe = NULL;
+ }
+ }
+}
+
+
+
+static struct i2c_algorithm ttusb_dec_algo = {
+ .name = "ttusb dec i2c algorithm",
+ .id = I2C_ALGO_BIT,
+ .master_xfer = master_xfer,
+ .functionality = functionality,
+};
+
static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev;
@@ -1140,6 +1274,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
up(&ttusb->sem);
dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
+ ttusb->adapter->priv = ttusb;
/* i2c */
memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter));
@@ -1155,18 +1290,13 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
ttusb->i2c_adap.algo = &ttusb_dec_algo;
ttusb->i2c_adap.algo_data = NULL;
ttusb->i2c_adap.id = I2C_ALGO_BIT;
- ttusb->i2c_adap.client_register = client_register;
- ttusb->i2c_adap.client_unregister = client_unregister;
-
+
result = i2c_add_adapter(&ttusb->i2c_adap);
if (result) {
dvb_unregister_adapter (ttusb->adapter);
return result;
}
- dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL,
- ttusb);
-
memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux));
ttusb->dvb_demux.dmx.capabilities =
@@ -1220,6 +1350,8 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
#endif
usb_set_intfdata(intf, (void *) ttusb);
+ frontend_init(ttusb);
+
return 0;
}
@@ -1237,7 +1369,7 @@ static void ttusb_disconnect(struct usb_interface *intf)
dvb_net_release(&ttusb->dvbnet);
dvb_dmxdev_release(&ttusb->dmxdev);
dvb_dmx_release(&ttusb->dvb_demux);
-
+ if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe);
i2c_del_adapter(&ttusb->i2c_adap);
dvb_unregister_adapter(ttusb->adapter);
@@ -1249,8 +1381,8 @@ static void ttusb_disconnect(struct usb_interface *intf)
}
static struct usb_device_id ttusb_table[] = {
- {USB_DEVICE(0xb48, 0x1003)},
- {USB_DEVICE(0xb48, 0x1004)}, /* to be confirmed ???? */
+/* {USB_DEVICE(0xb48, 0x1003)},UNDEFINED HARDWARE - mail linuxtv.org list */
+/* {USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/ /* to be confirmed ???? */
{USB_DEVICE(0xb48, 0x1005)},
{}
};
diff --git a/linux/drivers/media/dvb/ttusb-dec/Makefile b/linux/drivers/media/dvb/ttusb-dec/Makefile
index bf4e38740..b41bf1f06 100644
--- a/linux/drivers/media/dvb/ttusb-dec/Makefile
+++ b/linux/drivers/media/dvb/ttusb-dec/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o
+obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 6f1c40a7c..737ecbc16 100644
--- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -42,6 +42,7 @@
#include "dvb_filter.h"
#include "dvb_frontend.h"
#include "dvb_net.h"
+#include "ttusbdecfe.h"
static int debug;
static int output_pva;
@@ -69,9 +70,6 @@ MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
#define MAX_PVA_LENGTH 6144
-#define LOF_HI 10600000
-#define LOF_LO 9750000
-
enum ttusb_dec_model {
TTUSB_DEC2000T,
TTUSB_DEC2540T,
@@ -102,12 +100,9 @@ struct ttusb_dec {
struct dvb_demux demux;
struct dmx_frontend frontend;
struct dvb_net dvb_net;
- struct dvb_frontend_info *frontend_info;
- int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *);
+ struct dvb_frontend* fe;
u16 pid[DMX_PES_OTHER];
- int hi_band;
- int voltage;
/* USB bits */
struct usb_device *udev;
@@ -166,32 +161,6 @@ struct filter_info {
struct list_head filter_info_list;
};
-static struct dvb_frontend_info dec2000t_frontend_info = {
- .name = "TechnoTrend/Hauppauge DEC2000-t Frontend",
- .type = FE_OFDM,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 62500,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO,
-};
-
-static struct dvb_frontend_info dec3000s_frontend_info = {
- .name = "TechnoTrend/Hauppauge DEC3000-s Frontend",
- .type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
- .frequency_stepsize = 125,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO,
-};
-
static void ttusb_dec_set_model(struct ttusb_dec *dec,
enum ttusb_dec_model model);
@@ -1404,6 +1373,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
dvb_dmxdev_release(&dec->dmxdev);
dvb_dmx_release(&dec->demux);
+ if (dec->fe) dvb_unregister_frontend(dec->fe);
dvb_unregister_adapter(dec->adapter);
}
@@ -1435,261 +1405,6 @@ static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
}
}
-static int ttusb_dec_2000t_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd,
- void *arg)
-{
- struct ttusb_dec *dec = fe->data;
-
- dprintk("%s\n", __FUNCTION__);
-
- switch (cmd) {
- case FE_GET_INFO:
- dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
- memcpy(arg, dec->frontend_info,
- sizeof (struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS: {
- fe_status_t *status = (fe_status_t *)arg;
- dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
- *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
- FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
- break;
- }
-
- case FE_READ_BER: {
- u32 *ber = (u32 *)arg;
- dprintk("%s: FE_READ_BER\n", __FUNCTION__);
- *ber = 0;
- return -ENOSYS;
- break;
- }
-
- case FE_READ_SIGNAL_STRENGTH: {
- dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
- *(s32 *)arg = 0xFF;
- return -ENOSYS;
- break;
- }
-
- case FE_READ_SNR:
- dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
- *(s32 *)arg = 0;
- return -ENOSYS;
- break;
-
- case FE_READ_UNCORRECTED_BLOCKS:
- dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
- *(u32 *)arg = 0;
- return -ENOSYS;
- break;
-
- case FE_SET_FRONTEND: {
- struct dvb_frontend_parameters *p =
- (struct dvb_frontend_parameters *)arg;
- u8 b[] = { 0x00, 0x00, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff };
- u32 freq;
-
- dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
-
- dprintk(" frequency->%d\n", p->frequency);
- dprintk(" symbol_rate->%d\n",
- p->u.qam.symbol_rate);
- dprintk(" inversion->%d\n", p->inversion);
-
- freq = htonl(p->frequency / 1000);
- memcpy(&b[4], &freq, sizeof (u32));
- ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
-
- break;
- }
-
- case FE_GET_FRONTEND:
- dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
- break;
-
- case FE_SLEEP:
- dprintk("%s: FE_SLEEP\n", __FUNCTION__);
- return -ENOSYS;
- break;
-
- case FE_INIT:
- dprintk("%s: FE_INIT\n", __FUNCTION__);
- break;
-
- default:
- dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ttusb_dec_3000s_frontend_ioctl(struct dvb_frontend *fe,
- unsigned int cmd, void *arg)
-{
- struct ttusb_dec *dec = fe->data;
-
- dprintk("%s\n", __FUNCTION__);
-
- switch (cmd) {
-
- case FE_GET_INFO:
- dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
- memcpy(arg, dec->frontend_info,
- sizeof (struct dvb_frontend_info));
- break;
-
- case FE_READ_STATUS: {
- fe_status_t *status = (fe_status_t *)arg;
- dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
- *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
- FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
- break;
- }
-
- case FE_READ_BER: {
- u32 *ber = (u32 *)arg;
- dprintk("%s: FE_READ_BER\n", __FUNCTION__);
- *ber = 0;
- return -ENOSYS;
- break;
- }
-
- case FE_READ_SIGNAL_STRENGTH: {
- dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
- *(s32 *)arg = 0xFF;
- return -ENOSYS;
- break;
- }
-
- case FE_READ_SNR:
- dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
- *(s32 *)arg = 0;
- return -ENOSYS;
- break;
-
- case FE_READ_UNCORRECTED_BLOCKS:
- dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
- *(u32 *)arg = 0;
- return -ENOSYS;
- break;
-
- case FE_SET_FRONTEND: {
- struct dvb_frontend_parameters *p =
- (struct dvb_frontend_parameters *)arg;
- u8 b[] = { 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00 };
- u32 freq;
- u32 sym_rate;
- u32 band;
- u32 lnb_voltage;
-
- dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
-
- dprintk(" frequency->%d\n", p->frequency);
- dprintk(" symbol_rate->%d\n",
- p->u.qam.symbol_rate);
- dprintk(" inversion->%d\n", p->inversion);
-
- freq = htonl(p->frequency +
- (dec->hi_band ? LOF_HI : LOF_LO));
- memcpy(&b[4], &freq, sizeof(u32));
- sym_rate = htonl(p->u.qam.symbol_rate);
- memcpy(&b[12], &sym_rate, sizeof(u32));
- band = htonl(dec->hi_band ? LOF_HI : LOF_LO);
- memcpy(&b[24], &band, sizeof(u32));
- lnb_voltage = htonl(dec->voltage);
- memcpy(&b[28], &lnb_voltage, sizeof(u32));
-
- ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
-
- break;
- }
-
- case FE_GET_FRONTEND:
- dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
- break;
-
- case FE_SLEEP:
- dprintk("%s: FE_SLEEP\n", __FUNCTION__);
- return -ENOSYS;
- break;
-
- case FE_INIT:
- dprintk("%s: FE_INIT\n", __FUNCTION__);
- break;
-
- case FE_DISEQC_SEND_MASTER_CMD: {
- u8 b[] = { 0x00, 0xff, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00 };
- struct dvb_diseqc_master_cmd *cmd = arg;
- memcpy(&b[4], cmd->msg, cmd->msg_len);
- dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__);
- ttusb_dec_send_command(dec, 0x72,
- sizeof(b) - (6 - cmd->msg_len), b,
- NULL, NULL);
- break;
- }
-
- case FE_DISEQC_SEND_BURST:
- dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__);
- break;
-
- case FE_SET_TONE: {
- fe_sec_tone_mode_t tone = (fe_sec_tone_mode_t)arg;
- dprintk("%s: FE_SET_TONE\n", __FUNCTION__);
- dec->hi_band = (SEC_TONE_ON == tone);
- break;
- }
-
- case FE_SET_VOLTAGE:
- dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
- switch ((fe_sec_voltage_t) arg) {
- case SEC_VOLTAGE_13:
- dec->voltage = 13;
- break;
- case SEC_VOLTAGE_18:
- dec->voltage = 18;
- break;
- default:
- return -EINVAL;
- break;
- }
- break;
-
- default:
- dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void ttusb_dec_init_frontend(struct ttusb_dec *dec)
-{
- int ret;
- ret = dvb_register_frontend(dec->frontend_ioctl, dec->adapter, dec, dec->frontend_info, THIS_MODULE);
-}
-
-static void ttusb_dec_exit_frontend(struct ttusb_dec *dec)
-{
- dvb_unregister_frontend(dec->frontend_ioctl, dec->adapter);
-}
-
static void ttusb_dec_init_filters(struct ttusb_dec *dec)
{
INIT_LIST_HEAD(&dec->filter_info_list);
@@ -1708,6 +1423,18 @@ static void ttusb_dec_exit_filters(struct ttusb_dec *dec)
}
}
+int fe_send_command(struct dvb_frontend* fe, const u8 command,
+ int param_length, const u8 params[],
+ int *result_length, u8 cmd_result[])
+{
+ struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv;
+ return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
+}
+
+struct ttusbdecfe_config fe_config = {
+ .send_command = fe_send_command
+};
+
static int ttusb_dec_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -1749,7 +1476,32 @@ static int ttusb_dec_probe(struct usb_interface *intf,
return 0;
}
ttusb_dec_init_dvb(dec);
- ttusb_dec_init_frontend(dec);
+
+ dec->adapter->priv = dec;
+ switch (id->idProduct) {
+ case 0x1006:
+ dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
+ break;
+
+ case 0x1008:
+ case 0x1009:
+ dec->fe = ttusbdecfe_dvbt_attach(&fe_config);
+ break;
+ }
+
+ if (dec->fe == NULL) {
+ printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n",
+ dec->udev->descriptor.idVendor,
+ dec->udev->descriptor.idProduct);
+ } else {
+ if (dvb_register_frontend(dec->adapter, dec->fe)) {
+ printk("budget-ci: Frontend registration failed!\n");
+ if (dec->fe->ops->release)
+ dec->fe->ops->release(dec->fe);
+ dec->fe = NULL;
+ }
+ }
+
ttusb_dec_init_v_pes(dec);
ttusb_dec_init_filters(dec);
ttusb_dec_init_tasklet(dec);
@@ -1773,7 +1525,6 @@ static void ttusb_dec_disconnect(struct usb_interface *intf)
ttusb_dec_exit_tasklet(dec);
ttusb_dec_exit_filters(dec);
ttusb_dec_exit_usb(dec);
- ttusb_dec_exit_frontend(dec);
ttusb_dec_exit_dvb(dec);
}
@@ -1789,22 +1540,16 @@ static void ttusb_dec_set_model(struct ttusb_dec *dec,
case TTUSB_DEC2000T:
dec->model_name = "DEC2000-t";
dec->firmware_name = "dvb-ttusb-dec-2000t.fw";
- dec->frontend_info = &dec2000t_frontend_info;
- dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
break;
case TTUSB_DEC2540T:
dec->model_name = "DEC2540-t";
dec->firmware_name = "dvb-ttusb-dec-2540t.fw";
- dec->frontend_info = &dec2000t_frontend_info;
- dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
break;
case TTUSB_DEC3000S:
dec->model_name = "DEC3000-s";
dec->firmware_name = "dvb-ttusb-dec-3000s.fw";
- dec->frontend_info = &dec3000s_frontend_info;
- dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl;
break;
}
}
diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
new file mode 100644
index 000000000..d6dd11c98
--- /dev/null
+++ b/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -0,0 +1,258 @@
+/*
+ * TTUSB DEC Frontend Driver
+ *
+ * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.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 "dvb_frontend.h"
+#include "ttusbdecfe.h"
+
+
+#define LOF_HI 10600000
+#define LOF_LO 9750000
+
+struct ttusbdecfe_state {
+
+ struct dvb_frontend_ops ops;
+
+ /* configuration settings */
+ const struct ttusbdecfe_config* config;
+
+ struct dvb_frontend frontend;
+
+ u8 hi_band;
+ u8 voltage;
+};
+
+
+static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+ u8 b[] = { 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff };
+
+ u32 freq = htonl(p->frequency / 1000);
+ memcpy(&b[4], &freq, sizeof (u32));
+ state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
+
+ return 0;
+}
+
+static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+ u8 b[] = { 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ u32 freq;
+ u32 sym_rate;
+ u32 band;
+ u32 lnb_voltage;
+
+ freq = htonl(p->frequency +
+ (state->hi_band ? LOF_HI : LOF_LO));
+ memcpy(&b[4], &freq, sizeof(u32));
+ sym_rate = htonl(p->u.qam.symbol_rate);
+ memcpy(&b[12], &sym_rate, sizeof(u32));
+ band = htonl(state->hi_band ? LOF_HI : LOF_LO);
+ memcpy(&b[24], &band, sizeof(u32));
+ lnb_voltage = htonl(state->voltage);
+ memcpy(&b[28], &lnb_voltage, sizeof(u32));
+
+ state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
+
+ return 0;
+}
+
+static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
+{
+ struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+ u8 b[] = { 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00 };
+
+ memcpy(&b[4], cmd->msg, cmd->msg_len);
+
+ state->config->send_command(fe, 0x72,
+ sizeof(b) - (6 - cmd->msg_len), b,
+ NULL, NULL);
+
+ return 0;
+}
+
+
+static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+ state->hi_band = (SEC_TONE_ON == tone);
+
+ return 0;
+}
+
+
+static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ state->voltage = 13;
+ break;
+ case SEC_VOLTAGE_18:
+ state->voltage = 18;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void ttusbdecfe_release(struct dvb_frontend* fe)
+{
+ struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbt_ops;
+
+struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config)
+{
+ struct ttusbdecfe_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
+
+struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config)
+{
+ struct ttusbdecfe_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->voltage = 0;
+ state->hi_band = 0;
+ memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state) kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
+
+ .info = {
+ .name = "TechnoTrend/Hauppauge DEC2000-t Frontend",
+ .type = FE_OFDM,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = ttusbdecfe_release,
+
+ .set_frontend = ttusbdecfe_dvbt_set_frontend,
+
+ .read_status = ttusbdecfe_read_status,
+};
+
+static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
+
+ .info = {
+ .name = "TechnoTrend/Hauppauge DEC3000-s Frontend",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = ttusbdecfe_release,
+
+ .set_frontend = ttusbdecfe_dvbs_set_frontend,
+
+ .read_status = ttusbdecfe_read_status,
+
+ .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd,
+ .set_voltage = ttusbdecfe_dvbs_set_voltage,
+ .set_tone = ttusbdecfe_dvbs_set_tone,
+};
+
+MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver");
+MODULE_AUTHOR("Alex Woods/Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ttusbdecfe_dvbt_attach);
+EXPORT_SYMBOL(ttusbdecfe_dvbs_attach);
diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h b/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h
new file mode 100644
index 000000000..15ccc3d1a
--- /dev/null
+++ b/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h
@@ -0,0 +1,38 @@
+/*
+ * TTUSB DEC Driver
+ *
+ * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.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 TTUSBDECFE_H
+#define TTUSBDECFE_H
+
+#include <linux/dvb/frontend.h>
+
+struct ttusbdecfe_config
+{
+ int (*send_command)(struct dvb_frontend* fe, const u8 command,
+ int param_length, const u8 params[],
+ int *result_length, u8 cmd_result[]);
+};
+
+extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config);
+
+extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config);
+
+#endif // TTUSBDECFE_H
diff --git a/linux/include/linux/dvb/frontend.h b/linux/include/linux/dvb/frontend.h
index 36df2d66f..10616f0e2 100644
--- a/linux/include/linux/dvb/frontend.h
+++ b/linux/include/linux/dvb/frontend.h
@@ -78,7 +78,7 @@ struct dvb_frontend_info {
__u32 symbol_rate_min;
__u32 symbol_rate_max;
__u32 symbol_rate_tolerance; /* ppm */
- __u32 notifier_delay; /* ms */
+ __u32 notifier_delay; /* DEPRECATED */
fe_caps_t caps;
};