Commit 5355c9c6 authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] dvb: update dib-usb driver

- added new usb ids for some more clones
- added option to deliver the complete TS with USB2.0 devices
- added support for the dib3000mc/p frontend driver
Signed-off-by: default avatarMichael Hunold <hunold@linuxtv.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 92aeca38
......@@ -47,7 +47,7 @@ Produced and reselled by KWorld:
Others:
-------
- Ultima Electronic/Artec T1 USB TVBOX (AN2135 and AN2235)
http://www.arteceuro.com/products-tvbox.html
http://82.161.246.249/products-tvbox.html
- Compro Videomate DVB-U2000 - DVB-T USB
http://www.comprousa.com/products/vmu2000.htm
......@@ -63,14 +63,23 @@ Others:
Supported devices USB2.0
========================
- Twinhan MagicBox II
http://www.twinhan.com/product_terrestrial_7.asp
- Yakumo DVB-T mobile
http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
- DiBcom USB2.0 DVB-T reference device (non-public)
0. NEWS:
2004-12-06 - possibility for demod i2c-address probing
- new usb IDs (Compro,Artec)
2004-11-23 - merged changes from DiB3000MC_ver2.1
- revised the debugging
- possibility to deliver the complete TS for USB2.0
2004-11-21 - first working version of the dib3000mc/p frontend driver.
2004-11-12 - added additional remote control keys. Thanks to Uwe Hanke.
2004-11-07 - added remote control support. Thanks to David Matthews.
2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec)
- merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD
......@@ -165,9 +174,7 @@ as a slave device in vdr, was not working for me. Some work has to be done
2. Known problems and bugs
TODO:
- remote control
- signal-quality and strength calculations
- i2c address probing
2.1. Adding support for devices
......@@ -189,7 +196,29 @@ the dvb-dibusb.h-file and create a patch and send it over to me or to
the linux-dvb mailing list, _after_ you have tried compiling and modprobing
it.
2.2. Comments
2.2. USB1.1 Bandwidth limitation
Most of the current supported devices are USB1.1 and thus they have a
maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
This is not enough for receiving the complete transport stream of a
DVB-T channel (which can be about 16 MBit/s). Normally this is not a
problem, if you only want to watch TV, but watching a channel while
recording another channel on the same frequency simply does not work.
This applies to all USB1.1 DVB-T devices.
A special problem of the dibusb for the USB1.1 is, that the USB control
IC has a problem with write accesses while having MPEG2-streaming
enabled. When you set another pid while receiving MPEG2-TS it happens, that
the stream is disturbed and probably data is lost (results in distortions of
the video or strange beeps within the audio stream). DiBcom is preparing a
firmware especially for Linux which perhaps solves the problem.
Especially VDR users are victoms of this bug. VDR frequently requests new PIDs
due the automatic scanning (introduced in 1.3.x, afaik) and epg-scan. Disabling
these features is maybe a solution. Additionally this behaviour of VDR exceeds
the USB1.1 bandwidth.
2.3. Comments
Patches, comments and suggestions are very very welcome
......
......@@ -3,6 +3,7 @@ config DVB_DIBUSB
depends on DVB_CORE && USB
select FW_LOADER
select DVB_DIB3000MB
select DVB_DIB3000MC
help
Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
DiBcom (http://www.dibcom.fr).
......@@ -32,19 +33,25 @@ config DVB_DIBUSB
Say Y if you own such a device and want to use it. You should build it as
a module.
config DVB_DIBUSB_MISDESIGNED_AN2235
bool "Enable support for some Artec T1 device, which identifies as AN2235"
config DVB_DIBUSB_MISDESIGNED_DEVICES
bool "Enable support for some misdesigned (see help) devices, which identify with wrong IDs"
depends on DVB_DIBUSB
help
Somehow Artec forgot to program the eeprom for some of their T1 devices. So
comes that they identify with the default Vendor and Product ID of the Cypress
CY7C64613 (AN2235).
Somehow Artec/Ultima Electronic forgot to program the eeprom of some of their
USB1.1/USB2.0 devices.
So comes that they identify with the default Vendor and Product ID of the Cypress
CY7C64613 (AN2235) or Cypress FX2.
Say Y if your Artec device has 0x0574 as Vendor ID and 0x2235 as Product ID.
Affected device IDs:
0x0574:0x2235 (Artec T1 USB1.1, cold)
0x04b4:0x8613 (Artec T1 USB2.0, cold)
0x0574:0x1002 (Artec T1 USB2.0, warm)
Say Y if your device one of the mentioned IDs.
config DVB_DIBCOM_DEBUG
bool "Enable extended debug support for DiBcom USB device"
depends on DVB_DIBUSB
help
Say Y if you want to enable debuging. See modinfo dvb-dibusb for
debug level.
debug levels.
......@@ -7,10 +7,8 @@
* 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)
*
*
* Remote control code added by David Matthews (dm@prolingua.co.uk)
*
* This program is free software; you can redistribute it and/or
......@@ -70,6 +68,9 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=e
#define deb_err(args...) dprintk(0x10,args)
#define deb_rc(args...) dprintk(0x20,args)
static int pid_parse;
module_param(pid_parse, int, 0x644);
MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
/* Version information */
#define DRIVER_VERSION "0.1"
......@@ -91,7 +92,7 @@ static int dibusb_readwrite_usb(struct usb_dibusb *dib,
wbuf[0] == DIBUSB_REQ_I2C_WRITE &&
dib->dibdev->parm->type == DIBUSB1_1)
deb_err("BUG: writing to i2c, while TS-streaming destroys the stream."
"(%x reg: %x %x)", wbuf[0],wbuf[2],wbuf[3]);
"(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
debug_dump(wbuf,wlen);
......@@ -190,6 +191,7 @@ static int dibusb_ctrl_feed(struct usb_dibusb *dib, int pid, int onoff)
dib->feedcount += onoff ? 1 : -1;
if (dib->pid_parse) {
if (dib->xfer_ops.pid_ctrl != NULL) {
if (dib->xfer_ops.pid_ctrl(dib->fe,pid,onoff) < 0) {
err("no free pid in list.");
......@@ -199,11 +201,20 @@ static int dibusb_ctrl_feed(struct usb_dibusb *dib, int pid, int onoff)
err("no pid ctrl callback.");
return -ENODEV;
}
}
/*
* start the feed, either if there is the firmware bug or
* if this was the first pid to set.
*/
if (dib->dibdev->parm->firmware_bug || dib->feedcount == onoff) {
deb_ts("controlling pid parser\n");
if (dib->xfer_ops.pid_parse != NULL) {
if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) {
err("could not handle pid_parser");
}
}
deb_ts("start feeding\n");
if (dib->xfer_ops.fifo_ctrl != NULL) {
if (dib->xfer_ops.fifo_ctrl(dib->fe,1)) {
......@@ -269,6 +280,13 @@ static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] =
{ 0x00, 0xff, 0x4c, KEY_PAUSE },
{ 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */
{ 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
{ 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */
{ 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */
{ 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */
{ 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */
{ 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */
{ 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */
/* Key codes for the KWorld/ADSTech/JetWay remote. */
{ 0x86, 0x6b, 0x12, KEY_POWER },
{ 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */
......@@ -374,17 +392,11 @@ static void dibusb_query_rc (void *data)
*/
#if 0
/*
* #if 0'ing the following 5 functions as they are not in use _now_,
* #if 0'ing the following functions as they are not in use _now_,
* but probably will be sometime.
*/
static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
{
return dibusb_readwrite_usb(dib,buf,len,NULL,0);
}
/*
* do not use this, just a workaround for a bug,
* which will hopefully never occur :).
......@@ -395,6 +407,21 @@ static int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
return dibusb_write_usb(dib,b,1);
}
/*
* ioctl for power control
*/
static int dibusb_hw_sleep(struct usb_dibusb *dib)
{
u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
}
#endif
static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
{
return dibusb_readwrite_usb(dib,buf,len,NULL,0);
}
/*
* ioctl for the firmware
*/
......@@ -409,23 +436,12 @@ static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
return dibusb_write_usb(dib,b,2+size);
}
/*
* ioctl for power control
*/
static int dibusb_hw_sleep(struct usb_dibusb *dib)
{
u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
}
static int dibusb_hw_wakeup(struct usb_dibusb *dib)
{
u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
}
#endif
/*
* I2C
*/
......@@ -458,7 +474,8 @@ static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
return I2C_FUNC_I2C;
}
static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct
dvb_frontend_parameters* params);
static struct dib3000_config thomson_cable_eu_config = {
.demod_address = 0x10,
......@@ -466,7 +483,8 @@ static struct dib3000_config thomson_cable_eu_config = {
.pll_set = thomson_cable_eu_pll_set,
};
static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct
dvb_frontend_parameters* params)
{
struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
u8 buf[4];
......@@ -493,7 +511,71 @@ static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct dvb_frontend
buf[2] = 0x8e;
buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) return -EIO;
if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
return -EIO;
msleep(1);
return 0;
}
static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct
dvb_frontend_parameters *params);
static struct dib3000_config panasonic_cofdm_env57h1xd5 = {
.demod_address = 0x18,
.pll_addr = 192,
.pll_set = panasonic_cofdm_env57h1xd5_pll_set,
};
static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct
dvb_frontend_parameters *params)
{
struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
u8 buf[4];
u32 freq = params->frequency;
u32 tfreq = (freq + 36125000) / 1000000 * 6 + 1;
u8 TA, T210, R210, ctrl1, cp210, p4321;
struct i2c_msg msg = {
.addr = panasonic_cofdm_env57h1xd5.pll_addr,
.flags = 0,
.buf = buf,
.len = sizeof(buf)
};
if (freq > 858000000) {
err("frequency cannot be larger than 858 MHz.");
return -EINVAL;
}
// contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0
TA = 1;
T210 = 0;
R210 = 0x2;
ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210;
// ******** CHARGE PUMP CONFIG vs RF FREQUENCIES *****************
if (freq < 470000000)
cp210 = 2; // VHF Low and High band ch E12 to E4 to E12
else if (freq < 526000000)
cp210 = 4; // UHF band Ch E21 to E27
else // if (freq < 862000000)
cp210 = 5; // UHF band ch E28 to E69
//********************* BW select *******************************
if (freq < 153000000)
p4321 = 1; // BW selected for VHF low
else if (freq < 470000000)
p4321 = 2; // BW selected for VHF high E5 to E12
else // if (freq < 862000000)
p4321 = 4; // BW selection for UHF E21 to E69
buf[0] = (tfreq >> 8) & 0xff;
buf[1] = (tfreq >> 0) & 0xff;
buf[2] = 0xff & ctrl1;
buf[3] = (cp210 << 5) | (p4321);
if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
return -EIO;
msleep(1);
return 0;
......@@ -508,7 +590,15 @@ static struct i2c_algorithm dibusb_algo = {
static void frontend_init(struct usb_dibusb* dib)
{
switch (dib->dibdev->parm->type) {
case DIBUSB1_1:
case DIBUSB1_1_AN2235:
dib->fe = dib3000mb_attach(&thomson_cable_eu_config, &dib->i2c_adap,&dib->xfer_ops);
break;
case DIBUSB2_0:
dib->fe = dib3000mc_attach(&panasonic_cofdm_env57h1xd5,&dib->i2c_adap, &dib->xfer_ops);
break;
}
if (dib->fe == NULL) {
printk("dvb-dibusb: A frontend driver was not found for device %04x/%04x\n",
......@@ -671,9 +761,11 @@ static int dibusb_init(struct usb_dibusb *dib)
deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
/* allocate the actual buffer for the URBs */
if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) {
deb_info("not enough memory.\n");
dibusb_exit(dib);
return -ENOMEM;
}
deb_info("allocation complete\n");
memset(dib->buffer,0,bufsize);
/* allocate and submit the URBs */
......@@ -721,6 +813,8 @@ static int dibusb_init(struct usb_dibusb *dib)
INIT_WORK(&dib->rc_query_work, dibusb_query_rc, dib);
dibusb_hw_wakeup(dib);
if ((ret = dibusb_dvb_init(dib))) {
dibusb_exit(dib);
return ret;
......@@ -844,27 +938,33 @@ static int dibusb_probe(struct usb_interface *intf,
if (cold)
ret = dibusb_loadfirmware(udev,dibdev);
else {
dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL);
if (dib == NULL) {
err("no memory");
return ret;
}
memset(dib,0,sizeof(struct usb_dibusb));
dib->pid_parse = 1;
switch (udev->speed) {
case USB_SPEED_LOW:
err("cannot handle USB speed because it is to sLOW.");
break;
case USB_SPEED_FULL:
info("running at FULL speed, will use pid filter.");
info("running at FULL speed, will use pid parsing.");
break;
case USB_SPEED_HIGH:
if (!pid_parse) {
dib->pid_parse = 0;
info("running at HIGH speed, will deliver the complete TS.");
} else
info("running at HIGH speed, will use pid_parsing anyway.");
break;
case USB_SPEED_UNKNOWN: /* fall through */
default:
err("cannot handle USB speed because it is unkown.");
break;
}
dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL);
if (dib == NULL) {
err("no memory");
return ret;
}
memset(dib,0,sizeof(struct usb_dibusb));
dib->udev = udev;
dib->dibdev = dibdev;
......
......@@ -67,7 +67,7 @@ static struct dibusb_device_parameter dibusb_dev_parm[3] = {
.data_pipe = 0x82,
},
{ .type = DIBUSB2_0,
.demod_addr = 0x10,
.demod_addr = 0x18,
.fw_filenames = dibusb_fw_filenames2_0,
.usb_controller = "Cypress FX2",
.usb_cpu_csreg = 0xe600,
......@@ -109,6 +109,8 @@ struct dibusb_device {
#define USB_VID_ANCHOR 0x0547
#define USB_VID_AVERMEDIA 0x14aa
#define USB_VID_COMPRO 0x185b
#define USB_VID_COMPRO_UNK 0x145f
#define USB_VID_CYPRESS 0x04b4
#define USB_VID_DIBCOM 0x10b8
#define USB_VID_EMPIA 0xeb1a
#define USB_VID_GRANDTEC 0x5032
......@@ -122,6 +124,8 @@ struct dibusb_device {
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
......@@ -137,12 +141,15 @@ struct dibusb_device {
#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
#define USB_PID_YAKUMO_DTT200U_COLD 0x0201
#define USB_PID_YAKUMO_DTT200U_WARM 0x0301
#define DIBUSB_SUPPORTED_DEVICES 12
#define DIBUSB_SUPPORTED_DEVICES 15
/* USB Driver stuff */
static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
......@@ -176,11 +183,26 @@ static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
.warm_product_id = 0, /* undefined, this design becomes USB_PID_DIBCOM_MOD3000_WARM in warm state */
.parm = &dibusb_dev_parm[2],
},
{ .name = "Artec T1 USB2.0 TVBOX (please report the warm ID)",
.cold_product_id = USB_PID_ULTIMA_TVBOX_USB2_COLD,
.warm_product_id = 0, /* don't know, it is most likely that the device will get another USB ID in warm state */
.parm = &dibusb_dev_parm[1],
},
{ .name = "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
.cold_product_id = USB_PID_ULTIMA_TVBOX_USB2_FX_COLD,
.warm_product_id = USB_PID_ULTIMA_TVBOX_USB2_FX_WARM, /* undefined, it could be that the device will get another USB ID in warm state */
.parm = &dibusb_dev_parm[1],
},
{ .name = "Compro Videomate DVB-U2000 - DVB-T USB1.1",
.cold_product_id = USB_PID_COMPRO_DVBU2000_COLD,
.warm_product_id = USB_PID_COMPRO_DVBU2000_WARM,
.parm = &dibusb_dev_parm[0],
},
{ .name = "Compro Videomate DVB-U2000 - DVB-T USB1.1 (really ?? please report the name!)",
.cold_product_id = USB_PID_COMPRO_DVBU2000_UNK_COLD,
.warm_product_id = USB_PID_COMPRO_DVBU2000_UNK_WARM,
.parm = &dibusb_dev_parm[0],
},
{ .name = "Unkown USB1.1 DVB-T device ???? please report the name to the author",
.cold_product_id = USB_PID_UNK_HYPER_PALTEK_COLD,
.warm_product_id = USB_PID_UNK_HYPER_PALTEK_WARM,
......@@ -237,14 +259,18 @@ static struct usb_device_id dibusb_table [] = {
{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_COLD) },
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_WARM) },
{ USB_DEVICE(USB_PID_COMPRO_DVBU2000_UNK_COLD, USB_VID_COMPRO_UNK) },
{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
/*
* activate the following define when you have the device and want to compile
* build from build-2.6 in dvb-kernel
* activate the following define when you have one of the devices and want to
* build it from build-2.6 in dvb-kernel
*/
// #define CONFIG_DVB_DIBUSB_MISDESIGNED_AN2235
#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_AN2235
// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
{ USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
{ USB_DEVICE(USB_VID_CYPRESS, USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
{ USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
#endif
{ } /* Terminating entry */
};
......@@ -260,6 +286,7 @@ struct usb_dibusb {
struct dibusb_device * dibdev;
int feedcount;
int pid_parse;
struct dib3000_xfer_ops xfer_ops;
struct urb **urb_list;
......
......@@ -111,6 +111,13 @@ config DVB_DIB3000MB
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
config DVB_DIB3000MC
tristate "DiBcom 3000-MC/P"
depends on DVB_CORE
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
comment "DVB-C (cable) frontends"
depends on DVB_CORE
......
......@@ -11,7 +11,8 @@ obj-$(CONFIG_DVB_ATMEL_AT76C651) += at76c651.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
obj-$(CONFIG_DVB_L64781) += l64781.o
obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o dib3000-common.o
obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dib3000-common.o
obj-$(CONFIG_DVB_MT312) += mt312.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
......
#include "dib3000-common.h"
#ifdef CONFIG_DVB_DIBCOM_DEBUG
static int debug;
module_param(debug, int, 0x644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
#endif
#define deb_info(args...) dprintk(0x01,args)
#define deb_i2c(args...) dprintk(0x02,args)
#define deb_srch(args...) dprintk(0x04,args)
int dib3000_read_reg(struct dib3000_state *state, u16 reg)
{
u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
u8 rb[2];
struct i2c_msg msg[] = {
{ .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 },
{ .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
};
if (i2c_transfer(state->i2c, msg, 2) != 2)
deb_i2c("i2c read error\n");
deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
(rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
return (rb[0] << 8) | rb[1];
}
int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
{
u8 b[] = {
(reg >> 8) & 0xff, reg & 0xff,
(val >> 8) & 0xff, val & 0xff,
};
struct i2c_msg msg[] = {
{ .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
};
deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
}
int dib3000_init_pid_list(struct dib3000_state *state, int num)
{
int i;
if (state != NULL) {
state->pid_list = kmalloc(sizeof(struct dib3000_pid) * num,GFP_KERNEL);
if (state->pid_list == NULL)
return -ENOMEM;
deb_info("initializing %d pids for the pid_list.\n",num);
state->pid_list_lock = SPIN_LOCK_UNLOCKED;
memset(state->pid_list,0,num*(sizeof(struct dib3000_pid)));
for (i=0; i < num; i++) {
state->pid_list[i].pid = 0;
state->pid_list[i].active = 0;
}
state->feedcount = 0;
} else
return -EINVAL;
return 0;
}
void dib3000_dealloc_pid_list(struct dib3000_state *state)
{
if (state != NULL && state->pid_list != NULL)
kfree(state->pid_list);
}
/* fetch a pid from pid_list */
int dib3000_get_pid_index(struct dib3000_pid pid_list[], int num_pids, int pid,
spinlock_t *pid_list_lock,int onoff)
{
int i,ret = -1;
unsigned long flags;
spin_lock_irqsave(pid_list_lock,flags);
for (i=0; i < num_pids; i++)
if (onoff) {
if (!pid_list[i].active) {
pid_list[i].pid = pid;
pid_list[i].active = 1;
ret = i;
break;
}
} else {
if (pid_list[i].active && pid_list[i].pid == pid) {
pid_list[i].pid = 0;
pid_list[i].active = 0;
ret = i;
break;
}
}
deb_info("setting pid: %5d %04x at index %d '%s'\n",pid,pid,ret,onoff ? "on" : "off");
spin_unlock_irqrestore(pid_list_lock,flags);
return ret;
}
int dib3000_search_status(u16 irq,u16 lock)
{
if (irq & 0x02) {
if (lock & 0x01) {
deb_srch("auto search succeeded\n");
return 1; // auto search succeeded
} else {
deb_srch("auto search not successful\n");
return 0; // auto search failed
}
} else if (irq & 0x01) {
deb_srch("auto search failed\n");
return 0; // auto search failed
}
return -1; // try again
}
/* for auto search */
u16 dib3000_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 } */
}
};
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(dib3000_seq);
EXPORT_SYMBOL(dib3000_read_reg);
EXPORT_SYMBOL(dib3000_write_reg);
EXPORT_SYMBOL(dib3000_init_pid_list);
EXPORT_SYMBOL(dib3000_dealloc_pid_list);
EXPORT_SYMBOL(dib3000_get_pid_index);
EXPORT_SYMBOL(dib3000_search_status);
......@@ -26,6 +26,8 @@
#ifndef DIB3000_COMMON_H
#define DIB3000_COMMON_H
#include "dvb_frontend.h"
#include "dib3000.h"
/* info and err, taken from usb.h, if there is anything available like by default,
* please change !
......@@ -41,6 +43,63 @@ struct dib3000_pid
int active;
};
/* frontend state */
struct dib3000_state {
struct i2c_adapter* i2c;
struct dvb_frontend_ops ops;
/* configuration settings */
struct dib3000_config config;
spinlock_t pid_list_lock;
struct dib3000_pid *pid_list;
int feedcount;
struct dvb_frontend frontend;
int timing_offset;
int timing_offset_comp_done;
};
/* commonly used methods by the dib3000mb/mc/p frontend */
extern int dib3000_read_reg(struct dib3000_state *state, u16 reg);
extern int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val);
extern int dib3000_init_pid_list(struct dib3000_state *state, int num);
extern void dib3000_dealloc_pid_list(struct dib3000_state *state);
extern int dib3000_get_pid_index(struct dib3000_pid pid_list[], int num_pids,
int pid, spinlock_t *pid_list_lock,int onoff);
extern int dib3000_search_status(u16 irq,u16 lock);
/* handy shortcuts */
#define rd(reg) dib3000_read_reg(state,reg)
#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
{ err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
#define wr_foreach(a,v) { int i; \
if (sizeof(a) != sizeof(v)) \
err("sizeof: %d %d is different",sizeof(a),sizeof(v));\
for (i=0; i < sizeof(a)/sizeof(u16); i++) \
wr(a[i],v[i]); \
}
#define set_or(reg,val) wr(reg,rd(reg) | val)
#define set_and(reg,val) wr(reg,rd(reg) & val)
/* debug */
#ifdef CONFIG_DVB_DIBCOM_DEBUG
#define dprintk(level,args...) \
do { if ((debug & level)) { printk(args); } } while (0)
#else
#define dprintk(args...) do { } while (0)
#endif
/* mask for enabling a specific pid for the pid_filter */
#define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
......@@ -81,17 +140,7 @@ struct dib3000_pid
#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 7) | (1 << 7)))
/* for auto search */
static u16 dib3000_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 } */
}
};
extern u16 dib3000_seq[2][2][2];
#define DIB3000_REG_MANUFACTOR_ID ( 1025)
#define DIB3000_I2C_ID_DIBCOM (0x01b3)
......
......@@ -42,7 +42,7 @@ struct dib3000_config
struct dib3000_xfer_ops
{
/* pid and transfer handling is done in the demodulator */
int (*pid_filter)(struct dvb_frontend *fe, int onoff);
int (*pid_parse)(struct dvb_frontend *fe, int onoff);
int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff);
int (*pid_ctrl)(struct dvb_frontend *fe, int pid, int onoff);
};
......@@ -50,4 +50,6 @@ struct dib3000_xfer_ops
extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops);
extern struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops);
#endif // DIB3000_H
......@@ -34,135 +34,38 @@
#include "dib3000mb_priv.h"
#include "dib3000.h"
struct dib3000mb_state {
struct i2c_adapter* i2c;
struct dvb_frontend_ops ops;
/* configuration settings */
const struct dib3000_config* config;
spinlock_t pid_list_lock;
struct dib3000_pid pid_list[DIB3000MB_NUM_PIDS];
int feedcount;
struct dvb_frontend frontend;
};
/* debug */
/* Version information */
#define DRIVER_VERSION "0.1"
#define DRIVER_DESC "DiBcom 3000-MB DVB-T demodulator driver"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
#ifdef CONFIG_DVB_DIBCOM_DEBUG
#define dprintk(level,args...) \
do { if ((debug & level)) { printk(args); } } while (0)
static int debug;
module_param(debug, int, 0x644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=setfe,16=getfe (|-able)).");
#else
#define dprintk(args...) do { } while (0);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
#endif
#define deb_info(args...) dprintk(0x01,args)
#define deb_xfer(args...) dprintk(0x02,args)
#define deb_alot(args...) dprintk(0x04,args)
#define deb_setf(args...) dprintk(0x08,args)
#define deb_getf(args...) dprintk(0x10,args)
/* Version information */
#define DRIVER_VERSION "0.1"
#define DRIVER_DESC "DiBcom 3000-MB DVB-T demodulator driver"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
/* handy shortcuts */
#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));\
for (i=0; i < sizeof(a)/sizeof(u16); i++) \
wr(a[i],v[i]); \
}
static int dib3000mb_read_reg(struct dib3000mb_state *state, u16 reg)
{
u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
u8 rb[2];
struct i2c_msg msg[] = {
{ .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(state->i2c, msg, 2) != 2)
deb_alot("i2c read error\n");
return (rb[0] << 8) | rb[1];
}
static int dib3000mb_write_reg(struct dib3000mb_state *state, u16 reg, u16 val)
{
u8 b[] = {
(reg >> 8) & 0xff, reg & 0xff,
(val >> 8) & 0xff, val & 0xff,
};
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(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
}
static int dib3000mb_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep, int tuner);
#define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args)
static int dib3000mb_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep);
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(fe, &fep) == 0) {
deb_setf("reading tuning data from frontend succeeded.\n");
return dib3000mb_set_frontend(fe, &fep, 0) == 0;
} else {
deb_setf("reading tuning data failed -> tuning failed.\n");
return 0;
}
} else {
deb_setf("AS IRQ was pending, but LOCK2 was not & 0x01.\n");
return 0;
}
} else if (irq & 0x01) {
deb_setf("Autosearch failed.\n");
return 0;
}
return -1;
}
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 dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
fe_code_rate_t fe_cr = FEC_NONE;
int search_state,seq;
if (tuner) {
wr(DIB3000MB_REG_TUNER,
DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr));
state->config->pll_set(fe, fep);
DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
state->config.pll_set(fe, fep);
wr(DIB3000MB_REG_TUNER,
DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr));
DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
deb_setf("bandwidth: ");
switch (ofdm->bandwidth) {
......@@ -389,10 +292,22 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
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 && as_count++ < 100)
while ((search_state =
dib3000_search_status(
rd(DIB3000MB_REG_AS_IRQ_PENDING),
rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100)
msleep(1);
deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
if (search_state == 1) {
struct dvb_frontend_parameters feps;
if (dib3000mb_get_frontend(fe, &feps) == 0) {
deb_setf("reading tuning data from frontend succeeded.\n");
return dib3000mb_set_frontend(fe, &feps, 0);
}
}
} else {
wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_CTRL);
wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
......@@ -403,7 +318,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
{
struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_UP);
......@@ -474,12 +389,12 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
wr(DIB3000MB_REG_DATA_IN_DIVERSITY,DIB3000MB_DATA_DIVERSITY_IN_OFF);
if (state->config->pll_init) {
if (state->config.pll_init) {
wr(DIB3000MB_REG_TUNER,
DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr));
state->config->pll_init(fe);
DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
state->config.pll_init(fe);
wr(DIB3000MB_REG_TUNER,
DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr));
DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
}
return 0;
......@@ -488,7 +403,7 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
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 dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
fe_code_rate_t *cr;
u16 tps_val;
......@@ -499,7 +414,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
return 0;
dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
if (dds_val & threshold)
if (dds_val < threshold)
inv_test1 = 0;
else if (dds_val == threshold)
inv_test1 = 1;
......@@ -507,7 +422,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
inv_test1 = 2;
dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
if (dds_val & threshold)
if (dds_val < threshold)
inv_test2 = 0;
else if (dds_val == threshold)
inv_test2 = 1;
......@@ -516,7 +431,8 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
fep->inversion =
((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
((inv_test2 == 0) && (inv_test1==1 || inv_test1==2));
((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
INVERSION_ON : INVERSION_OFF;
deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
......@@ -541,10 +457,8 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
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 DIB3000_ALPHA_0:
deb_getf("HIERARCHY_NONE ");
......@@ -567,12 +481,15 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
break;
}
deb_getf("TPS: %d\n", tps_val);
tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
} 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;
tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
}
switch (tps_val) {
......@@ -645,7 +562,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
{
struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
*stat = 0;
......@@ -684,7 +601,7 @@ static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
{
struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
*ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB) );
return 0;
......@@ -701,7 +618,7 @@ static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
#define DIB3000MB_GAIN_DELTA_dBm -2
static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
/* TODO log10
u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER),
......@@ -737,7 +654,7 @@ static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength
*/
static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state* state = (struct dib3000_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);
......@@ -757,7 +674,7 @@ static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
*unc = rd(DIB3000MB_REG_UNC);
return 0;
......@@ -765,7 +682,7 @@ static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
static int dib3000mb_sleep(struct dvb_frontend* fe)
{
struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_DOWN);
return 0;
......@@ -792,49 +709,17 @@ static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_
static void dib3000mb_release(struct dvb_frontend* fe)
{
struct dib3000mb_state *state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
kfree(state);
}
/* pid filter and transfer stuff */
/* fetch a pid from pid_list */
static int dib3000_get_pid_index(struct dib3000_pid pid_list[],
int num_pids, int pid, spinlock_t *pid_list_lock,int onoff)
{
int i,ret = -1;
unsigned long flags;
spin_lock_irqsave(pid_list_lock,flags);
for (i=0; i < num_pids; i++)
if (onoff) {
if (!pid_list[i].active) {
pid_list[i].pid = pid;
pid_list[i].active = 1;
ret = i;
break;
}
} else {
if (pid_list[i].active && pid_list[i].pid == pid) {
pid_list[i].pid = 0;
pid_list[i].active = 0;
ret = i;
break;
}
}
spin_unlock_irqrestore(pid_list_lock,flags);
return ret;
}
static int dib3000mb_pid_control(struct dvb_frontend *fe,int pid,int onoff)
{
struct dib3000mb_state *state = fe->demodulator_priv;
struct dib3000_state *state = fe->demodulator_priv;
int index = dib3000_get_pid_index(state->pid_list, DIB3000MB_NUM_PIDS, pid, &state->pid_list_lock,onoff);
pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
deb_info("setting pid 0x%x on index %d\n",pid,index);
if (index >= 0) {
wr(index+DIB3000MB_REG_FIRST_PID,pid);
} else {
......@@ -846,8 +731,9 @@ static int dib3000mb_pid_control(struct dvb_frontend *fe,int pid,int onoff)
static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff)
{
struct dib3000mb_state *state = (struct dib3000mb_state*) fe->demodulator_priv;
struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
if (onoff) {
wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE);
} else {
......@@ -856,9 +742,9 @@ static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff)
return 0;
}
static int dib3000mb_pid_filter(struct dvb_frontend *fe, int onoff)
static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff)
{
//struct dib3000mb_state *state = fe->demodulator_priv;
//struct dib3000_state *state = fe->demodulator_priv;
/* switch it off and on */
return 0;
}
......@@ -868,17 +754,16 @@ static struct dvb_frontend_ops dib3000mb_ops;
struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops)
{
struct dib3000mb_state* state = NULL;
int i;
struct dib3000_state* state = NULL;
/* allocate memory for the internal state */
state = (struct dib3000mb_state*) kmalloc(sizeof(struct dib3000mb_state), GFP_KERNEL);
state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
if (state == NULL)
goto error;
/* setup the state */
state->config = config;
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
......@@ -888,22 +773,15 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID)
goto error;
/* initialize the id_list */
deb_info("initializing %d pids for the pid_list.\n",DIB3000MB_NUM_PIDS);
state->pid_list_lock = SPIN_LOCK_UNLOCKED;
memset(state->pid_list,0,DIB3000MB_NUM_PIDS*(sizeof(struct dib3000_pid)));
for (i=0; i < DIB3000MB_NUM_PIDS; i++) {
state->pid_list[i].pid = 0;
state->pid_list[i].active = 0;
}
state->feedcount = 0;
if (dib3000_init_pid_list(state,DIB3000MB_NUM_PIDS))
goto error;
/* create dvb_frontend */
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
/* set the xfer operations */
xfer_ops->pid_filter = dib3000mb_pid_filter;
xfer_ops->pid_parse = dib3000mb_pid_parse;
xfer_ops->fifo_ctrl = dib3000mb_fifo_control;
xfer_ops->pid_ctrl = dib3000mb_pid_control;
......
/*
* Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P
* 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.
*
* Acknowledgements
*
* Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
* sources, on which this driver (and the dvb-dibusb) are based.
*
* see Documentation/dvb/README.dibusb for more information
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "dib3000-common.h"
#include "dib3000mc_priv.h"
#include "dib3000.h"
/* Version information */
#define DRIVER_VERSION "0.1"
#define DRIVER_DESC "DiBcom 3000-MC DVB-T demodulator driver"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
#ifdef CONFIG_DVB_DIBCOM_DEBUG
static int debug;
module_param(debug, int, 0x644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
#endif
#define deb_info(args...) dprintk(0x01,args)
#define deb_xfer(args...) dprintk(0x02,args)
#define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args)
static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
{
switch (transmission_mode) {
case TRANSMISSION_MODE_2K:
wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]);
break;
case TRANSMISSION_MODE_8K:
wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]);
break;
default:
break;
}
switch (bandwidth) {
/* case BANDWIDTH_5_MHZ:
wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]);
break; */
case BANDWIDTH_6_MHZ:
wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]);
break;
case BANDWIDTH_7_MHZ:
wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]);
break;
case BANDWIDTH_8_MHZ:
wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]);
break;
default:
break;
}
switch (mode) {
case 0: /* no impulse */ /* fall through */
wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]);
break;
case 1: /* new algo */
wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]);
set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */
break;
default: /* old algo */
wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]);
break;
}
return 0;
}
static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset,
fe_transmit_mode_t fft, fe_bandwidth_t bw)
{
u16 timf_msb,timf_lsb;
s32 tim_offset,tim_sgn;
u64 comp1,comp2,comp=0;
switch (bw) {
case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break;
case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break;
case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break;
default: err("unknown bandwidth (%d)",bw); break;
}
timf_msb = (comp >> 16) & 0xff;
timf_lsb = (comp & 0xffff);
// Update the timing offset ;
if (upd_offset > 0) {
if (!state->timing_offset_comp_done) {
msleep(200);
state->timing_offset_comp_done = 1;
}
tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB);
if ((tim_offset & 0x2000) == 0x2000)
tim_offset |= 0xC000;
if (fft == TRANSMISSION_MODE_2K)
tim_offset <<= 2;
state->timing_offset += tim_offset;
}
tim_offset = state->timing_offset;
if (tim_offset < 0) {
tim_sgn = 1;
tim_offset = -tim_offset;
} else
tim_sgn = 0;
comp1 = (u32)tim_offset * (u32)timf_lsb ;
comp2 = (u32)tim_offset * (u32)timf_msb ;
comp = ((comp1 >> 16) + comp2) >> 7;
if (tim_sgn == 0)
comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp;
else
comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ;
timf_msb = (comp >> 16) & 0xff;
timf_lsb = comp & 0xffff;
wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb);
wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb);
return 0;
}
static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost)
{
if (boost) {
wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON);
} else {
wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF);
}
switch (bw) {
case BANDWIDTH_8_MHZ:
wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
break;
case BANDWIDTH_7_MHZ:
wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz);
break;
case BANDWIDTH_6_MHZ:
wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz);
break;
/* case BANDWIDTH_5_MHZ:
wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz);
break;*/
case BANDWIDTH_AUTO:
return -EOPNOTSUPP;
default:
err("unknown bandwidth value (%d).",bw);
return -EINVAL;
}
if (boost) {
u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) +
rd(DIB3000MC_REG_BW_TIMOUT_LSB);
timeout *= 85; timeout >>= 7;
wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff);
wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff);
}
return 0;
}
static int dib3000mc_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep);
static int dib3000mc_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep, int tuner)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
fe_code_rate_t fe_cr = FEC_NONE;
int search_state, seq;
u16 val;
u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0;
if (tuner) {
wr(DIB3000MC_REG_TUNER,
DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
state->config.pll_set(fe, fep);
wr(DIB3000MC_REG_TUNER,
DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
}
dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth);
dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0);
wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC);
wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
/* Default cfg isi offset adp */
wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]);
wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT);
wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]);
wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133);
wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
if (ofdm->bandwidth == BANDWIDTH_8_MHZ) {
wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]);
} else {
wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]);
}
switch (ofdm->transmission_mode) {
case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break;
case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break;
case TRANSMISSION_MODE_AUTO: break;
default: return -EINVAL;
}
switch (ofdm->guard_interval) {
case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break;
case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break;
case GUARD_INTERVAL_1_8: guard = DIB3000_GUARD_TIME_1_8; break;
case GUARD_INTERVAL_1_4: guard = DIB3000_GUARD_TIME_1_4; break;
case GUARD_INTERVAL_AUTO: break;
default: return -EINVAL;
}
switch (ofdm->constellation) {
case QPSK: qam = DIB3000_CONSTELLATION_QPSK; break;
case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break;
case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break;
case QAM_AUTO: break;
default: return -EINVAL;
}
switch (ofdm->hierarchy_information) {
case HIERARCHY_NONE: /* fall through */
case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break;
case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break;
case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break;
case HIERARCHY_AUTO: break;
default: return -EINVAL;
}
if (ofdm->hierarchy_information == HIERARCHY_NONE) {
hrch = DIB3000_HRCH_OFF;
sel_hp = DIB3000_SELECT_HP;
fe_cr = ofdm->code_rate_HP;
} else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
hrch = DIB3000_HRCH_ON;
sel_hp = DIB3000_SELECT_LP;
fe_cr = ofdm->code_rate_LP;
}
switch (fe_cr) {
case FEC_1_2: cr = DIB3000_FEC_1_2; break;
case FEC_2_3: cr = DIB3000_FEC_2_3; break;
case FEC_3_4: cr = DIB3000_FEC_3_4; break;
case FEC_5_6: cr = DIB3000_FEC_5_6; break;
case FEC_7_8: cr = DIB3000_FEC_7_8; break;
case FEC_NONE: break;
case FEC_AUTO: break;
default: return -EINVAL;
}
wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft));
wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch));
switch (fep->inversion) {
case INVERSION_OFF:
wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
break;
case INVERSION_AUTO:
break;
case INVERSION_ON:
wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON);
break;
default:
return -EINVAL;
}
seq = dib3000_seq
[ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
[ofdm->guard_interval == GUARD_INTERVAL_AUTO]
[fep->inversion == INVERSION_AUTO];
deb_setf("seq? %d\n", seq);
wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1));
dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
val = rd(DIB3000MC_REG_DEMOD_PARM);
wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON);
wr(DIB3000MC_REG_DEMOD_PARM,val);
msleep(70);
wr_foreach(dib3000mc_reg_agc_bandwidth, dib3000mc_agc_bandwidth);
/* something has to be auto searched */
if (ofdm->constellation == QAM_AUTO ||
ofdm->hierarchy_information == HIERARCHY_AUTO ||
ofdm->guard_interval == GUARD_INTERVAL_AUTO ||
ofdm->transmission_mode == TRANSMISSION_MODE_AUTO ||
fe_cr == FEC_AUTO ||
fep->inversion == INVERSION_AUTO
) {
int as_count=0;
deb_setf("autosearch enabled.\n");
val = rd(DIB3000MC_REG_DEMOD_PARM);
wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
wr(DIB3000MC_REG_DEMOD_PARM,val);
while ((search_state = dib3000_search_status(
rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100)
msleep(10);
deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
if (search_state == 1) {
struct dvb_frontend_parameters feps;
feps.u.ofdm.bandwidth = ofdm->bandwidth; /* bw is not auto searched */;
if (dib3000mc_get_frontend(fe, &feps) == 0) {
deb_setf("reading tuning data from frontend succeeded.\n");
return dib3000mc_set_frontend(fe, &feps, 0);
}
}
} else {
wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[qam]);
/* set_offset_cfg */
wr_foreach(dib3000mc_reg_offset,
dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
// dib3000mc_set_timing(1,ofdm->transmission_mode,ofdm->bandwidth);
// wr(DIB3000MC_REG_LOCK_MASK,DIB3000MC_ACTIVATE_LOCK_MASK); /* activates some locks if needed */
/* set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF);
wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_ON);
wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_OFF);*/
}
return 0;
}
static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
state->timing_offset = 0;
state->timing_offset_comp_done = 0;
wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK);
wr(DIB3000MC_REG_RST_I2C_ADDR,
DIB3000MC_DEMOD_ADDR(state->config.demod_address) |
DIB3000MC_DEMOD_ADDR_ON);
wr(DIB3000MC_REG_RST_I2C_ADDR,
DIB3000MC_DEMOD_ADDR(state->config.demod_address));
wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG);
wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP);
wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE);
wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP);
wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT);
wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF);
wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19);
wr(33,5);
wr(36,81);
wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);
wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99);
wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */
/* mobile mode - portable reception */
wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]);
/* TUNER_PANASONIC_ENV57H12D5: */
wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general);
wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]);
wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110);
wr(26,0x6680);
wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1);
wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2);
wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3);
wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT);
wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4);
wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB);
dib3000mc_set_timing(state,0,TRANSMISSION_MODE_2K,BANDWIDTH_8_MHZ);
// wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120);
wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134);
wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG);
dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
/* output mode control, just the MPEG2_SLAVE */
set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE);
wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE);
wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE);
/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
wr(DIB3000MC_REG_OUTMODE,
DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
rd(DIB3000MC_REG_OUTMODE)));
wr(DIB3000MC_REG_SMO_MODE,
DIB3000MC_SMO_MODE_DEFAULT |
DIB3000MC_SMO_MODE_188);
wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
*/
/* diversity */
wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT);
wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT);
wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
/* if (state->config->pll_init) {
wr(DIB3000MC_REG_TUNER,
DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr));
state->config->pll_init(fe);
wr(DIB3000MC_REG_TUNER,
DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr));
}*/
return 0;
}
static int dib3000mc_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
fe_code_rate_t *cr;
u16 tps_val,cr_val;
int inv_test1,inv_test2;
u32 dds_val, threshold = 0x1000000;
if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507))
return 0;
dds_val = ((rd(DIB3000MC_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB);
if (dds_val < threshold)
inv_test1 = 0;
else if (dds_val == threshold)
inv_test1 = 1;
else
inv_test1 = 2;
dds_val = ((rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_SET_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)) ?
INVERSION_ON : INVERSION_OFF;
deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
tps_val = rd(DIB3000MC_REG_TUNING_PARM);
switch (DIB3000MC_TP_QAM(tps_val)) {
case DIB3000_CONSTELLATION_QPSK:
deb_getf("QPSK ");
ofdm->constellation = QPSK;
break;
case DIB3000_CONSTELLATION_16QAM:
deb_getf("QAM16 ");
ofdm->constellation = QAM_16;
break;
case DIB3000_CONSTELLATION_64QAM:
deb_getf("QAM64 ");
ofdm->constellation = QAM_64;
break;
default:
err("Unexpected constellation returned by TPS (%d)", tps_val);
break;
}
if (DIB3000MC_TP_HRCH(tps_val)) {
deb_getf("HRCH ON ");
cr = &ofdm->code_rate_LP;
ofdm->code_rate_HP = FEC_NONE;
switch (DIB3000MC_TP_ALPHA(tps_val)) {
case DIB3000_ALPHA_0:
deb_getf("HIERARCHY_NONE ");
ofdm->hierarchy_information = HIERARCHY_NONE;
break;
case DIB3000_ALPHA_1:
deb_getf("HIERARCHY_1 ");
ofdm->hierarchy_information = HIERARCHY_1;
break;
case DIB3000_ALPHA_2:
deb_getf("HIERARCHY_2 ");
ofdm->hierarchy_information = HIERARCHY_2;
break;
case DIB3000_ALPHA_4:
deb_getf("HIERARCHY_4 ");
ofdm->hierarchy_information = HIERARCHY_4;
break;
default:
err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
break;
}
cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val);
} else {
deb_getf("HRCH OFF ");
cr = &ofdm->code_rate_HP;
ofdm->code_rate_LP = FEC_NONE;
ofdm->hierarchy_information = HIERARCHY_NONE;
cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val);
}
switch (cr_val) {
case DIB3000_FEC_1_2:
deb_getf("FEC_1_2 ");
*cr = FEC_1_2;
break;
case DIB3000_FEC_2_3:
deb_getf("FEC_2_3 ");
*cr = FEC_2_3;
break;
case DIB3000_FEC_3_4:
deb_getf("FEC_3_4 ");
*cr = FEC_3_4;
break;
case DIB3000_FEC_5_6:
deb_getf("FEC_5_6 ");
*cr = FEC_4_5;
break;
case DIB3000_FEC_7_8:
deb_getf("FEC_7_8 ");
*cr = FEC_7_8;
break;
default:
err("Unexpected FEC returned by TPS (%d)", tps_val);
break;
}
switch (DIB3000MC_TP_GUARD(tps_val)) {
case DIB3000_GUARD_TIME_1_32:
deb_getf("GUARD_INTERVAL_1_32 ");
ofdm->guard_interval = GUARD_INTERVAL_1_32;
break;
case DIB3000_GUARD_TIME_1_16:
deb_getf("GUARD_INTERVAL_1_16 ");
ofdm->guard_interval = GUARD_INTERVAL_1_16;
break;
case DIB3000_GUARD_TIME_1_8:
deb_getf("GUARD_INTERVAL_1_8 ");
ofdm->guard_interval = GUARD_INTERVAL_1_8;
break;
case DIB3000_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;
}
switch (DIB3000MC_TP_FFT(tps_val)) {
case DIB3000_TRANSMISSION_MODE_2K:
deb_getf("TRANSMISSION_MODE_2K ");
ofdm->transmission_mode = TRANSMISSION_MODE_2K;
break;
case DIB3000_TRANSMISSION_MODE_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;
}
return 0;
}
static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
u16 lock = rd(DIB3000MC_REG_LOCKING);
*stat = 0;
if (DIB3000MC_AGC_LOCK(lock))
*stat |= FE_HAS_SIGNAL;
if (DIB3000MC_CARRIER_LOCK(lock))
*stat |= FE_HAS_CARRIER;
if (DIB3000MC_TPS_LOCK(lock)) /* VIT_LOCK ? */
*stat |= FE_HAS_VITERBI;
if (DIB3000MC_MPEG_SYNC_LOCK(lock))
*stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
deb_info("actual status is %2x\n",*stat);
return 0;
}
static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
*ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB));
return 0;
}
static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
*unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT);
return 0;
}
/* see dib3000mb.c for calculation comments */
static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
*strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
deb_info("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff);
return 0;
}
/* see dib3000mb.c for calculation comments */
static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB),
val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
u16 sig,noise;
sig = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3);
if (noise == 0)
*snr = 0xffff;
else
*snr = (u16) sig/noise;
deb_info("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff);
deb_info("noise: mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff);
deb_info("snr: %d\n",*snr);
return 0;
}
static int dib3000mc_sleep(struct dvb_frontend* fe)
{
struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN);
wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN);
wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN);
wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN);
return 0;
}
static int dib3000mc_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;
return 0;
}
static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe)
{
return dib3000mc_fe_init(fe, 0);
}
static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
{
return dib3000mc_set_frontend(fe, fep, 1);
}
static void dib3000mc_release(struct dvb_frontend* fe)
{
struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
dib3000_dealloc_pid_list(state);
kfree(state);
}
/* pid filter and transfer stuff */
static int dib3000mc_pid_control(struct dvb_frontend *fe,int pid,int onoff)
{
struct dib3000_state *state = fe->demodulator_priv;
int index = dib3000_get_pid_index(state->pid_list, DIB3000MC_NUM_PIDS, pid, &state->pid_list_lock,onoff);
pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
if (index >= 0) {
wr(index+DIB3000MC_REG_FIRST_PID,pid);
} else {
err("no more pids for filtering.");
return -ENOMEM;
}
return 0;
}
static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff)
{
struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
deb_xfer("%s fifo",onoff ? "enabling" : "disabling");
if (onoff) {
wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
} else {
wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
}
return 0;
}
static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
{
struct dib3000_state *state = fe->demodulator_priv;
u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
deb_xfer("%s pid parsing",onoff ? "enabling" : "disabling");
if (onoff) {
wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
} else {
wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
}
return 0;
}
static struct dvb_frontend_ops dib3000mc_ops;
struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops)
{
struct dib3000_state* state = NULL;
u16 devid;
/* allocate memory for the internal state */
state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
if (state == NULL)
goto error;
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
goto error;
devid = rd(DIB3000_REG_DEVICE_ID);
if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID)
goto error;
switch (devid) {
case DIB3000MC_DEVICE_ID:
info("Found a DiBcom 3000-MC.");
break;
case DIB3000P_DEVICE_ID:
info("Found a DiBcom 3000-P.");
break;
}
if (dib3000_init_pid_list(state,DIB3000MC_NUM_PIDS))
goto error;
/* create dvb_frontend */
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
/* set the xfer operations */
xfer_ops->pid_parse = dib3000mc_pid_parse;
xfer_ops->fifo_ctrl = dib3000mc_fifo_control;
xfer_ops->pid_ctrl = dib3000mc_pid_control;
return &state->frontend;
error:
if (state)
kfree(state);
return NULL;
}
static struct dvb_frontend_ops dib3000mc_ops = {
.info = {
.name = "DiBcom 3000-MC/P 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 = dib3000mc_release,
.init = dib3000mc_fe_init_nonmobile,
.sleep = dib3000mc_sleep,
.set_frontend = dib3000mc_set_frontend_and_tuner,
.get_frontend = dib3000mc_get_frontend,
.get_tune_settings = dib3000mc_fe_get_tune_settings,
.read_status = dib3000mc_read_status,
.read_ber = dib3000mc_read_ber,
.read_signal_strength = dib3000mc_read_signal_strength,
.read_snr = dib3000mc_read_snr,
.read_ucblocks = dib3000mc_read_unc_blocks,
};
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(dib3000mc_attach);
/*
* dib3000mc_priv.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.
*
* for more information see dib3000mc.c .
*/
#ifndef __DIB3000MC_PRIV_H__
#define __DIB3000MC_PRIV_H__
/* 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)
// defines the phase noise algorithm to be used (O:Inhib, 1:CPE on)
#define DEF_PHASE_NOISE_MODE 0
// define Mobille algorithms
#define DEF_MOBILE_MODE Auto_Reception
// defines the tuner type
#define DEF_TUNER_TYPE TUNER_PANASONIC_ENV57H13D5
// defines the impule noise algorithm to be used
#define DEF_IMPULSE_NOISE_MODE 0
// defines the MPEG2 data output format
#define DEF_MPEG2_OUTPUT_188 0
// defines the MPEG2 data output format
#define DEF_OUTPUT_MODE MPEG2_PARALLEL_CONTINUOUS_CLOCK
/*
* Demodulator parameters
* reg: 0 1 1 1 11 11 111
* | | | | | |
* | | | | | +-- alpha (000=0, 001=1, 010=2, 100=4)
* | | | | +----- constellation (00=QPSK, 01=16QAM, 10=64QAM)
* | | | +-------- guard (00=1/32, 01=1/16, 10=1/8, 11=1/4)
* | | +----------- transmission mode (0=2k, 1=8k)
* | |
* | +-------------- restart autosearch for parameters
* +---------------- restart the demodulator
* reg: 181 1 111 1
* | | |
* | | +- FEC applies for HP or LP (0=LP, 1=HP)
* | +---- FEC rate (001=1/2, 010=2/3, 011=3/4, 101=5/6, 111=7/8)
* +------- hierarchy on (0=no, 1=yes)
*/
/* demodulator tuning parameter and restart options */
#define DIB3000MC_REG_DEMOD_PARM ( 0)
#define DIB3000MC_DEMOD_PARM(a,c,g,t) ( \
(0x7 & a) | \
((0x3 & c) << 3) | \
((0x3 & g) << 5) | \
((0x1 & t) << 7) )
#define DIB3000MC_DEMOD_RST_AUTO_SRCH_ON (1 << 8)
#define DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF (0 << 8)
#define DIB3000MC_DEMOD_RST_DEMOD_ON (1 << 9)
#define DIB3000MC_DEMOD_RST_DEMOD_OFF (0 << 9)
/* register for hierarchy parameters */
#define DIB3000MC_REG_HRCH_PARM ( 181)
#define DIB3000MC_HRCH_PARM(s,f,h) ( \
(0x1 & s) | \
((0x7 & f) << 1) | \
((0x1 & h) << 4) )
/* timeout ??? */
#define DIB3000MC_REG_UNK_1 ( 1)
#define DIB3000MC_UNK_1 ( 0x04)
/* timeout ??? */
#define DIB3000MC_REG_UNK_2 ( 2)
#define DIB3000MC_UNK_2 ( 0x04)
/* timeout ??? */
#define DIB3000MC_REG_UNK_3 ( 3)
#define DIB3000MC_UNK_3 (0x1000)
#define DIB3000MC_REG_UNK_4 ( 4)
#define DIB3000MC_UNK_4 (0x0814)
/* timeout ??? */
#define DIB3000MC_REG_SEQ_TPS ( 5)
#define DIB3000MC_SEQ_TPS_DEFAULT ( 1)
#define DIB3000MC_SEQ_TPS(s,t) ( \
((s & 0x0f) << 4) | \
((t & 0x01) << 8) )
#define DIB3000MC_IS_TPS(v) ((v << 8) & 0x1)
#define DIB3000MC_IS_AS(v) ((v >> 4) & 0xf)
/* parameters for the bandwidth */
#define DIB3000MC_REG_BW_TIMOUT_MSB ( 6)
#define DIB3000MC_REG_BW_TIMOUT_LSB ( 7)
static u16 dib3000mc_reg_bandwidth[] = { 6,7,8,9,10,11,16,17 };
/*static u16 dib3000mc_bandwidth_5mhz[] =
{ 0x28, 0x9380, 0x87, 0x4100, 0x2a4, 0x4500, 0x1, 0xb0d0 };*/
static u16 dib3000mc_bandwidth_6mhz[] =
{ 0x21, 0xd040, 0x70, 0xb62b, 0x233, 0x8ed5, 0x1, 0xb0d0 };
static u16 dib3000mc_bandwidth_7mhz[] =
{ 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 };
static u16 dib3000mc_bandwidth_8mhz[] =
{ 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0b0 };
static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 };
static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 };
/* lock mask */
#define DIB3000MC_REG_LOCK_MASK ( 15)
#define DIB3000MC_ACTIVATE_LOCK_MASK (0x0800)
/* reset the uncorrected packet count (??? do it 5 times) */
#define DIB3000MC_REG_RST_UNC ( 18)
#define DIB3000MC_RST_UNC_ON ( 1)
#define DIB3000MC_RST_UNC_OFF ( 0)
#define DIB3000MC_REG_UNK_19 ( 19)
#define DIB3000MC_UNK_19 ( 0)
/* DDS frequency value (IF position) and inversion bit */
#define DIB3000MC_REG_INVERSION ( 21)
#define DIB3000MC_REG_SET_DDS_FREQ_MSB ( 21)
#define DIB3000MC_DDS_FREQ_MSB_INV_OFF (0x0164)
#define DIB3000MC_DDS_FREQ_MSB_INV_ON (0x0364)
#define DIB3000MC_REG_SET_DDS_FREQ_LSB ( 22)
#define DIB3000MC_DDS_FREQ_LSB (0x463d)
/* timing frequencies setting */
#define DIB3000MC_REG_TIMING_FREQ_MSB ( 23)
#define DIB3000MC_REG_TIMING_FREQ_LSB ( 24)
#define DIB3000MC_CLOCK_REF (0x151fd1)
//static u16 dib3000mc_reg_timing_freq[] = { 23,24 };
//static u16 dib3000mc_timing_freq[][2] = {
// { 0x69, 0x9f18 }, /* 5 MHz */
// { 0x7e ,0xbee9 }, /* 6 MHz */
// { 0x93 ,0xdebb }, /* 7 MHz */
// { 0xa8 ,0xfe8c }, /* 8 MHz */
//};
/* timeout ??? */
static u16 dib3000mc_reg_offset[] = { 26,33 };
static u16 dib3000mc_offset[][2] = {
{ 26240, 5 }, /* default */
{ 30336, 6 }, /* 8K */
{ 38528, 8 }, /* 2K */
};
#define DIB3000MC_REG_ISI ( 29)
#define DIB3000MC_ISI_DEFAULT (0x1073)
#define DIB3000MC_ISI_ACTIVATE (0x0000)
#define DIB3000MC_ISI_INHIBIT (0x0200)
/* impulse noise control */
static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 };
static u16 dib3000mc_imp_noise_ctl[][2] = {
{ 0x1294, 0xfff8 }, /* mode 0 */
{ 0x1294, 0xfff8 }, /* mode 1 */
{ 0x1294, 0xfff8 }, /* mode 2 */
{ 0x1294, 0xfff8 }, /* mode 3 */
{ 0x1294, 0xfff8 }, /* mode 4 */
};
/* AGC registers */
static u16 dib3000mc_reg_agc[] = {
36,37,38,39,42,43,44,45,46,47,48,49
};
static u16 dib3000mc_agc_tuner[][12] = {
{ 0x0051, 0x301d, 0x0000, 0x1cc7, 0xcf5c, 0x6666,
0xbae1, 0xa148, 0x3b5e, 0x3c1c, 0x001a, 0x2019
}, /* TUNER_PANASONIC_ENV77H04D5, */
{ 0x0051, 0x301d, 0x0000, 0x1cc7, 0xdc29, 0x570a,
0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0x000a, 0x951e
}, /* TUNER_PANASONIC_ENV57H13D5, TUNER_PANASONIC_ENV57H12D5 */
{ 0x0051, 0x301d, 0x0000, 0x1cc7, 0xffff, 0xffff,
0xffff, 0x0000, 0xfdfd, 0x4040, 0x00fd, 0x4040
}, /* TUNER_SAMSUNG_DTOS333IH102, TUNER_RFAGCIN_UNKNOWN */
{ 0x0196, 0x301d, 0x0000, 0x1cc7, 0xbd71, 0x5c29,
0xb5c3, 0x6148, 0x6569, 0x5127, 0x0033, 0x3537
}, /* TUNER_PROVIDER_X */
/* TODO TUNER_PANASONIC_ENV57H10D8, TUNER_PANASONIC_ENV57H11D8 */
};
/* AGC loop bandwidth */
static u16 dib3000mc_reg_agc_bandwidth[] = { 40,41 };
static u16 dib3000mc_agc_bandwidth[] = { 0x119,0x330 };
static u16 dib3000mc_reg_agc_bandwidth_general[] = { 50,51,52,53,54 };
static u16 dib3000mc_agc_bandwidth_general[] =
{ 0x8000, 0x91ca, 0x01ba, 0x0087, 0x0087 };
#define DIB3000MC_REG_IMP_NOISE_55 ( 55)
#define DIB3000MC_IMP_NEW_ALGO(w) (w | (1<<10))
/* Impulse noise params */
static u16 dib3000mc_reg_impulse_noise[] = { 55,56,57 };
static u16 dib3000mc_impluse_noise[][3] = {
{ 0x489, 0x89, 0x72 }, /* 5 MHz */
{ 0x4a5, 0xa5, 0x89 }, /* 6 MHz */
{ 0x4c0, 0xc0, 0xa0 }, /* 7 MHz */
{ 0x4db, 0xdb, 0xb7 }, /* 8 Mhz */
};
static u16 dib3000mc_reg_fft[] = {
58,59,60,61,62,63,64,65,66,67,68,69,
70,71,72,73,74,75,76,77,78,79,80,81,
82,83,84,85,86
};
static u16 dib3000mc_fft_modes[][29] = {
{ 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0, 0xd
}, /* fft mode 0 */
{ 0x3b, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
0x3ffe, 0x5b3, 0x3feb, 0x0, 0x8200, 0xd
}, /* fft mode 1 */
};
#define DIB3000MC_REG_UNK_88 ( 88)
#define DIB3000MC_UNK_88 (0x0410)
static u16 dib3000mc_reg_bw[] = { 93,94,95,96,97,98 };
static u16 dib3000mc_bw[][6] = {
{ 0,0,0,0,0,0 }, /* 5 MHz */
{ 0,0,0,0,0,0 }, /* 6 MHz */
{ 0,0,0,0,0,0 }, /* 7 MHz */
{ 0x20, 0x21, 0x20, 0x23, 0x20, 0x27 }, /* 8 MHz */
};
/* phase noise control */
#define DIB3000MC_REG_UNK_99 ( 99)
#define DIB3000MC_UNK_99 (0x0220)
#define DIB3000MC_REG_SCAN_BOOST ( 100)
#define DIB3000MC_SCAN_BOOST_ON ((11 << 6) + 6)
#define DIB3000MC_SCAN_BOOST_OFF ((16 << 6) + 9)
/* timeout ??? */
#define DIB3000MC_REG_UNK_110 ( 110)
#define DIB3000MC_UNK_110 ( 3277)
#define DIB3000MC_REG_UNK_111 ( 111)
#define DIB3000MC_UNK_111_PH_N_MODE_0 ( 0)
#define DIB3000MC_UNK_111_PH_N_MODE_1 (1 << 1)
/* superious rm config */
#define DIB3000MC_REG_UNK_120 ( 120)
#define DIB3000MC_UNK_120 ( 8207)
#define DIB3000MC_REG_UNK_133 ( 133)
#define DIB3000MC_UNK_133 ( 15564)
#define DIB3000MC_REG_UNK_134 ( 134)
#define DIB3000MC_UNK_134 ( 0)
/* adapter config for constellation */
static u16 dib3000mc_reg_adp_cfg[] = { 129, 130, 131, 132 };
static u16 dib3000mc_adp_cfg[][4] = {
{ 0x99a, 0x7fae, 0x333, 0x7ff0 }, /* QPSK */
{ 0x23d, 0x7fdf, 0x0a4, 0x7ff0 }, /* 16-QAM */
{ 0x148, 0x7ff0, 0x0a4, 0x7ff8 }, /* 64-QAM */
};
static u16 dib3000mc_reg_mobile_mode[] = { 139, 140, 141, 175, 1032 };
static u16 dib3000mc_mobile_mode[][5] = {
{ 0x01, 0x0, 0x0, 0x00, 0x12c }, /* fixed */
{ 0x01, 0x0, 0x0, 0x00, 0x12c }, /* portable */
{ 0x00, 0x0, 0x0, 0x02, 0x000 }, /* mobile */
{ 0x00, 0x0, 0x0, 0x02, 0x000 }, /* auto */
};
#define DIB3000MC_REG_DIVERSITY1 ( 177)
#define DIB3000MC_DIVERSITY1_DEFAULT ( 1)
#define DIB3000MC_REG_DIVERSITY2 ( 178)
#define DIB3000MC_DIVERSITY2_DEFAULT ( 1)
#define DIB3000MC_REG_DIVERSITY3 ( 180)
#define DIB3000MC_DIVERSITY3_IN_OFF (0xfff0)
#define DIB3000MC_DIVERSITY3_IN_ON (0xfff6)
#define DIB3000MC_REG_FEC_CFG ( 195)
#define DIB3000MC_FEC_CFG ( 0x10)
#define DIB3000MC_REG_SMO_MODE ( 206)
#define DIB3000MC_SMO_MODE_DEFAULT (1 << 2)
#define DIB3000MC_SMO_MODE_FIFO_FLUSH (1 << 3)
#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH ~DIB3000MC_SMO_MODE_FIFO_FLUSH
#define DIB3000MC_SMO_MODE_PID_PARSE (1 << 4)
#define DIB3000MC_SMO_MODE_NO_PID_PARSE ~DIB3000MC_SMO_MODE_PID_PARSE
#define DIB3000MC_SMO_MODE_188 (1 << 5)
#define DIB3000MC_SMO_MODE_SLAVE (DIB3000MC_SMO_MODE_DEFAULT | \
DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1))
#define DIB3000MC_REG_FIFO_THRESHOLD ( 207)
#define DIB3000MC_FIFO_THRESHOLD_DEFAULT ( 1792)
#define DIB3000MC_FIFO_THRESHOLD_SLAVE ( 512)
/*
* pidfilter
* it is not a hardware pidfilter but a filter which drops all pids
* except the ones set. When connected to USB1.1 bandwidth this is important.
* DiB3000-MC/P can filter up to 32 PIDs
*/
#define DIB3000MC_REG_FIRST_PID ( 212)
#define DIB3000MC_NUM_PIDS ( 32)
#define DIB3000MC_REG_OUTMODE ( 244)
#define DIB3000MC_OM_PARALLEL_GATED_CLK ( 0)
#define DIB3000MC_OM_PAR_CONT_CLK (1 << 11)
#define DIB3000MC_OM_SERIAL (2 << 11)
#define DIB3000MC_OM_DIVOUT_ON (4 << 11)
#define DIB3000MC_OM_SLAVE (DIB3000MC_OM_DIVOUT_ON | DIB3000MC_OM_PAR_CONT_CLK)
#define DIB3000MC_REG_RF_POWER ( 392)
#define DIB3000MC_REG_FFT_POSITION ( 407)
#define DIB3000MC_REG_DDS_FREQ_MSB ( 414)
#define DIB3000MC_REG_DDS_FREQ_LSB ( 415)
#define DIB3000MC_REG_TIMING_OFFS_MSB ( 416)
#define DIB3000MC_REG_TIMING_OFFS_LSB ( 417)
#define DIB3000MC_REG_TUNING_PARM ( 458)
#define DIB3000MC_TP_QAM(v) ((v >> 13) & 0x03)
#define DIB3000MC_TP_HRCH(v) ((v >> 12) & 0x01)
#define DIB3000MC_TP_ALPHA(v) ((v >> 9) & 0x07)
#define DIB3000MC_TP_FFT(v) ((v >> 8) & 0x01)
#define DIB3000MC_TP_FEC_CR_HP(v) ((v >> 5) & 0x07)
#define DIB3000MC_TP_FEC_CR_LP(v) ((v >> 2) & 0x07)
#define DIB3000MC_TP_GUARD(v) (v & 0x03)
#define DIB3000MC_REG_SIGNAL_NOISE_MSB ( 483)
#define DIB3000MC_REG_SIGNAL_NOISE_LSB ( 484)
#define DIB3000MC_REG_MER ( 485)
#define DIB3000MC_REG_BER_MSB ( 500)
#define DIB3000MC_REG_BER_LSB ( 501)
#define DIB3000MC_REG_PACKET_ERRORS ( 503)
#define DIB3000MC_REG_PACKET_ERROR_COUNT ( 506)
#define DIB3000MC_REG_LOCK_507 ( 507)
#define DIB3000MC_LOCK_507 (0x0002) // ? name correct ?
#define DIB3000MC_REG_LOCKING ( 509)
#define DIB3000MC_AGC_LOCK(v) (v & 0x8000)
#define DIB3000MC_CARRIER_LOCK(v) (v & 0x2000)
#define DIB3000MC_MPEG_SYNC_LOCK(v) (v & 0x0080)
#define DIB3000MC_MPEG_DATA_LOCK(v) (v & 0x0040)
#define DIB3000MC_TPS_LOCK(v) (v & 0x0004)
#define DIB3000MC_REG_AS_IRQ ( 511)
#define DIB3000MC_AS_IRQ_SUCCESS (1 << 1)
#define DIB3000MC_AS_IRQ_FAIL ( 1)
#define DIB3000MC_REG_TUNER ( 769)
#define DIB3000MC_REG_RST_I2C_ADDR ( 1024)
#define DIB3000MC_DEMOD_ADDR_ON ( 1)
#define DIB3000MC_DEMOD_ADDR(a) ((a << 3) & 0x03F0)
#define DIB3000MC_REG_RESTART ( 1027)
#define DIB3000MC_RESTART_OFF (0x0000)
#define DIB3000MC_RESTART_AGC (0x0800)
#define DIB3000MC_RESTART_CONFIG (0x8000)
#define DIB3000MC_REG_RESTART_VIT ( 1028)
#define DIB3000MC_RESTART_VIT_OFF ( 0)
#define DIB3000MC_RESTART_VIT_ON ( 1)
#define DIB3000MC_REG_CLK_CFG_1 ( 1031)
#define DIB3000MC_CLK_CFG_1_POWER_UP ( 0)
#define DIB3000MC_CLK_CFG_1_POWER_DOWN (0xffff)
#define DIB3000MC_REG_CLK_CFG_2 ( 1032)
#define DIB3000MC_CLK_CFG_2_PUP_FIXED (0x012c)
#define DIB3000MC_CLK_CFG_2_PUP_PORT (0x0104)
#define DIB3000MC_CLK_CFG_2_PUP_MOBILE (0x0000)
#define DIB3000MC_CLK_CFG_2_POWER_DOWN (0xffff)
#define DIB3000MC_REG_CLK_CFG_3 ( 1033)
#define DIB3000MC_CLK_CFG_3_POWER_UP ( 0)
#define DIB3000MC_CLK_CFG_3_POWER_DOWN (0xfff5)
#define DIB3000MC_REG_CLK_CFG_7 ( 1037)
#define DIB3000MC_CLK_CFG_7_INIT ( 12592)
#define DIB3000MC_CLK_CFG_7_POWER_UP (~0x0003)
#define DIB3000MC_CLK_CFG_7_PWR_DOWN (0x0003)
#define DIB3000MC_CLK_CFG_7_DIV_IN_OFF (1 << 8)
/* was commented out ??? */
#define DIB3000MC_REG_CLK_CFG_8 ( 1038)
#define DIB3000MC_CLK_CFG_8_POWER_UP (0x160c)
#define DIB3000MC_REG_CLK_CFG_9 ( 1039)
#define DIB3000MC_CLK_CFG_9_POWER_UP ( 0)
/* also clock ??? */
#define DIB3000MC_REG_ELEC_OUT ( 1040)
#define DIB3000MC_ELEC_OUT_HIGH_Z ( 0)
#define DIB3000MC_ELEC_OUT_DIV_OUT_ON ( 1)
#define DIB3000MC_ELEC_OUT_SLAVE ( 3)
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment