summaryrefslogtreecommitdiff
path: root/linux/drivers/media
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-08-03 18:42:33 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-08-03 18:42:33 -0300
commit2c888a66d88e5aefc1bdb302c7cd7323b63e389f (patch)
tree75348f946cc95400e870fbd29d38d6311fe32359 /linux/drivers/media
parent33c78c13eddb4c4a04755bd86526fc21536a3c8b (diff)
parent4ff0e90195667bad0ed6a181d045fb8d71f7d053 (diff)
downloadmediapointer-dvb-s2-2c888a66d88e5aefc1bdb302c7cd7323b63e389f.tar.gz
mediapointer-dvb-s2-2c888a66d88e5aefc1bdb302c7cd7323b63e389f.tar.bz2
merge: http://linuxtv.org/hg/~tap/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@infradead.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'linux/drivers/media')
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c2
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Kconfig1
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dib0700.h1
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dib0700_core.c21
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dib0700_devices.c526
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h12
-rw-r--r--linux/drivers/media/dvb/frontends/Kconfig9
-rw-r--r--linux/drivers/media/dvb/frontends/Makefile1
-rw-r--r--linux/drivers/media/dvb/frontends/dib0070.c595
-rw-r--r--linux/drivers/media/dvb/frontends/dib0070.h44
-rw-r--r--linux/drivers/media/dvb/frontends/dib3000mc.c216
-rw-r--r--linux/drivers/media/dvb/frontends/dib7000m.c743
-rw-r--r--linux/drivers/media/dvb/frontends/dib7000p.c913
-rw-r--r--linux/drivers/media/dvb/frontends/dib7000p.h14
-rw-r--r--linux/drivers/media/dvb/frontends/dibx000_common.h57
-rw-r--r--linux/drivers/media/dvb/frontends/mt2266.c4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.h7
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-fb.c43
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-ioctl.c3
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-irq.c22
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-yuv.c33
21 files changed, 2463 insertions, 804 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index a05f4267a..e39820d23 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -753,7 +753,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
dprintk ("%s\n", __FUNCTION__);
- if (!fe || fepriv->exit)
+ if (fepriv->exit)
return -ENODEV;
if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig
index dec03ee32..d73934dd4 100644
--- a/linux/drivers/media/dvb/dvb-usb/Kconfig
+++ b/linux/drivers/media/dvb/dvb-usb/Kconfig
@@ -75,6 +75,7 @@ config DVB_USB_DIB0700
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_DIB0070
help
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
USB bridge is also present in devices having the DiB7700 DVB-T-USB
diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700.h b/linux/drivers/media/dvb/dvb-usb/dib0700.h
index 74ae6c240..4a903ea95 100644
--- a/linux/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/linux/drivers/media/dvb/dvb-usb/dib0700.h
@@ -30,6 +30,7 @@ extern int dvb_usb_dib0700_debug;
// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
// 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " )
+#define REQUEST_SET_RC 0x11
#define REQUEST_GET_VERSION 0x15
struct dib0700_state {
diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c
index 57327ed9f..cab743531 100644
--- a/linux/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/linux/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,6 +13,10 @@ int dvb_usb_dib0700_debug;
module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
+static int dvb_usb_dib0700_ir_proto = 1;
+module_param(dvb_usb_dib0700_ir_proto, int, 0644);
+MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
+
/* expecting rx buffer: request data[0] data[1] ... data[2] */
static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
{
@@ -260,10 +264,22 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return dib0700_ctrl_wr(adap->dev, b, 4);
}
+static int dib0700_rc_setup(struct dvb_usb_device *d)
+{
+ u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
+ int i = dib0700_ctrl_wr(d, rc_setup, 3);
+ if (i<0) {
+ err("ir protocol setup failed");
+ return -1;
+ }
+ return 0;
+}
+
static int dib0700_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
int i;
+ struct dvb_usb_device *dev;
#if 0
struct usb_device *udev = interface_to_usbdev(intf);
@@ -276,8 +292,11 @@ static int dib0700_probe(struct usb_interface *intf,
#endif
for (i = 0; i < dib0700_device_count; i++)
- if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0)
+ if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0)
+ {
+ dib0700_rc_setup(dev);
return 0;
+ }
return -ENODEV;
}
diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 122d9d4b4..4a3c5467d 100644
--- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -4,7 +4,7 @@
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
- * Copyright (C) 2005-6 DiBcom, SA
+ * Copyright (C) 2005-7 DiBcom, SA
*/
#include "dib0700.h"
@@ -13,13 +13,18 @@
#include "dib7000p.h"
#include "mt2060.h"
#include "mt2266.h"
+#include "dib0070.h"
static int force_lna_activation;
module_param(force_lna_activation, int, 0644);
MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
"if applicable for the device (default: 0=automatic/off).");
-/* Hauppauge Nova-T 500
+struct dib0700_adapter_state {
+ int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+};
+
+/* Hauppauge Nova-T 500 (aka Bristol)
* has a LNA on GPIO0 which is enabled by setting 1 */
static struct mt2060_config bristol_mt2060_config[2] = {
{
@@ -97,43 +102,89 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
}
-/* STK7700D: Pinnacle Dual DVB-T Diversity */
-
-static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config = {
- BAND_UHF/* | BAND_VHF*/,
- 0xE64, // setup
- 2372, // inv_gain
- 21, // time_stabiliz
-
- 0, // alpha_level
- 118, // thlock
-
- 0, // wbd_inv
- 0, // wbd_ref
- 0, // wbd_sel
- 0, // wbd_alpha
+/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
- 65535, // agc1_max
- 0, // agc1_min
- 65535, // agc2_max
- 23592, // agc2_min
- 0, // agc1_pt1
- 128, // agc1_pt2
- 128, // agc1_pt3
- 128, // agc1_slope1
- 0, // agc1_slope2
- 128, // agc2_pt1
- 253, // agc2_pt2
- 81, // agc2_slope1
- 0, // agc2_slope2
-
- 17, // alpha_mant
- 27, // alpha_exp
-
- 23, // beta_mant
- 51, // beta_exp
-
- 0, // perform_agc_softsplit : 1 en vrai!
+/* MT226x */
+static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
+ {
+ BAND_UHF, // band_caps
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+ 1130, // inv_gain
+ 21, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 0, // wbd_alpha
+
+ 65535, // agc1_max
+ 33770, // agc1_min
+ 65535, // agc2_max
+ 23592, // agc2_min
+
+ 0, // agc1_pt1
+ 62, // agc1_pt2
+ 255, // agc1_pt3
+ 64, // agc1_slope1
+ 64, // agc1_slope2
+ 132, // agc2_pt1
+ 192, // agc2_pt2
+ 80, // agc2_slope1
+ 80, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 1, // perform_agc_softsplit
+ }, {
+ BAND_VHF | BAND_LBAND, // band_caps
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+ 2372, // inv_gain
+ 21, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 0, // wbd_alpha
+
+ 65535, // agc1_max
+ 0, // agc1_min
+ 65535, // agc2_max
+ 23592, // agc2_min
+
+ 0, // agc1_pt1
+ 128, // agc1_pt2
+ 128, // agc1_pt3
+ 128, // agc1_slope1
+ 0, // agc1_slope2
+ 128, // agc2_pt1
+ 253, // agc2_pt2
+ 81, // agc2_slope1
+ 0, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 1, // perform_agc_softsplit
+ }
};
static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
@@ -150,23 +201,25 @@ static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .agc = &stk7700d_7000p_mt2266_agc_config,
+ .agc_config_count = 2,
+ .agc = stk7700d_7000p_mt2266_agc_config,
.bw = &stk7700d_mt2266_pll_config,
- .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
- .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
- .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
},
{ .output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .agc = &stk7700d_7000p_mt2266_agc_config,
+ .agc_config_count = 2,
+ .agc = stk7700d_7000p_mt2266_agc_config,
.bw = &stk7700d_mt2266_pll_config,
- .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
- .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
- .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
}
};
@@ -211,7 +264,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
-int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[4];
int i;
@@ -221,27 +274,25 @@ int stk7700d_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*state = REMOTE_NO_KEY_PRESSED;
i=dib0700_ctrl_rd(d,rc_request,2,key,4);
if (i<=0) {
- err("stk7700d:RC Query Failed\n");
- return 0;
+ err("RC Query Failed");
+ return -1;
}
if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
- if (key[1]!=st->rc_toggle) {
+ if (key[3-1]!=st->rc_toggle) {
for (i=0;i<d->props.rc_key_map_size; i++) {
- if (keymap[i].custom == key[2] && keymap[i].data == key[3]) {
+ if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
*event = keymap[i].event;
*state = REMOTE_KEY_PRESSED;
- st->rc_toggle=key[1];
+ st->rc_toggle=key[3-1];
return 0;
}
}
- err("stk7700d:Unknown remote controller key : %2X %2X\n",(int)key[2],(int)key[3]);
+ err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]);
}
return 0;
}
-#define KEY_MAP_SIZE (25+48)
-
-struct dvb_usb_rc_key stk7700d_rc_keys[] = {
+static struct dvb_usb_rc_key dib0700_rc_keys[] = {
/* Key codes for the tiny Pinnacle remote*/
{ 0x07, 0x00, KEY_MUTE },
{ 0x07, 0x01, KEY_MENU }, // Pinnacle logo
@@ -295,7 +346,7 @@ struct dvb_usb_rc_key stk7700d_rc_keys[] = {
{ 0xeb, 0x1a, KEY_BLUE },
{ 0xeb, 0x1b, KEY_CHANNELUP },
{ 0xeb, 0x1c, KEY_VOLUMEUP },
- { 0xeb, 0x1d, KEY_MUTE },
+ { 0xeb, 0x1d, KEY_MUTE },
{ 0xeb, 0x1e, KEY_VOLUMEDOWN },
{ 0xeb, 0x1f, KEY_CHANNELDOWN },
{ 0xeb, 0x40, KEY_PAUSE },
@@ -316,8 +367,55 @@ struct dvb_usb_rc_key stk7700d_rc_keys[] = {
{ 0xeb, 0x4f, KEY_FASTFORWARD },
{ 0xeb, 0x54, KEY_PREVIOUS },
{ 0xeb, 0x58, KEY_RECORD },
- { 0xeb, 0x5c, KEY_NEXT }
- };
+ { 0xeb, 0x5c, KEY_NEXT },
+
+ /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+ { 0x1e, 0x00, KEY_0 },
+ { 0x1e, 0x01, KEY_1 },
+ { 0x1e, 0x02, KEY_2 },
+ { 0x1e, 0x03, KEY_3 },
+ { 0x1e, 0x04, KEY_4 },
+ { 0x1e, 0x05, KEY_5 },
+ { 0x1e, 0x06, KEY_6 },
+ { 0x1e, 0x07, KEY_7 },
+ { 0x1e, 0x08, KEY_8 },
+ { 0x1e, 0x09, KEY_9 },
+ { 0x1e, 0x0a, KEY_KPASTERISK },
+ { 0x1e, 0x0b, KEY_RED },
+ { 0x1e, 0x0c, KEY_RADIO },
+ { 0x1e, 0x0d, KEY_MENU },
+ { 0x1e, 0x0e, KEY_GRAVE }, /* # */
+ { 0x1e, 0x0f, KEY_MUTE },
+ { 0x1e, 0x10, KEY_VOLUMEUP },
+ { 0x1e, 0x11, KEY_VOLUMEDOWN },
+ { 0x1e, 0x12, KEY_CHANNEL },
+ { 0x1e, 0x14, KEY_UP },
+ { 0x1e, 0x15, KEY_DOWN },
+ { 0x1e, 0x16, KEY_LEFT },
+ { 0x1e, 0x17, KEY_RIGHT },
+ { 0x1e, 0x18, KEY_VIDEO },
+ { 0x1e, 0x19, KEY_AUDIO },
+ { 0x1e, 0x1a, KEY_MEDIA },
+ { 0x1e, 0x1b, KEY_EPG },
+ { 0x1e, 0x1c, KEY_TV },
+ { 0x1e, 0x1e, KEY_NEXT },
+ { 0x1e, 0x1f, KEY_BACK },
+ { 0x1e, 0x20, KEY_CHANNELUP },
+ { 0x1e, 0x21, KEY_CHANNELDOWN },
+ { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
+ { 0x1e, 0x25, KEY_OK },
+ { 0x1e, 0x29, KEY_BLUE},
+ { 0x1e, 0x2e, KEY_GREEN },
+ { 0x1e, 0x30, KEY_PAUSE },
+ { 0x1e, 0x32, KEY_REWIND },
+ { 0x1e, 0x34, KEY_FASTFORWARD },
+ { 0x1e, 0x35, KEY_PLAY },
+ { 0x1e, 0x36, KEY_STOP },
+ { 0x1e, 0x37, KEY_RECORD },
+ { 0x1e, 0x38, KEY_YELLOW },
+ { 0x1e, 0x3b, KEY_GOTO },
+ { 0x1e, 0x3d, KEY_POWER },
+};
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
@@ -417,6 +515,7 @@ static struct dibx000_bandwidth_config stk7700p_pll_config = {
(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
60258167, // ifreq
20452225, // timf
+ 30000000, // xtal
};
static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -436,6 +535,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = {
static struct dib7000p_config stk7700p_dib7000p_config = {
.output_mpeg2_in_188_bytes = 1,
+ .agc_config_count = 1,
.agc = &stk7700p_7000p_mt2060_agc_config,
.bw = &stk7700p_pll_config,
@@ -490,30 +590,244 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
}
+/* DIB7070 generic */
+static struct dibx000_agc_config dib7070_agc_config = {
+ BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+ 600, // inv_gain
+ 10, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 5, // wbd_alpha
+
+ 65535, // agc1_max
+ 0, // agc1_min
+
+ 65535, // agc2_max
+ 0, // agc2_min
+
+ 0, // agc1_pt1
+ 40, // agc1_pt2
+ 183, // agc1_pt3
+ 206, // agc1_slope1
+ 255, // agc1_slope2
+ 72, // agc2_pt1
+ 152, // agc2_pt2
+ 88, // agc2_slope1
+ 90, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 0, // perform_agc_softsplit
+};
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+ return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+ return dib7000p_set_gpio(fe, 9, 0, onoff);
+}
+
+static struct dib0070_config dib7070p_dib0070_config[2] = {
+ {
+ .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+ .reset = dib7070_tuner_reset,
+ .sleep = dib7070_tuner_sleep,
+ .clock_khz = 12000,
+ .clock_pad_drive = 4
+ }, {
+ .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+ .reset = dib7070_tuner_reset,
+ .sleep = dib7070_tuner_sleep,
+ .clock_khz = 12000,
+
+ }
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ u16 offset;
+ u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+ switch (band) {
+ case BAND_VHF: offset = 950; break;
+ case BAND_UHF:
+ default: offset = 550; break;
+ }
+ deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
+ dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+ return state->set_param_save(fe, fep);
+}
+
+static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_adapter_state *st = adap->priv;
+ struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+ if (adap->id == 0) {
+ if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
+ return -ENODEV;
+ } else {
+ if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
+ return -ENODEV;
+ }
+
+ st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+ adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+ return 0;
+}
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+ 60000, 15000, // internal, sampling
+ 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+ 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+ (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+ (0 << 25) | 0, // ifreq = 0.000000 MHz
+ 20452225, // timf
+ 12000000, // xtal_hz
+};
+
+static struct dib7000p_config dib7070p_dib7000p_config = {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+};
+
+/* STK7070P */
+static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config);
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* STK7070PD */
+static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
+ {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+ }, {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+ }
+};
+
+static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config);
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
+{
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* DVB-USB and USB stuff follows */
struct usb_device_id dib0700_usb_id_table[] = {
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
+/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
- { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
+/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
{ USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) },
{ USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) },
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
- { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
+/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) },
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
- { } /* Terminating entry */
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) },
+/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
+ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) },
+ { 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
.caps = DVB_USB_IS_AN_I2C_ADAPTER, \
.usb_ctrl = DEVICE_SPECIFIC, \
- .firmware = "dvb-usb-dib0700-01.fw", \
+ .firmware = "dvb-usb-dib0700-03-pre1.fw", \
.download_firmware = dib0700_download_firmware, \
.no_reconnect = 1, \
.size_of_priv = sizeof(struct dib0700_state), \
@@ -562,7 +876,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
{ "Compro Videomate U500",
- { &dib0700_usb_id_table[6], NULL },
+ { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] },
{ NULL },
},
{ "Uniwill STK7700P based (Hama and others)",
@@ -597,7 +911,12 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
{ NULL },
},
- }
+ },
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -615,7 +934,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .num_device_descs = 3,
+ .num_device_descs = 4,
.devices = {
{ "Pinnacle PCTV 2000e",
{ &dib0700_usb_id_table[11], NULL },
@@ -625,16 +944,79 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[12], NULL },
{ NULL },
},
- { "Haupauge Nova-TD Stick",
+ { "Haupauge Nova-TD Stick/Elgato Eye-TV Diversity",
{ &dib0700_usb_id_table[13], NULL },
{ NULL },
},
+ { "DiBcom STK7700D reference design",
+ { &dib0700_usb_id_table[14], NULL },
+ { NULL },
+ },
},
+
.rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = stk7700d_rc_keys,
- .rc_key_map_size = KEY_MAP_SIZE,
- .rc_query = stk7700d_rc_query
- }
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
+
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .frontend_attach = stk7070p_frontend_attach,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ },
+ },
+
+ .num_device_descs = 2,
+ .devices = {
+ { "DiBcom STK7070P reference design",
+ { &dib0700_usb_id_table[15], NULL },
+ { NULL },
+ },
+ { "Pinnacle PCTV DVB-T Flash Stick",
+ { &dib0700_usb_id_table[16], NULL },
+ { NULL },
+ },
+ }
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .frontend_attach = stk7070pd_frontend_attach0,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }, {
+ .frontend_attach = stk7070pd_frontend_attach1,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }
+ },
+
+ .num_device_descs = 2,
+ .devices = {
+ { "DiBcom STK7070PD reference design",
+ { &dib0700_usb_id_table[17], NULL },
+ { NULL },
+ },
+ { "Pinnacle PCTV Dual DVB-T Diversity Stick",
+ { &dib0700_usb_id_table[18], NULL },
+ { NULL },
+ },
+ }
+ },
};
int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 2e38be3aa..a16be605c 100644
--- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -59,6 +59,7 @@
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
#define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78
+#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
@@ -67,6 +68,9 @@
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
#define USB_PID_DIBCOM_STK7700P 0x1e14
#define USB_PID_DIBCOM_STK7700P_PC 0x1e78
+#define USB_PID_DIBCOM_STK7700D 0x1ef0
+#define USB_PID_DIBCOM_STK7070P 0x1ebc
+#define USB_PID_DIBCOM_STK7070PD 0x1ebe
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
#define USB_PID_DPOSH_M9206_COLD 0x9206
#define USB_PID_DPOSH_M9206_WARM 0xa090
@@ -121,6 +125,11 @@
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_PINNACLE_PCTV2000E 0x022c
+#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
+#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229
+#define USB_PID_PCTV_200E 0x020e
+#define USB_PID_PCTV_400E 0x020f
+#define USB_PID_PCTV_450E 0x0222
#define USB_PID_NEBULA_DIGITV 0x0201
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
@@ -140,9 +149,6 @@
#define USB_PID_MSI_MEGASKY580_55801 0x5581
#define USB_PID_KYE_DVB_T_COLD 0x701e
#define USB_PID_KYE_DVB_T_WARM 0x701f
-#define USB_PID_PCTV_200E 0x020e
-#define USB_PID_PCTV_400E 0x020f
-#define USB_PID_PCTV_450E 0x0222
#define USB_PID_LITEON_DVB_T_COLD 0xf000
#define USB_PID_LITEON_DVB_T_WARM 0xf001
#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360
diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig
index faf9fe3c9..53e775539 100644
--- a/linux/drivers/media/dvb/frontends/Kconfig
+++ b/linux/drivers/media/dvb/frontends/Kconfig
@@ -344,6 +344,15 @@ config DVB_TUNER_MT2131
help
A driver for the silicon baseband tuner MT2131 from Microtune.
+config DVB_TUNER_DIB0070
+ tristate "DiBcom DiB0070 silicon base-band tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner DiB0070 from DiBcom.
+ This device is only used inside a SiP called togther with a
+ demodulator for now.
+
comment "Miscellaneous devices"
depends on DVB_CORE
diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile
index c46b9d8e9..4b8ad1f13 100644
--- a/linux/drivers/media/dvb/frontends/Makefile
+++ b/linux/drivers/media/dvb/frontends/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_DVB_TDA826X) += tda826x.o
obj-$(CONFIG_DVB_TDA827X) += tda827x.o
obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
+obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
diff --git a/linux/drivers/media/dvb/frontends/dib0070.c b/linux/drivers/media/dvb/frontends/dib0070.c
new file mode 100644
index 000000000..5643248a2
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/dib0070.c
@@ -0,0 +1,595 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.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.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib0070.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0)
+
+#define DIB0070_P1D 0x00
+#define DIB0070_P1F 0x01
+#define DIB0070_P1G 0x03
+#define DIB0070S_P1A 0x02
+
+struct dib0070_state {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend *fe;
+ const struct dib0070_config *cfg;
+ u16 wbd_ff_offset;
+ u8 revision;
+};
+
+static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+{
+ u8 b[2];
+ struct i2c_msg msg[2] = {
+ { .addr = state->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 },
+ };
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "DiB0070 I2C read failed\n");
+ return 0;
+ }
+ return (b[0] << 8) | b[1];
+}
+
+static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+{
+ u8 b[3] = { reg, val >> 8, val & 0xff };
+ struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "DiB0070 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0)
+
+static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ u16 tmp = 0;
+ tmp = dib0070_read_reg(st, 0x02) & 0x3fff;
+
+ switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) {
+ case 8000:
+ tmp |= (0 << 14);
+ break;
+ case 7000:
+ tmp |= (1 << 14);
+ break;
+ case 6000:
+ tmp |= (2 << 14);
+ break;
+ case 5000:
+ default:
+ tmp |= (3 << 14);
+ break;
+ }
+ dib0070_write_reg(st, 0x02, tmp);
+ return 0;
+}
+
+static void dib0070_captrim(struct dib0070_state *st, u16 LO4)
+{
+ int8_t captrim, fcaptrim, step_sign, step;
+ u16 adc, adc_diff = 3000;
+
+
+
+ dib0070_write_reg(st, 0x0f, 0xed10);
+ dib0070_write_reg(st, 0x17, 0x0034);
+
+ dib0070_write_reg(st, 0x18, 0x0032);
+ msleep(2);
+
+ step = captrim = fcaptrim = 64;
+
+ do {
+ step /= 2;
+ dib0070_write_reg(st, 0x14, LO4 | captrim);
+ msleep(1);
+ adc = dib0070_read_reg(st, 0x19);
+
+ dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024);
+
+ if (adc >= 400) {
+ adc -= 400;
+ step_sign = -1;
+ } else {
+ adc = 400 - adc;
+ step_sign = 1;
+ }
+
+ if (adc < adc_diff) {
+ dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff);
+ adc_diff = adc;
+ fcaptrim = captrim;
+
+
+
+ }
+ captrim += (step_sign * step);
+ } while (step >= 1);
+
+ dib0070_write_reg(st, 0x14, LO4 | fcaptrim);
+ dib0070_write_reg(st, 0x18, 0x07ff);
+}
+
+#define LPF 100 // define for the loop filter 100kHz by default 16-07-06
+#define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7)
+#define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12)
+#define LO4_SET_CTRIM(l, c) l |= (c) << 10
+static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf);
+
+ u8 band = BAND_OF_FREQUENCY(freq), c;
+
+ /*******************VCO***********************************/
+ u16 lo4 = 0;
+
+ u8 REFDIV, PRESC = 2;
+ u32 FBDiv, Rest, FREF, VCOF_kHz;
+ u16 Num, Den;
+ /*******************FrontEnd******************************/
+ u16 value = 0;
+
+ dprintk( "Tuning for Band: %hd (%d kHz)", band, freq);
+
+
+ dib0070_write_reg(st, 0x17, 0x30);
+
+ dib0070_set_bandwidth(fe, ch); /* c is used as HF */
+ switch (st->revision) {
+ case DIB0070S_P1A:
+ switch (band) {
+ case BAND_LBAND:
+ LO4_SET_VCO_HFDIV(lo4, 1, 1);
+ c = 2;
+ break;
+ case BAND_SBAND:
+ LO4_SET_VCO_HFDIV(lo4, 0, 0);
+ LO4_SET_CTRIM(lo4, 1);;
+ c = 1;
+ break;
+ case BAND_UHF:
+ default:
+ if (freq < 570000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 3);
+ PRESC = 6; c = 6;
+ } else if (freq < 680000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 2);
+ c = 4;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 1, 2);
+ c = 4;
+ }
+ break;
+ } break;
+
+ case DIB0070_P1G:
+ case DIB0070_P1F:
+ default:
+ switch (band) {
+ case BAND_FM:
+ LO4_SET_VCO_HFDIV(lo4, 0, 7);
+ c = 24;
+ break;
+ case BAND_LBAND:
+ LO4_SET_VCO_HFDIV(lo4, 1, 0);
+ c = 2;
+ break;
+ case BAND_VHF:
+ if (freq < 180000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 3);
+ c = 16;
+ } else if (freq < 190000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 3);
+ c = 16;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 0, 6);
+ c = 12;
+ }
+ break;
+
+ case BAND_UHF:
+ default:
+ if (freq < 570000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 5);
+ c = 6;
+ } else if (freq < 700000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 1);
+ c = 4;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 1, 1);
+ c = 4;
+ }
+ break;
+ }
+ break;
+ }
+
+ dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf);
+ dprintk( "VCO = %hd", (lo4 >> 11) & 0x3);
+
+
+ VCOF_kHz = (c * freq) * 2;
+ dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq);
+
+ switch (band) {
+ case BAND_VHF:
+ REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000);
+ break;
+ case BAND_FM:
+ REFDIV = (u8) ((st->cfg->clock_khz) / 1000);
+ break;
+ default:
+ REFDIV = (u8) ( st->cfg->clock_khz / 10000);
+ break;
+ }
+ FREF = st->cfg->clock_khz / REFDIV;
+
+ dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF);
+
+
+
+ switch (st->revision) {
+ case DIB0070S_P1A:
+ FBDiv = (VCOF_kHz / PRESC / FREF);
+ Rest = (VCOF_kHz / PRESC) - FBDiv * FREF;
+ break;
+
+ case DIB0070_P1G:
+ case DIB0070_P1F:
+ default:
+ FBDiv = (freq / (FREF / 2));
+ Rest = 2 * freq - FBDiv * FREF;
+ break;
+ }
+
+
+ if (Rest < LPF) Rest = 0;
+ else if (Rest < 2 * LPF) Rest = 2 * LPF;
+ else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; }
+ else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF;
+ Rest = (Rest * 6528) / (FREF / 10);
+ dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest);
+
+ Num = 0;
+ Den = 1;
+
+ if (Rest > 0) {
+ LO4_SET_SD(lo4, 1);
+ Den = 255;
+ Num = (u16)Rest;
+ }
+ dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1);
+
+
+
+ dib0070_write_reg(st, 0x11, (u16)FBDiv);
+
+
+ dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV);
+
+
+ dib0070_write_reg(st, 0x13, Num);
+
+
+ value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001;
+
+ switch (band) {
+ case BAND_UHF: value |= 0x4000 | 0x0800; break;
+ case BAND_LBAND: value |= 0x2000 | 0x0400; break;
+ default: value |= 0x8000 | 0x1000; break;
+ }
+ dib0070_write_reg(st, 0x20, value);
+
+ dib0070_captrim(st, lo4);
+ if (st->revision == DIB0070S_P1A) {
+ if (band == BAND_SBAND)
+ dib0070_write_reg(st, 0x15, 0x16e2);
+ else
+ dib0070_write_reg(st, 0x15, 0x56e5);
+ }
+
+
+
+ switch (band) {
+ case BAND_UHF: value = 0x7c82; break;
+ case BAND_LBAND: value = 0x7c84; break;
+ default: value = 0x7c81; break;
+ }
+ dib0070_write_reg(st, 0x0f, value);
+ dib0070_write_reg(st, 0x06, 0x3fff);
+
+ /* Front End */
+ /* c == TUNE, value = SWITCH */
+ c = 0;
+ value = 0;
+ switch (band) {
+ case BAND_FM:
+ c = 0; value = 1;
+ break;
+
+ case BAND_VHF:
+ if (freq <= 180000) c = 0;
+ else if (freq <= 188200) c = 1;
+ else if (freq <= 196400) c = 2;
+ else c = 3;
+ value = 1;
+ break;
+
+ case BAND_LBAND:
+ if (freq <= 1500000) c = 0;
+ else if (freq <= 1600000) c = 1;
+ else c = 3;
+ break;
+
+ case BAND_SBAND:
+ c = 7;
+ dib0070_write_reg(st, 0x1d,0xFFFF);
+ break;
+
+ case BAND_UHF:
+ default:
+ if (st->cfg->flip_chip) {
+ if (freq <= 550000) c = 0;
+ else if (freq <= 590000) c = 1;
+ else if (freq <= 666000) c = 3;
+ else c = 5;
+ } else {
+ if (freq <= 550000) c = 2;
+ else if (freq <= 650000) c = 3;
+ else if (freq <= 750000) c = 5;
+ else if (freq <= 850000) c = 6;
+ else c = 7;
+ }
+ value = 2;
+ break;
+ }
+
+ /* default: LNA_MATCH=7, BIAS=3 */
+ dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0));
+ dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127));
+ dib0070_write_reg(st, 0x0d, 0x0d80);
+
+
+ dib0070_write_reg(st, 0x18, 0x07ff);
+ dib0070_write_reg(st, 0x17, 0x0033);
+
+ return 0;
+}
+
+static int dib0070_wakeup(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ if (st->cfg->sleep)
+ st->cfg->sleep(fe, 0);
+ return 0;
+}
+
+static int dib0070_sleep(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ if (st->cfg->sleep)
+ st->cfg->sleep(fe, 1);
+ return 0;
+}
+
+static u16 dib0070_p1f_defaults[] =
+
+{
+ 7, 0x02,
+ 0x0008,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0002,
+ 0x0100,
+
+ 3, 0x0d,
+ 0x0d80,
+ 0x0001,
+ 0x0000,
+
+ 4, 0x11,
+ 0x0000,
+ 0x0103,
+ 0x0000,
+ 0x0000,
+
+ 3, 0x16,
+ 0x0004 | 0x0040,
+ 0x0030,
+ 0x07ff,
+
+ 6, 0x1b,
+ 0x4112,
+ 0xff00,
+ 0xc07f,
+ 0x0000,
+ 0x0180,
+ 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
+
+ 0,
+};
+
+static void dib0070_wbd_calibration(struct dib0070_state *state)
+{
+ u16 wbd_offs;
+ dib0070_write_reg(state, 0x0f, 0x6d81);
+ dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
+ msleep(9);
+ wbd_offs = dib0070_read_reg(state, 0x19);
+ dib0070_write_reg(state, 0x20, 0);
+ state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
+ dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
+}
+
+u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ return st->wbd_ff_offset;
+}
+
+EXPORT_SYMBOL(dib0070_wbd_offset);
+static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
+{
+ struct dib0070_state *state = fe->tuner_priv;
+ u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
+ dprintk( "CTRL_LO5: 0x%x", lo5);
+ return dib0070_write_reg(state, 0x15, lo5);
+}
+
+#define pgm_read_word(w) (*w)
+static int dib0070_reset(struct dib0070_state *state)
+{
+ u16 l, r, *n;
+
+ HARD_RESET(state);
+
+
+#ifndef FORCE_SBAND_TUNER
+ if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
+ state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
+ else
+#endif
+ state->revision = DIB0070S_P1A;
+
+ /* P1F or not */
+ dprintk( "Revision: %x", state->revision);
+
+ if (state->revision == DIB0070_P1D) {
+ dprintk( "Error: this driver is not to be used meant for P1D or earlier");
+ return -EINVAL;
+ }
+
+ n = (u16 *) dib0070_p1f_defaults;
+ l = pgm_read_word(n++);
+ while (l) {
+ r = pgm_read_word(n++);
+ do {
+ dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
+ r++;
+ } while (--l);
+ l = pgm_read_word(n++);
+ }
+
+ if (state->cfg->force_crystal_mode != 0)
+ r = state->cfg->force_crystal_mode;
+ else if (state->cfg->clock_khz >= 24000)
+ r = 1;
+ else
+ r = 2;
+
+ r |= state->cfg->osc_buffer_state << 3;
+
+ dib0070_write_reg(state, 0x10, r);
+ dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4));
+
+ if (state->cfg->invert_iq) {
+ r = dib0070_read_reg(state, 0x02) & 0xffdf;
+ dib0070_write_reg(state, 0x02, r | (1 << 5));
+ }
+
+
+ if (state->revision == DIB0070S_P1A)
+ dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1);
+ else
+ dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0);
+
+#if 0
+ /* BBFilter calib disabled until further notice */
+
+ dib0070_write_reg(state, 0x1e, 0x0010);
+ msleep(10);
+ r = dib0070_read_reg(state, 0x1e) >> 6;
+
+ if (r == 0)
+ r = 54;
+ else
+ r = (u16) (149 - (r * 3112) / state->cfg->clock_khz);
+
+ dib0070_write_reg(state, 0x01, (r << 9) | 0xc8);
+#else
+ dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
+#endif
+ return 0;
+}
+
+
+static int dib0070_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static struct dvb_tuner_ops dib0070_ops = {
+ .info = {
+ .name = "DiBcom DiB0070",
+ .frequency_min = 45000000,
+ .frequency_max = 860000000,
+ .frequency_step = 1000,
+ },
+ .release = dib0070_release,
+
+ .init = dib0070_wakeup,
+ .sleep = dib0070_sleep,
+ .set_params = dib0070_tune_digital,
+// .get_frequency = dib0070_get_frequency,
+// .get_bandwidth = dib0070_get_bandwidth
+};
+
+struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
+{
+ struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
+ if (state == NULL)
+ return NULL;
+
+ state->cfg = cfg;
+ state->i2c = i2c;
+ state->fe = fe;
+ fe->tuner_priv = state;
+
+ if (dib0070_reset(state) != 0)
+ goto free_mem;
+
+ dib0070_wbd_calibration(state);
+
+ printk(KERN_INFO "DiB0070: successfully identified\n");
+ memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = state;
+ return fe;
+
+free_mem:
+ kfree(state);
+ fe->tuner_priv = NULL;
+ return NULL;
+}
+EXPORT_SYMBOL(dib0070_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/frontends/dib0070.h b/linux/drivers/media/dvb/frontends/dib0070.h
new file mode 100644
index 000000000..786e37d33
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/dib0070.h
@@ -0,0 +1,44 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.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.
+ */
+#ifndef DIB0070_H
+#define DIB0070_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define DEFAULT_DIB0070_I2C_ADDRESS 0x60
+
+struct dib0070_config {
+ u8 i2c_address;
+
+ /* tuner pins controlled externally */
+ int (*reset) (struct dvb_frontend *, int);
+ int (*sleep) (struct dvb_frontend *, int);
+
+ /* offset in kHz */
+ int freq_offset_khz_uhf;
+ int freq_offset_khz_vhf;
+
+ u8 osc_buffer_state; /* 0= normal, 1= tri-state */
+ u32 clock_khz;
+ u8 clock_pad_drive; /* (Drive + 1) * 2mA */
+
+ u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */
+
+ u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
+
+ u8 flip_chip;
+};
+
+extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
+extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
+extern u16 dib0070_wbd_offset(struct dvb_frontend *);
+
+#endif
diff --git a/linux/drivers/media/dvb/frontends/dib3000mc.c b/linux/drivers/media/dvb/frontends/dib3000mc.c
index 7413aa923..494ca17cb 100644
--- a/linux/drivers/media/dvb/frontends/dib3000mc.c
+++ b/linux/drivers/media/dvb/frontends/dib3000mc.c
@@ -1,7 +1,7 @@
/*
* Driver for DiBcom DiB3000MC/P-demodulator.
*
- * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This code is partially based on the previous dib3000mc.c .
@@ -13,10 +13,6 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
-//#include <linux/init.h>
-//#include <linux/delay.h>
-//#include <linux/string.h>
-//#include <linux/slab.h>
#include "dvb_frontend.h"
@@ -26,7 +22,11 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0)
struct dib3000mc_state {
struct dvb_frontend demod;
@@ -42,6 +42,8 @@ struct dib3000mc_state {
fe_bandwidth_t current_bandwidth;
u16 dev_id;
+
+ u8 sfn_workaround_active :1;
};
static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
@@ -71,31 +73,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
-#if 0
-static void dump_fep(struct dibx000_ofdm_channel *cd)
-{
- printk(KERN_DEBUG "DiB3000MC: ");
- switch (cd->nfft) {
- case 1: printk("8K "); break;
- case 2: printk("4K "); break;
- case 0: printk("2K "); break;
- default: printk("FFT_UNK "); break;
- }
-
- printk("1/%i ", 32 / (1 << cd->guard));
- switch (cd->nqam) {
- case 0: printk("QPSK "); break;
- case 1: printk("16QAM "); break;
- case 2: printk("64QAM "); break;
- default: printk("QAM_UNK "); break;
- }
- printk("ALPHA %i ", cd->vit_alpha);
- printk("Code Rate HP %i/%i ", cd->vit_code_rate_hp, cd->vit_code_rate_hp + 1);
- printk("Code Rate LP %i/%i ", cd->vit_code_rate_lp, cd->vit_code_rate_lp + 1);
- printk("HRCH %i\n", cd->vit_hrch);
-}
-#endif
-
static int dib3000mc_identify(struct dib3000mc_state *state)
{
u16 value;
@@ -116,7 +93,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state)
return 0;
}
-static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
+static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
{
u32 timf;
@@ -127,7 +104,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw,
} else
timf = state->timf;
- timf *= (BW_INDEX_TO_KHZ(bw) / 1000);
+ timf *= (bw / 1000);
if (update_offset) {
s16 tim_offs = dib3000mc_read_word(state, 416);
@@ -135,17 +112,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw,
if (tim_offs & 0x2000)
tim_offs -= 0x4000;
- if (nfft == 0)
+ if (nfft == TRANSMISSION_MODE_2K)
tim_offs *= 4;
timf += tim_offs;
- state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000);
+ state->timf = timf / (bw / 1000);
}
dprintk("timf: %d\n", timf);
- dib3000mc_write_word(state, 23, timf >> 16);
- dib3000mc_write_word(state, 24, timf & 0xffff);
+ dib3000mc_write_word(state, 23, (u16) (timf >> 16));
+ dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff);
return 0;
}
@@ -233,31 +210,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
return ret;
}
-static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
+static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw)
{
- struct dib3000mc_state *state = demod->demodulator_priv;
u16 bw_cfg[6] = { 0 };
u16 imp_bw_cfg[3] = { 0 };
u16 reg;
/* settings here are for 27.7MHz */
switch (bw) {
- case BANDWIDTH_8_MHZ:
+ case 8000:
bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000:
bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
break;
- case BANDWIDTH_6_MHZ:
+ case 6000:
bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
break;
- case 255 /* BANDWIDTH_5_MHZ */:
+ case 5000:
bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
break;
@@ -281,7 +257,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
// Timing configuration
- dib3000mc_set_timing(state, 0, bw, 0);
+ dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0);
return 0;
}
@@ -300,7 +276,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode,
for (i = 58; i < 87; i++)
dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
- if (nfft == 1) {
+ if (nfft == TRANSMISSION_MODE_8K) {
dib3000mc_write_word(state, 58, 0x3b);
dib3000mc_write_word(state, 84, 0x00);
dib3000mc_write_word(state, 85, 0x8200);
@@ -400,7 +376,7 @@ static int dib3000mc_init(struct dvb_frontend *demod)
// P_search_maxtrial=1
dib3000mc_write_word(state, 5, 1);
- dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+ dib3000mc_set_bandwidth(state, 8000);
// div_lock_mask
dib3000mc_write_word(state, 4, 0x814);
@@ -421,7 +397,7 @@ static int dib3000mc_init(struct dvb_frontend *demod)
dib3000mc_write_word(state, 180, 0x2FF0);
// Impulse noise configuration
- dib3000mc_set_impulse_noise(state, 0, 1);
+ dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K);
// output mode set-up
dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
@@ -447,13 +423,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
{
u16 cfg[4] = { 0 },reg;
switch (qam) {
- case 0:
+ case QPSK:
cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
break;
- case 1:
+ case QAM_16:
cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
break;
- case 2:
+ case QAM_64:
cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
break;
}
@@ -461,11 +437,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
dib3000mc_write_word(state, reg, cfg[reg - 129]);
}
-static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq)
{
- u16 tmp;
-
- dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
+ u16 value;
+ dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0);
// if (boost)
// dib3000mc_write_word(state, 100, (11 << 6) + 6);
@@ -479,7 +455,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
dib3000mc_write_word(state, 26, 0x6680);
dib3000mc_write_word(state, 29, 0x1273);
dib3000mc_write_word(state, 33, 5);
- dib3000mc_set_adp_cfg(state, 1);
+ dib3000mc_set_adp_cfg(state, QAM_16);
dib3000mc_write_word(state, 133, 15564);
dib3000mc_write_word(state, 12 , 0x0);
@@ -494,45 +470,88 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
dib3000mc_write_word(state, 97,0);
dib3000mc_write_word(state, 98,0);
- dib3000mc_set_impulse_noise(state, 0, chan->nfft);
-
- tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
- dib3000mc_write_word(state, 0, tmp);
+ dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib3000mc_write_word(state, 0, value);
dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
- tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
- if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
- tmp |= chan->vit_code_rate_hp << 1;
- else
- tmp |= chan->vit_code_rate_lp << 1;
- dib3000mc_write_word(state, 181, tmp);
+ value = 0;
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
+ dib3000mc_write_word(state, 181, value);
- // diversity synchro delay
- tmp = dib3000mc_read_word(state, 180) & 0x000f;
- tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
- dib3000mc_write_word(state, 180, tmp);
+ // diversity synchro delay add 50% SFN margin
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case TRANSMISSION_MODE_2K:
+ default: value = 64; break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ value <<= 4;
+ value |= dib3000mc_read_word(state, 180) & 0x000f;
+ dib3000mc_write_word(state, 180, value);
// restart demod
- tmp = dib3000mc_read_word(state, 0);
- dib3000mc_write_word(state, 0, tmp | (1 << 9));
- dib3000mc_write_word(state, 0, tmp);
+ value = dib3000mc_read_word(state, 0);
+ dib3000mc_write_word(state, 0, value | (1 << 9));
+ dib3000mc_write_word(state, 0, value);
msleep(30);
- dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
+ dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);
}
-static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan)
{
struct dib3000mc_state *state = demod->demodulator_priv;
u16 reg;
// u32 val;
- struct dibx000_ofdm_channel fchan;
+ struct dvb_frontend_parameters schan;
- INIT_OFDM_CHANNEL(&fchan);
- fchan = *chan;
+ schan = *chan;
+ /* TODO what is that ? */
#if 0
if (boost) {
val = (dib3000mc_read_word(state, 6) << 16) | dib3000mc_read_word(state, 7);
@@ -544,11 +563,14 @@ static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000
#endif
/* a channel for autosearch */
- fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
- fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
- fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_2_3;
+ schan.u.ofdm.hierarchy_information = 0;
- dib3000mc_set_channel_cfg(state, &fchan, 11);
+ dib3000mc_set_channel_cfg(state, &schan, 11);
reg = dib3000mc_read_word(state, 0);
dib3000mc_write_word(state, 0, reg | (1 << 8));
@@ -572,7 +594,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
return 0; // still pending
}
-static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib3000mc_state *state = demod->demodulator_priv;
@@ -580,11 +602,17 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe
dib3000mc_set_channel_cfg(state, ch, 0);
// activates isi
- dib3000mc_write_word(state, 29, 0x1073);
-
- dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
+ if (state->sfn_workaround_active) {
+ dprintk("SFN workaround is active\n");
+ dib3000mc_write_word(state, 29, 0x1273);
+ dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift
+ } else {
+ dib3000mc_write_word(state, 29, 0x1073);
+ dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
+ }
- if (ch->nfft == 1) {
+ dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);
+ if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {
dib3000mc_write_word(state, 26, 38528);
dib3000mc_write_word(state, 33, 8);
} else {
@@ -593,7 +621,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe
}
if (dib3000mc_read_word(state, 509) & 0x80)
- dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
+ dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);
return 0;
}
@@ -665,13 +693,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib3000mc_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+ /* maybe the parameter has been changed */
+ state->sfn_workaround_active = buggy_sfn_workaround;
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, fep);
@@ -684,7 +711,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 100, found;
- dib3000mc_autosearch_start(fe, &ch);
+ dib3000mc_autosearch_start(fe, fep);
do {
msleep(1);
found = dib3000mc_autosearch_is_irq(fe);
@@ -695,13 +722,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
return 0; // no channel found
dib3000mc_get_frontend(fe, fep);
- FEP2DIB(fep,&ch);
}
/* make this a config parameter */
dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib3000mc_tune(fe, &ch);
+ return dib3000mc_tune(fe, fep);
}
static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
diff --git a/linux/drivers/media/dvb/frontends/dib7000m.c b/linux/drivers/media/dvb/frontends/dib7000m.c
index 7b93541a4..00cd5fcbd 100644
--- a/linux/drivers/media/dvb/frontends/dib7000m.c
+++ b/linux/drivers/media/dvb/frontends/dib7000m.c
@@ -2,7 +2,7 @@
* Linux-DVB Driver for DiBcom's DiB7000M and
* first generation DiB7000P-demodulator-family.
*
- * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2005-7 DiBcom (http://www.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
@@ -19,7 +19,7 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0)
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0)
struct dib7000m_state {
struct dvb_frontend demod;
@@ -39,8 +39,16 @@ struct dib7000m_state {
fe_bandwidth_t current_bandwidth;
struct dibx000_agc_config *current_agc;
u32 timf;
+ u32 timf_default;
+ u32 internal_clk;
+
+ u8 div_force_off : 1;
+ u8 div_state : 1;
+ u16 div_sync_wait;
u16 revision;
+
+ u8 agc_state;
};
enum dib7000m_power_mode {
@@ -63,7 +71,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
};
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
- dprintk("i2c read error on %d\n",reg);
+ dprintk("i2c read error on %d",reg);
return (rb[0] << 8) | rb[1];
}
@@ -79,6 +87,25 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
};
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
+static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+{
+ u16 l = 0, r, *n;
+ n = buf;
+ l = *n++;
+ while (l) {
+ r = *n++;
+
+ if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
+ r++;
+
+ do {
+ dib7000m_write_word(state, r, *n++);
+ r++;
+ } while (--l);
+ l = *n++;
+ }
+}
+
static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
{
int ret = 0;
@@ -89,8 +116,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
fifo_threshold = 1792;
smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
- dprintk("-I- Setting output mode for demod %p to %d\n",
- &state->demod, mode);
+ dprintk( "setting output mode for demod %p to %d", &state->demod, mode);
switch (mode) {
case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
@@ -117,7 +143,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
outreg = 0;
break;
default:
- dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
break;
}
@@ -129,13 +155,20 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
ret |= dib7000m_write_word(state, 1795, outreg);
ret |= dib7000m_write_word(state, 1805, sram);
+ if (state->revision == 0x4003) {
+ u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
+ if (mode == OUTMODE_DIVERSITY)
+ clk_cfg1 |= (1 << 1); // P_O_CLK_en
+ dib7000m_write_word(state, 909, clk_cfg1);
+ }
return ret;
}
-static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
+static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
{
/* by default everything is going to be powered off */
u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff;
+ u8 offset = 0;
/* now, depending on the requested mode, we power on */
switch (mode) {
@@ -170,16 +203,17 @@ static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_p
if (!state->cfg.mobile_mode)
reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
- /* P_sdio_select_clk = 0 on MC */
+ /* P_sdio_select_clk = 0 on MC and after*/
if (state->revision != 0x4000)
reg_906 <<= 1;
- dib7000m_write_word(state, 903, reg_903);
- dib7000m_write_word(state, 904, reg_904);
- dib7000m_write_word(state, 905, reg_905);
- dib7000m_write_word(state, 906, reg_906);
+ if (state->revision == 0x4003)
+ offset = 1;
- return 0;
+ dib7000m_write_word(state, 903 + offset, reg_903);
+ dib7000m_write_word(state, 904 + offset, reg_904);
+ dib7000m_write_word(state, 905 + offset, reg_905);
+ dib7000m_write_word(state, 906 + offset, reg_906);
}
static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
@@ -230,34 +264,55 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc
break;
}
-// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914);
-
+// dprintk( "913: %x, 914: %x", reg_913, reg_914);
ret |= dib7000m_write_word(state, 913, reg_913);
ret |= dib7000m_write_word(state, 914, reg_914);
return ret;
}
-static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx)
+static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
{
- struct dib7000m_state *state = demod->demodulator_priv;
u32 timf;
// store the current bandwidth for later use
- state->current_bandwidth = bw_idx;
+ state->current_bandwidth = bw;
if (state->timf == 0) {
- dprintk("-D- Using default timf\n");
- timf = state->cfg.bw->timf;
+ dprintk( "using default timf");
+ timf = state->timf_default;
} else {
- dprintk("-D- Using updated timf\n");
+ dprintk( "using updated timf");
timf = state->timf;
}
- timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80;
+ timf = timf * (bw / 50) / 160;
- dib7000m_write_word(state, 23, (timf >> 16) & 0xffff);
- dib7000m_write_word(state, 24, (timf ) & 0xffff);
+ dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+ dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff));
+
+ return 0;
+}
+
+static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+
+ if (state->div_force_off) {
+ dprintk( "diversity combination deactivated - forced by COFDM parameters");
+ onoff = 0;
+ }
+ state->div_state = (u8)onoff;
+
+ if (onoff) {
+ dib7000m_write_word(state, 263 + state->reg_offs, 6);
+ dib7000m_write_word(state, 264 + state->reg_offs, 6);
+ dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+ } else {
+ dib7000m_write_word(state, 263 + state->reg_offs, 1);
+ dib7000m_write_word(state, 264 + state->reg_offs, 0);
+ dib7000m_write_word(state, 266 + state->reg_offs, 0);
+ }
return 0;
}
@@ -265,7 +320,7 @@ static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx)
static int dib7000m_sad_calib(struct dib7000m_state *state)
{
#if 0
- REAL ref,x;
+ double ref,x;
/* external */
dib7000m_write_word(state, 928, (1 << 14) | (3 << 12) | (524 << 0));
dib7000m_write_word(state, 929, (1 << 1) | (0 << 0));
@@ -275,32 +330,32 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
ref = dib7000m_read_word(state, 934);
x = 0.625/3.3 * (4096.0/ref);
- dprintk("-D- ref: %g = %g (%x) \n", ref, x, (INT) (x * 8192.0) / 2);
+ dprintk( "ref: %g = %g (%x)", ref, x, (int) (x * 8192.0) / 2);
- dib7000m_write_word(state, 930, (INT) (x * 8192.0) / 2);
+ dib7000m_write_word(state, 930, (int) (x * 8192.0) / 2);
dib7000m_write_word(state, 928, (0 << 14) | (1 << 12) | (524 << 0));
msleep(1);
ref = dib7000m_read_word(state, 932);
- dprintk("-D- wbd voltage: %g = %g\n", ref, ref/4096.0 * 3.3);
+ dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3);
msleep(1);
ref = dib7000m_read_word(state, 932);
- dprintk("-D- wbd voltage: %g = %g\n", ref, ref/4096.0 * 3.3);
+ dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3);
msleep(1);
ref = dib7000m_read_word(state, 932);
- dprintk("-D- wbd voltage: %g = %g\n", ref, ref/4096.0 * 3.3);
+ dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3);
msleep(1);
ref = dib7000m_read_word(state, 932);
- dprintk("-D- wbd voltage: %g = %g\n", ref, ref/4096.0 * 3.3);
+ dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3);
msleep(1);
ref = dib7000m_read_word(state, 932);
- dprintk("-D- wbd voltage: %g = %g\n", ref, ref/4096.0 * 3.3);
+ dprintk( "wbd voltage: %g = %g", ref, ref/4096.0 * 3.3);
#else
/* internal */
-// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
+// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
@@ -316,10 +371,10 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
{
- dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
- dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff);
- dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff);
- dib7000m_write_word(state, 22, bw->ifreq & 0xffff);
+ dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+ dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff));
+ dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
+ dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff));
dib7000m_write_word(state, 928, bw->sad_cfg);
}
@@ -360,15 +415,19 @@ static void dib7000m_reset_pll(struct dib7000m_state *state)
static void dib7000mc_reset_pll(struct dib7000m_state *state)
{
const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+ u16 clk_cfg1;
// clk_cfg0
dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
// clk_cfg1
//dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
- dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) |
+ clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
(bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
- (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0));
+ (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
+ dib7000m_write_word(state, 908, clk_cfg1);
+ clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
+ dib7000m_write_word(state, 908, clk_cfg1);
// smpl_cfg
dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
@@ -379,9 +438,6 @@ static void dib7000mc_reset_pll(struct dib7000m_state *state)
static int dib7000m_reset_gpio(struct dib7000m_state *st)
{
/* reset the GPIOs */
- dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",
- st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos);
-
dib7000m_write_word(st, 773, st->cfg.gpio_dir);
dib7000m_write_word(st, 774, st->cfg.gpio_val);
@@ -393,6 +449,107 @@ static int dib7000m_reset_gpio(struct dib7000m_state *st)
return 0;
}
+static u16 dib7000m_defaults_common[] =
+
+{
+ // auto search configuration
+ 3, 2,
+ 0x0004,
+ 0x1000,
+ 0x0814,
+
+ 12, 6,
+ 0x001b,
+ 0x7740,
+ 0x005b,
+ 0x8d80,
+ 0x01c9,
+ 0xc380,
+ 0x0000,
+ 0x0080,
+ 0x0000,
+ 0x0090,
+ 0x0001,
+ 0xd4c0,
+
+ 1, 26,
+ 0x6680, // P_corm_thres Lock algorithms configuration
+
+ 1, 170,
+ 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
+
+ 8, 173,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ 1, 182,
+ 8192, // P_fft_nb_to_cut
+
+ 2, 195,
+ 0x0ccd, // P_pha3_thres
+ 0, // P_cti_use_cpe, P_cti_use_prog
+
+ 1, 205,
+ 0x200f, // P_cspu_regul, P_cspu_win_cut
+
+ 5, 214,
+ 0x023d, // P_adp_regul_cnt
+ 0x00a4, // P_adp_noise_cnt
+ 0x00a4, // P_adp_regul_ext
+ 0x7ff0, // P_adp_noise_ext
+ 0x3ccc, // P_adp_fil
+
+ 1, 226,
+ 0, // P_2d_byp_ti_num
+
+ 1, 255,
+ 0x800, // P_equal_thres_wgn
+
+ 1, 263,
+ 0x0001,
+
+ 1, 281,
+ 0x0010, // P_fec_*
+
+ 1, 294,
+ 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+ 0
+};
+
+static u16 dib7000m_defaults[] =
+
+{
+ /* set ADC level to -16 */
+ 11, 76,
+ (1 << 13) - 825 - 117,
+ (1 << 13) - 837 - 117,
+ (1 << 13) - 811 - 117,
+ (1 << 13) - 766 - 117,
+ (1 << 13) - 737 - 117,
+ (1 << 13) - 693 - 117,
+ (1 << 13) - 648 - 117,
+ (1 << 13) - 619 - 117,
+ (1 << 13) - 575 - 117,
+ (1 << 13) - 531 - 117,
+ (1 << 13) - 501 - 117,
+
+ // Tuner IO bank: max drive (14mA)
+ 1, 912,
+ 0x2c8a,
+
+ 1, 1817,
+ 1,
+
+ 0,
+};
+
static int dib7000m_demod_reset(struct dib7000m_state *state)
{
dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
@@ -417,22 +574,47 @@ static int dib7000m_demod_reset(struct dib7000m_state *state)
dib7000mc_reset_pll(state);
if (dib7000m_reset_gpio(state) != 0)
- dprintk("-E- GPIO reset was not successful.\n");
+ dprintk( "GPIO reset was not successful.");
if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
- dprintk("-E- OUTPUT_MODE could not be resetted.\n");
+ dprintk( "OUTPUT_MODE could not be reset.");
/* unforce divstr regardless whether i2c enumeration was done or not */
dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
- dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+ dib7000m_set_bandwidth(state, 8000);
dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
dib7000m_sad_calib(state);
dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+ if (state->cfg.dvbt_mode)
+ dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
+
+ if (state->cfg.mobile_mode)
+ dib7000m_write_word(state, 261 + state->reg_offs, 2);
+ else
+ dib7000m_write_word(state, 224 + state->reg_offs, 1);
+
+ // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
+ if(state->cfg.tuner_is_baseband)
+ dib7000m_write_word(state, 36, 0x0755);
+ else
+ dib7000m_write_word(state, 36, 0x1f55);
+
+ // P_divclksel=3 P_divbitsel=1
+ if (state->revision == 0x4000)
+ dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
+ else
+ dib7000m_write_word(state, 909, (3 << 4) | 1);
+
+ dib7000m_write_tab(state, dib7000m_defaults_common);
+ dib7000m_write_tab(state, dib7000m_defaults);
+
dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
+ state->internal_clk = state->cfg.bw->internal;
+
return 0;
}
@@ -462,7 +644,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state)
(agc - state->current_agc->split.min_thres) /
(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
- dprintk("AGC split_offset: %d\n",split_offset);
+ dprintk( "AGC split_offset: %d",split_offset);
// P_agc_force_split and P_agc_split_offset
return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
@@ -470,35 +652,26 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state)
static int dib7000m_update_lna(struct dib7000m_state *state)
{
- int i;
u16 dyn_gain;
- // when there is no LNA to program return immediatly
- if (state->cfg.update_lna == NULL)
- return 0;
-
- msleep(60);
- for (i = 0; i < 20; i++) {
- // read dyn_gain here (because it is demod-dependent and not tuner)
+ if (state->cfg.update_lna) {
+ // read dyn_gain here (because it is demod-dependent and not fe)
dyn_gain = dib7000m_read_word(state, 390);
- dprintk("agc global: %d\n", dyn_gain);
-
if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
dib7000m_restart_agc(state);
- msleep(60);
- } else
- break;
+ return 1;
+ }
}
return 0;
}
-static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
+static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
{
struct dibx000_agc_config *agc = NULL;
int i;
- if (state->current_band == band)
- return;
+ if (state->current_band == band && state->current_agc != NULL)
+ return 0;
state->current_band = band;
for (i = 0; i < state->cfg.agc_config_count; i++)
@@ -508,8 +681,8 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
}
if (agc == NULL) {
- dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band);
- return;
+ dprintk( "no valid AGC configuration found for band 0x%02x",band);
+ return -EINVAL;
}
state->current_agc = agc;
@@ -524,7 +697,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp);
- dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
+ dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
/* AGC continued */
@@ -545,7 +718,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
if (state->revision > 0x4000) { // settings for the MC
dib7000m_write_word(state, 71, agc->agc1_pt3);
-// dprintk("-D- 929: %x %d %d\n",
+// dprintk( "929: %x %d %d",
// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
} else {
@@ -554,33 +727,160 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
for (i = 0; i < 9; i++)
dib7000m_write_word(state, 88 + i, b[i]);
}
+ return 0;
}
-static void dib7000m_update_timf_freq(struct dib7000m_state *state)
+static void dib7000m_update_timf(struct dib7000m_state *state)
{
u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
- state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+ state->timf = timf * 160 / (state->current_bandwidth / 50);
dib7000m_write_word(state, 23, (u16) (timf >> 16));
dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
- dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+ dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
+}
+
+static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+ u16 cfg_72 = dib7000m_read_word(state, 72);
+ int ret = -1;
+ u8 *agc_state = &state->agc_state;
+ u8 agc_split;
+
+ switch (state->agc_state) {
+ case 0:
+ // set power-up level: interf+analog+AGC
+ dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
+ dib7000m_set_adc_state(state, DIBX000_ADC_ON);
+
+ if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+ return -1;
+
+ ret = 7; /* ADC power up */
+ (*agc_state)++;
+ break;
+
+ case 1:
+ /* AGC initialization */
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 1);
+
+ dib7000m_write_word(state, 75, 32768);
+ if (!state->current_agc->perform_agc_softsplit) {
+ /* we are using the wbd - so slow AGC startup */
+ dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
+ (*agc_state)++;
+ ret = 5;
+ } else {
+ /* default AGC startup */
+ (*agc_state) = 4;
+ /* wait AGC rough lock time */
+ ret = 7;
+ }
+
+ dib7000m_restart_agc(state);
+ break;
+
+ case 2: /* fast split search path after 5sec */
+ dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */
+ dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */
+ (*agc_state)++;
+ ret = 14;
+ break;
+
+ case 3: /* split search ended */
+ agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
+ dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
+
+ dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */
+ dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+ dib7000m_restart_agc(state);
+
+ dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+ (*agc_state)++;
+ ret = 5;
+ break;
+
+ case 4: /* LNA startup */
+ /* wait AGC accurate lock time */
+ ret = 7;
+
+ if (dib7000m_update_lna(state))
+ // wait only AGC rough lock time
+ ret = 5;
+ else
+ (*agc_state)++;
+ break;
+
+ case 5:
+ dib7000m_agc_soft_split(state);
+
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 0);
+
+ (*agc_state)++;
+ break;
+
+ default:
+ break;
+ }
+ return ret;
}
-static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq)
{
u16 value, est[4];
- dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz));
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
/* nfft, guard, qam, alpha */
- dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ case /* 4K MODE */ 255: value |= (2 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib7000m_write_word(state, 0, value);
dib7000m_write_word(state, 5, (seq << 4));
- /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
- value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
- if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
- value |= (ch->vit_code_rate_hp << 1);
- else
- value |= (ch->vit_code_rate_lp << 1);
+ /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+ value = 0;
+ if (1 != 0)
+ value |= (1 << 6);
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
dib7000m_write_word(state, 267 + state->reg_offs, value);
/* offset loop parameters */
@@ -598,32 +898,38 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of
dib7000m_write_word(state, 33, (0 << 4) | 0x5);
/* P_dvsy_sync_wait */
- switch (ch->nfft) {
- case 1: value = 256; break;
- case 2: value = 128; break;
- case 0:
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
- value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
- value <<= 4;
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
/* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
- if (ch->intlv_native || state->revision > 0x4000)
- value |= (1 << 2) | (2 << 0);
+ if (1 == 1 || state->revision > 0x4000)
+ state->div_force_off = 0;
else
- value |= 0;
- dib7000m_write_word(state, 266 + state->reg_offs, value);
+ state->div_force_off = 1;
+ dib7000m_set_diversity_in(&state->demod, state->div_state);
/* channel estimation fine configuration */
- switch (ch->nqam) {
- case 2:
+ switch (ch->u.ofdm.constellation) {
+ case QAM_64:
est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
break;
- case 1:
+ case QAM_16:
est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
@@ -639,70 +945,48 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of
for (value = 0; value < 4; value++)
dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
- // set power-up level: interf+analog+AGC
- dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
- dib7000m_set_adc_state(state, DIBX000_ADC_ON);
-
- msleep(7);
-
- //AGC initialization
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 1);
-
- dib7000m_restart_agc(state);
-
- // wait AGC rough lock time
- msleep(5);
-
- dib7000m_update_lna(state);
- dib7000m_agc_soft_split(state);
-
- // wait AGC accurate lock time
- msleep(7);
-
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 0);
-
// set power-up level: autosearch
dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
}
-static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000m_state *state = demod->demodulator_priv;
- struct dibx000_ofdm_channel auto_ch;
+ struct dvb_frontend_parameters schan;
int ret = 0;
- u32 value;
-
- INIT_OFDM_CHANNEL(&auto_ch);
- auto_ch.RF_kHz = ch->RF_kHz;
- auto_ch.Bw = ch->Bw;
- auto_ch.nqam = 2;
- auto_ch.guard = 0;
- auto_ch.nfft = 1;
- auto_ch.vit_alpha = 1;
- auto_ch.vit_select_hp = 1;
- auto_ch.vit_code_rate_hp = 2;
- auto_ch.vit_code_rate_lp = 3;
- auto_ch.vit_hrch = 0;
- auto_ch.intlv_native = 1;
-
- dib7000m_set_channel(state, &auto_ch, 7);
+ u32 value, factor;
+
+ schan = *ch;
+
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_3_4;
+ schan.u.ofdm.hierarchy_information = 0;
+
+ dib7000m_set_channel(state, &schan, 7);
+
+ factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+ if (factor >= 5000)
+ factor = 1;
+ else
+ factor = 6;
// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
- value = 30 * state->cfg.bw->internal;
+ value = 30 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
- value = 100 * state->cfg.bw->internal;
+ value = 100 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
- value = 500 * state->cfg.bw->internal;
+ value = 500 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
// start search
value = dib7000m_read_word(state, 0);
- ret |= dib7000m_write_word(state, 0, value | (1 << 9));
+ ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
/* clear n_irq_pending */
if (state->revision == 0x4000)
@@ -720,12 +1004,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
u16 irq_pending = dib7000m_read_word(state, reg);
if (irq_pending & 0x1) { // failed
- dprintk("#\n");
+ dprintk( "autosearch failed");
return 1;
}
if (irq_pending & 0x2) { // succeeded
- dprintk("!\n");
+ dprintk( "autosearch succeeded");
return 2;
}
return 0; // still pending
@@ -740,7 +1024,7 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
return dib7000m_autosearch_irq(state, 537);
}
-static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000m_state *state = demod->demodulator_priv;
int ret = 0;
@@ -757,182 +1041,103 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
ret |= dib7000m_write_word(state, 898, 0x0000);
msleep(45);
- ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
+ dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
- // never achieved a lock with that bandwidth so far - wait for timfreq to update
+ // never achieved a lock before - wait for timfreq to update
if (state->timf == 0)
msleep(200);
//dump_reg(state);
/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
value = (6 << 8) | 0x80;
- switch (ch->nfft) {
- case 0: value |= (7 << 12); break;
- case 1: value |= (9 << 12); break;
- case 2: value |= (8 << 12); break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
+ case /* 4K MODE */ 255: value |= (8 << 12); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
}
ret |= dib7000m_write_word(state, 26, value);
/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
value = (0 << 4);
- switch (ch->nfft) {
- case 0: value |= 0x6; break;
- case 1: value |= 0x8; break;
- case 2: value |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= 0x6; break;
+ case /* 4K MODE */ 255: value |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
ret |= dib7000m_write_word(state, 32, value);
/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
value = (0 << 4);
- switch (ch->nfft) {
- case 0: value |= 0x6; break;
- case 1: value |= 0x8; break;
- case 2: value |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= 0x6; break;
+ case /* 4K MODE */ 255: value |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
ret |= dib7000m_write_word(state, 33, value);
- // we achieved a lock - it's time to update the osc freq
+ // we achieved a lock - it's time to update the timf freq
if ((dib7000m_read_word(state, 535) >> 6) & 0x1)
- dib7000m_update_timf_freq(state);
+ dib7000m_update_timf(state);
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
return ret;
}
-static int dib7000m_init(struct dvb_frontend *demod)
+static int dib7000m_wakeup(struct dvb_frontend *demod)
{
struct dib7000m_state *state = demod->demodulator_priv;
- int ret = 0;
- u8 o = state->reg_offs;
dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
- dprintk("-E- could not start Slow ADC\n");
-
- if (state->cfg.dvbt_mode)
- dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
-
- if (state->cfg.mobile_mode)
- ret |= dib7000m_write_word(state, 261 + o, 2);
- else
- ret |= dib7000m_write_word(state, 224 + o, 1);
-
- ret |= dib7000m_write_word(state, 173 + o, 0);
- ret |= dib7000m_write_word(state, 174 + o, 0);
- ret |= dib7000m_write_word(state, 175 + o, 0);
- ret |= dib7000m_write_word(state, 176 + o, 0);
- ret |= dib7000m_write_word(state, 177 + o, 0);
- ret |= dib7000m_write_word(state, 178 + o, 0);
- ret |= dib7000m_write_word(state, 179 + o, 0);
- ret |= dib7000m_write_word(state, 180 + o, 0);
-
- // P_corm_thres Lock algorithms configuration
- ret |= dib7000m_write_word(state, 26, 0x6680);
-
- // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
- ret |= dib7000m_write_word(state, 170 + o, 0x0410);
- // P_fft_nb_to_cut
- ret |= dib7000m_write_word(state, 182 + o, 8192);
- // P_pha3_thres
- ret |= dib7000m_write_word(state, 195 + o, 0x0ccd);
- // P_cti_use_cpe, P_cti_use_prog
- ret |= dib7000m_write_word(state, 196 + o, 0);
- // P_cspu_regul, P_cspu_win_cut
- ret |= dib7000m_write_word(state, 205 + o, 0x200f);
- // P_adp_regul_cnt
- ret |= dib7000m_write_word(state, 214 + o, 0x023d);
- // P_adp_noise_cnt
- ret |= dib7000m_write_word(state, 215 + o, 0x00a4);
- // P_adp_regul_ext
- ret |= dib7000m_write_word(state, 216 + o, 0x00a4);
- // P_adp_noise_ext
- ret |= dib7000m_write_word(state, 217 + o, 0x7ff0);
- // P_adp_fil
- ret |= dib7000m_write_word(state, 218 + o, 0x3ccc);
-
- // P_2d_byp_ti_num
- ret |= dib7000m_write_word(state, 226 + o, 0);
-
- // P_fec_*
- ret |= dib7000m_write_word(state, 281 + o, 0x0010);
- // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
- ret |= dib7000m_write_word(state, 294 + o,0x0062);
-
- // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
- if(state->cfg.tuner_is_baseband)
- ret |= dib7000m_write_word(state, 36, 0x0755);
- else
- ret |= dib7000m_write_word(state, 36, 0x1f55);
-
- // auto search configuration
- ret |= dib7000m_write_word(state, 2, 0x0004);
- ret |= dib7000m_write_word(state, 3, 0x1000);
- ret |= dib7000m_write_word(state, 4, 0x0814);
- ret |= dib7000m_write_word(state, 6, 0x001b);
- ret |= dib7000m_write_word(state, 7, 0x7740);
- ret |= dib7000m_write_word(state, 8, 0x005b);
- ret |= dib7000m_write_word(state, 9, 0x8d80);
- ret |= dib7000m_write_word(state, 10, 0x01c9);
- ret |= dib7000m_write_word(state, 11, 0xc380);
- ret |= dib7000m_write_word(state, 12, 0x0000);
- ret |= dib7000m_write_word(state, 13, 0x0080);
- ret |= dib7000m_write_word(state, 14, 0x0000);
- ret |= dib7000m_write_word(state, 15, 0x0090);
- ret |= dib7000m_write_word(state, 16, 0x0001);
- ret |= dib7000m_write_word(state, 17, 0xd4c0);
- ret |= dib7000m_write_word(state, 263 + o,0x0001);
-
- // P_divclksel=3 P_divbitsel=1
- if (state->revision == 0x4000)
- dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
- else
- dib7000m_write_word(state, 909, (3 << 4) | 1);
-
- // Tuner IO bank: max drive (14mA)
- ret |= dib7000m_write_word(state, 912 ,0x2c8a);
+ dprintk( "could not start Slow ADC");
- ret |= dib7000m_write_word(state, 1817, 1);
-
- return ret;
+ return 0;
}
static int dib7000m_sleep(struct dvb_frontend *demod)
{
struct dib7000m_state *st = demod->demodulator_priv;
dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
- return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) |
- dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
+ dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
+ return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
}
static int dib7000m_identify(struct dib7000m_state *state)
{
u16 value;
+
if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
- dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value);
+ dprintk( "wrong Vendor ID (0x%x)",value);
return -EREMOTEIO;
}
state->revision = dib7000m_read_word(state, 897);
if (state->revision != 0x4000 &&
state->revision != 0x4001 &&
- state->revision != 0x4002) {
- dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value);
+ state->revision != 0x4002 &&
+ state->revision != 0x4003) {
+ dprintk( "wrong Device ID (0x%x)",value);
return -EREMOTEIO;
}
/* protect this driver to be used with 7000PC */
if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
- dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n");
+ dprintk( "this driver does not work with DiB7000PC");
return -EREMOTEIO;
}
switch (state->revision) {
- case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break;
- case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break;
- case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break;
+ case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break;
+ case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break;
+ case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break;
+ case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break;
}
return 0;
@@ -1001,41 +1206,45 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib7000m_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
+ int time;
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, fep);
+ /* start up the AGC */
+ state->agc_state = 0;
+ do {
+ time = dib7000m_agc_startup(fe, fep);
+ if (time != -1)
+ msleep(time);
+ } while (time != -1);
+
if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
fep->u.ofdm.constellation == QAM_AUTO ||
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 800, found;
- dib7000m_autosearch_start(fe, &ch);
+ dib7000m_autosearch_start(fe, fep);
do {
msleep(1);
found = dib7000m_autosearch_is_irq(fe);
} while (found == 0 && i--);
- dprintk("autosearch returns: %d\n",found);
+ dprintk("autosearch returns: %d",found);
if (found == 0 || found == 1)
return 0; // no channel found
dib7000m_get_frontend(fe, fep);
- FEP2DIB(fep, &ch);
}
/* make this a config parameter */
dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib7000m_tune(fe, &ch);
+ return dib7000m_tune(fe, fep);
}
static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -1122,7 +1331,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
if (dib7000m_identify(&st) != 0) {
st.i2c_addr = default_addr;
if (dib7000m_identify(&st) != 0) {
- dprintk("DiB7000M #%d: not identified\n", k);
+ dprintk("DiB7000M #%d: not identified", k);
return -EIO;
}
}
@@ -1135,7 +1344,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
/* set new i2c address and force divstart */
dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
- dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+ dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
}
for (k = 0; k < no_of_demods; k++) {
@@ -1170,6 +1379,8 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
demod->demodulator_priv = st;
memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
+ st->timf_default = cfg->bw->timf;
+
if (dib7000m_identify(st) != 0)
goto error;
@@ -1207,7 +1418,7 @@ static struct dvb_frontend_ops dib7000m_ops = {
.release = dib7000m_release,
- .init = dib7000m_init,
+ .init = dib7000m_wakeup,
.sleep = dib7000m_sleep,
.set_frontend = dib7000m_set_frontend,
diff --git a/linux/drivers/media/dvb/frontends/dib7000p.c b/linux/drivers/media/dvb/frontends/dib7000p.c
index f8d98773c..81eb3db06 100644
--- a/linux/drivers/media/dvb/frontends/dib7000p.c
+++ b/linux/drivers/media/dvb/frontends/dib7000p.c
@@ -1,7 +1,7 @@
/*
* Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
*
- * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2005-7 DiBcom (http://www.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
@@ -18,7 +18,11 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
struct dib7000p_state {
struct dvb_frontend demod;
@@ -36,12 +40,21 @@ struct dib7000p_state {
struct dibx000_agc_config *current_agc;
u32 timf;
+ u8 div_force_off : 1;
+ u8 div_state : 1;
+ u16 div_sync_wait;
+
+ u8 agc_state;
+
u16 gpio_dir;
u16 gpio_val;
+
+ u8 sfn_workaround_active :1;
};
enum dib7000p_power_mode {
DIB7000P_POWER_ALL = 0,
+ DIB7000P_POWER_ANALOG_ADC,
DIB7000P_POWER_INTERFACE_ONLY,
};
@@ -55,7 +68,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
};
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
- dprintk("i2c read error on %d\n",reg);
+ dprintk("i2c read error on %d",reg);
return (rb[0] << 8) | rb[1];
}
@@ -71,6 +84,22 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
};
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
+static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
+{
+ u16 l = 0, r, *n;
+ n = buf;
+ l = *n++;
+ while (l) {
+ r = *n++;
+
+ do {
+ dib7000p_write_word(state, r, *n++);
+ r++;
+ } while (--l);
+ l = *n++;
+ }
+}
+
static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
{
int ret = 0;
@@ -80,7 +109,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
fifo_threshold = 1792;
smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
- dprintk("-I- Setting output mode for demod %p to %d\n",
+ dprintk( "setting output mode for demod %p to %d",
&state->demod, mode);
switch (mode) {
@@ -104,19 +133,17 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
fifo_threshold = 512;
outreg = (1 << 10) | (5 << 6);
break;
+ case OUTMODE_ANALOG_ADC:
+ outreg = (1 << 10) | (3 << 6);
+ break;
case OUTMODE_HIGH_Z: // disable
outreg = 0;
break;
default:
- dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
break;
}
- if (state->cfg.hostbus_diversity) {
- ret |= dib7000p_write_word(state, 204, 1); // Diversity ?
- ret |= dib7000p_write_word(state, 205, 0); // Diversity ?
- }
-
if (state->cfg.output_mpeg2_in_188_bytes)
smo_mode |= (1 << 5) ;
@@ -127,6 +154,30 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
return ret;
}
+static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+
+ if (state->div_force_off) {
+ dprintk( "diversity combination deactivated - forced by COFDM parameters");
+ onoff = 0;
+ }
+ state->div_state = (u8)onoff;
+
+ if (onoff) {
+ dib7000p_write_word(state, 204, 6);
+ dib7000p_write_word(state, 205, 16);
+ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+ dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+ } else {
+ dib7000p_write_word(state, 204, 1);
+ dib7000p_write_word(state, 205, 0);
+ dib7000p_write_word(state, 207, 0);
+ }
+
+ return 0;
+}
+
static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
{
/* by default everything is powered off */
@@ -139,10 +190,21 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p
case DIB7000P_POWER_ALL:
reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
break;
+
+ case DIB7000P_POWER_ANALOG_ADC:
+ /* dem, cfg, iqc, sad, agc */
+ reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
+ /* nud */
+ reg_776 &= ~((1 << 0));
+ /* Dout */
+ reg_1280 &= ~((1 << 11));
+ /* fall through wanted to enable the interfaces */
+
/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
break;
+
/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
#if 0
case DIB7000_POWER_LEVEL_INTERF_ANALOG_AGC:
@@ -218,34 +280,31 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad
break;
}
-// dprintk("908: %x, 909: %x\n", reg_908, reg_909);
+// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
dib7000p_write_word(state, 908, reg_908);
dib7000p_write_word(state, 909, reg_909);
}
-static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
+static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
{
- struct dib7000p_state *state = demod->demodulator_priv;
u32 timf;
// store the current bandwidth for later use
- state->current_bandwidth = BW_Idx;
+ state->current_bandwidth = bw;
if (state->timf == 0) {
- dprintk("-D- Using default timf\n");
+ dprintk( "using default timf");
timf = state->cfg.bw->timf;
} else {
- dprintk("-D- Using updated timf\n");
+ dprintk( "using updated timf");
timf = state->timf;
}
- timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80;
-
- dprintk("timf: %d\n",timf);
+ timf = timf * (bw / 50) / 160;
- dib7000p_write_word(state, 23, (timf >> 16) & 0xffff);
- dib7000p_write_word(state, 24, (timf ) & 0xffff);
+ dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+ dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff));
return 0;
}
@@ -253,7 +312,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
static int dib7000p_sad_calib(struct dib7000p_state *state)
{
/* internal */
-// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
+// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
@@ -266,18 +325,37 @@ static int dib7000p_sad_calib(struct dib7000p_state *state)
return 0;
}
+int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ if (value > 4095)
+ value = 4095;
+ state->wbd_ref = value;
+ return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
+}
+
+EXPORT_SYMBOL(dib7000p_set_wbd_ref);
static void dib7000p_reset_pll(struct dib7000p_state *state)
{
struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
+ u16 clk_cfg0;
+
+ /* force PLL bypass */
+ clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
+ (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
+ (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
+ dib7000p_write_word(state, 900, clk_cfg0);
+
+ /* P_pll_cfg */
dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
- dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) |
- (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0));
+ clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
+ dib7000p_write_word(state, 900, clk_cfg0);
- dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
- dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff);
- dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff);
- dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff);
+ dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+ dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff));
+ dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
+ dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff));
dib7000p_write_word(state, 72, bw->sad_cfg);
}
@@ -285,7 +363,7 @@ static void dib7000p_reset_pll(struct dib7000p_state *state)
static int dib7000p_reset_gpio(struct dib7000p_state *st)
{
/* reset the GPIOs */
- dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
+ dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
dib7000p_write_word(st, 1029, st->gpio_dir);
dib7000p_write_word(st, 1030, st->gpio_val);
@@ -298,6 +376,120 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st)
return 0;
}
+static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
+{
+ st->gpio_dir = dib7000p_read_word(st, 1029);
+ st->gpio_dir &= ~(1 << num); /* reset the direction bit */
+ st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
+ dib7000p_write_word(st, 1029, st->gpio_dir);
+
+ st->gpio_val = dib7000p_read_word(st, 1030);
+ st->gpio_val &= ~(1 << num); /* reset the direction bit */
+ st->gpio_val |= (val & 0x01) << num; /* set the new value */
+ dib7000p_write_word(st, 1030, st->gpio_val);
+
+ return 0;
+}
+
+int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ return dib7000p_cfg_gpio(state, num, dir, val);
+}
+
+EXPORT_SYMBOL(dib7000p_set_gpio);
+static u16 dib7000p_defaults[] =
+
+{
+ // auto search configuration
+ 3, 2,
+ 0x0004,
+ 0x1000,
+ 0x0814, /* Equal Lock */
+
+ 12, 6,
+ 0x001b,
+ 0x7740,
+ 0x005b,
+ 0x8d80,
+ 0x01c9,
+ 0xc380,
+ 0x0000,
+ 0x0080,
+ 0x0000,
+ 0x0090,
+ 0x0001,
+ 0xd4c0,
+
+ 1, 26,
+ 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
+
+ /* set ADC level to -16 */
+ 11, 79,
+ (1 << 13) - 825 - 117,
+ (1 << 13) - 837 - 117,
+ (1 << 13) - 811 - 117,
+ (1 << 13) - 766 - 117,
+ (1 << 13) - 737 - 117,
+ (1 << 13) - 693 - 117,
+ (1 << 13) - 648 - 117,
+ (1 << 13) - 619 - 117,
+ (1 << 13) - 575 - 117,
+ (1 << 13) - 531 - 117,
+ (1 << 13) - 501 - 117,
+
+ 1, 142,
+ 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
+
+ /* disable power smoothing */
+ 8, 145,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ 1, 154,
+ 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
+
+ 1, 168,
+ 0x0ccd, // P_pha3_thres, default 0x3000
+
+// 1, 169,
+// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
+
+ 1, 183,
+ 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
+
+ 5, 187,
+ 0x023d, // P_adp_regul_cnt=573, default: 410
+ 0x00a4, // P_adp_noise_cnt=
+ 0x00a4, // P_adp_regul_ext
+ 0x7ff0, // P_adp_noise_ext
+ 0x3ccc, // P_adp_fil
+
+ 1, 198,
+ 0x800, // P_equal_thres_wgn
+
+ 1, 222,
+ 0x0010, // P_fec_ber_rs_len=2
+
+ 1, 235,
+ 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+ 2, 901,
+ 0x0006, // P_clk_cfg1
+ (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
+
+ 1, 905,
+ 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
+
+ 0,
+};
+
static int dib7000p_demod_reset(struct dib7000p_state *state)
{
dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
@@ -322,111 +514,307 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
dib7000p_reset_pll(state);
if (dib7000p_reset_gpio(state) != 0)
- dprintk("-E- GPIO reset was not successful.\n");
+ dprintk( "GPIO reset was not successful.");
if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
- dprintk("-E- OUTPUT_MODE could not be resetted.\n");
+ dprintk( "OUTPUT_MODE could not be reset.");
/* unforce divstr regardless whether i2c enumeration was done or not */
dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
+ dib7000p_set_bandwidth(state, 8000);
+
+ dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+ dib7000p_sad_calib(state);
+ dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+
+ // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
+ if(state->cfg.tuner_is_baseband)
+ dib7000p_write_word(state, 36,0x0755);
+ else
+ dib7000p_write_word(state, 36,0x1f55);
+
+ dib7000p_write_tab(state, dib7000p_defaults);
+
dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+
return 0;
}
+static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+{
+ u16 tmp = 0;
+ tmp = dib7000p_read_word(state, 903);
+ dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
+ tmp = dib7000p_read_word(state, 900);
+ dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
+}
+
static void dib7000p_restart_agc(struct dib7000p_state *state)
{
// P_restart_iqc & P_restart_agc
- dib7000p_write_word(state, 770, 0x0c00);
+ dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
dib7000p_write_word(state, 770, 0x0000);
}
-static void dib7000p_update_lna(struct dib7000p_state *state)
+static int dib7000p_update_lna(struct dib7000p_state *state)
{
- int i;
u16 dyn_gain;
// when there is no LNA to program return immediatly
- if (state->cfg.update_lna == NULL)
- return;
-
- for (i = 0; i < 5; i++) {
- // read dyn_gain here (because it is demod-dependent and not tuner)
+ if (state->cfg.update_lna) {
+ // read dyn_gain here (because it is demod-dependent and not fe)
dyn_gain = dib7000p_read_word(state, 394);
-
if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
dib7000p_restart_agc(state);
- msleep(5);
- } else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
+{
+ struct dibx000_agc_config *agc = NULL;
+ int i;
+ if (state->current_band == band && state->current_agc != NULL)
+ return 0;
+ state->current_band = band;
+
+ for (i = 0; i < state->cfg.agc_config_count; i++)
+ if (state->cfg.agc[i].band_caps & band) {
+ agc = &state->cfg.agc[i];
break;
+ }
+
+ if (agc == NULL) {
+ dprintk( "no valid AGC configuration found for band 0x%02x",band);
+ return -EINVAL;
}
+
+ state->current_agc = agc;
+
+ /* AGC */
+ dib7000p_write_word(state, 75 , agc->setup );
+ dib7000p_write_word(state, 76 , agc->inv_gain );
+ dib7000p_write_word(state, 77 , agc->time_stabiliz );
+ dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
+
+ // Demod AGC loop configuration
+ dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
+ dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
+
+ /* AGC continued */
+ dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
+ state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+ if (state->wbd_ref != 0)
+ dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
+ else
+ dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
+
+ dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
+
+ dib7000p_write_word(state, 107, agc->agc1_max);
+ dib7000p_write_word(state, 108, agc->agc1_min);
+ dib7000p_write_word(state, 109, agc->agc2_max);
+ dib7000p_write_word(state, 110, agc->agc2_min);
+ dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+ dib7000p_write_word(state, 112, agc->agc1_pt3);
+ dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+ dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+ dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+ return 0;
}
-static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
- u16 tmp = 0;
- tmp = dib7000p_read_word(state, 903);
- dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
- tmp = dib7000p_read_word(state, 900);
- dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
+ struct dib7000p_state *state = demod->demodulator_priv;
+ int ret = -1;
+ u8 *agc_state = &state->agc_state;
+ u8 agc_split;
+
+ switch (state->agc_state) {
+ case 0:
+ // set power-up level: interf+analog+AGC
+ dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+ dib7000p_set_adc_state(state, DIBX000_ADC_ON);
+ dib7000p_pll_clk_cfg(state);
+
+ if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+ return -1;
+
+ ret = 7;
+ (*agc_state)++;
+ break;
+
+ case 1:
+ // AGC initialization
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 1);
+
+ dib7000p_write_word(state, 78, 32768);
+ if (!state->current_agc->perform_agc_softsplit) {
+ /* we are using the wbd - so slow AGC startup */
+ /* force 0 split on WBD and restart AGC */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
+ (*agc_state)++;
+ ret = 5;
+ } else {
+ /* default AGC startup */
+ (*agc_state) = 4;
+ /* wait AGC rough lock time */
+ ret = 7;
+ }
+
+ dib7000p_restart_agc(state);
+ break;
+
+ case 2: /* fast split search path after 5sec */
+ dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
+ (*agc_state)++;
+ ret = 14;
+ break;
+
+ case 3: /* split search ended */
+ agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
+ dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
+
+ dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+ dib7000p_restart_agc(state);
+
+ dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+ (*agc_state)++;
+ ret = 5;
+ break;
+
+ case 4: /* LNA startup */
+ // wait AGC accurate lock time
+ ret = 7;
+
+ if (dib7000p_update_lna(state))
+ // wait only AGC rough lock time
+ ret = 5;
+ else // nothing was done, go to the next state
+ (*agc_state)++;
+ break;
+
+ case 5:
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 0);
+ (*agc_state)++;
+ break;
+ default:
+ break;
+ }
+ return ret;
}
-static void dib7000p_update_timf_freq(struct dib7000p_state *state)
+static void dib7000p_update_timf(struct dib7000p_state *state)
{
u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
- state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+ state->timf = timf * 160 / (state->current_bandwidth / 50);
dib7000p_write_word(state, 23, (u16) (timf >> 16));
dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
- dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+ dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
+
}
-static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
{
- u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208;
+ u16 value, est[4];
+
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
/* nfft, guard, qam, alpha */
- dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ case /* 4K MODE */ 255: value |= (2 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib7000p_write_word(state, 0, value);
dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
- /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
- tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
- if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
- tmp |= (ch->vit_code_rate_hp << 1);
- else
- tmp |= (ch->vit_code_rate_lp << 1);
- dib7000p_write_word(state, 208, tmp);
+ /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+ value = 0;
+ if (1 != 0)
+ value |= (1 << 6);
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
+ dib7000p_write_word(state, 208, value);
+
+ /* offset loop parameters */
+ dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
+ dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
+ dib7000p_write_word(state, 29, 0x1273); // isi
+ dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
/* P_dvsy_sync_wait */
- switch (ch->nfft) {
- case 1: tmp = 256; break;
- case 2: tmp = 128; break;
- case 0:
- default: tmp = 64; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_2K:
+ default: value = 64; break;
}
- tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
- tmp <<= 4;
-
- /* deactive the possibility of diversity reception if extended interleave */
- /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
- if (ch->intlv_native || ch->nfft == 1)
- tmp |= (1 << 2) | (2 << 0);
- dib7000p_write_word(state, 207, tmp);
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
- dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
- dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073
- dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
- dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
+ /* deactive the possibility of diversity reception if extended interleaver */
+ state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
+ dib7000p_set_diversity_in(&state->demod, state->div_state);
/* channel estimation fine configuration */
- switch (ch->nqam) {
- case 2:
+ switch (ch->u.ofdm.constellation) {
+ case QAM_64:
est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
break;
- case 1:
+ case QAM_16:
est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
@@ -439,66 +827,45 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_of
est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
break;
}
- for (tmp = 0; tmp < 4; tmp++)
- dib7000p_write_word(state, 187 + tmp, est[tmp]);
-
- // set power-up level: interf+analog+AGC
- dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
- dib7000p_set_adc_state(state, DIBX000_ADC_ON);
- dib7000p_pll_clk_cfg(state);
- msleep(7);
-
- // AGC initialization
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 1);
-
- dib7000p_restart_agc(state);
-
- // wait AGC rough lock time
- msleep(5);
-
- dib7000p_update_lna(state);
-
- // wait AGC accurate lock time
- msleep(7);
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 0);
+ for (value = 0; value < 4; value++)
+ dib7000p_write_word(state, 187 + value, est[value]);
}
-static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000p_state *state = demod->demodulator_priv;
- struct dibx000_ofdm_channel auto_ch;
- u32 value;
-
- INIT_OFDM_CHANNEL(&auto_ch);
- auto_ch.RF_kHz = ch->RF_kHz;
- auto_ch.Bw = ch->Bw;
- auto_ch.nqam = 2;
- auto_ch.guard = 0;
- auto_ch.nfft = 1;
- auto_ch.vit_alpha = 1;
- auto_ch.vit_select_hp = 1;
- auto_ch.vit_code_rate_hp = 2;
- auto_ch.vit_code_rate_lp = 3;
- auto_ch.vit_hrch = 0;
- auto_ch.intlv_native = 1;
-
- dib7000p_set_channel(state, &auto_ch, 7);
+ struct dvb_frontend_parameters schan;
+ u32 value, factor;
+
+ schan = *ch;
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_3_4;
+ schan.u.ofdm.hierarchy_information = 0;
+
+ dib7000p_set_channel(state, &schan, 7);
+
+ factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+ if (factor >= 5000)
+ factor = 1;
+ else
+ factor = 6;
// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
- value = 30 * state->cfg.bw->internal;
+ value = 30 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
- value = 100 * state->cfg.bw->internal;
+ value = 100 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
- value = 500 * state->cfg.bw->internal;
+ value = 500 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
value = dib7000p_read_word(state, 0);
- dib7000p_write_word(state, 0, (1 << 9) | value);
+ dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
dib7000p_read_word(state, 1284);
dib7000p_write_word(state, 0, (u16) value);
@@ -519,7 +886,95 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
return 0; // still pending
}
-static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
+{
+ static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
+ static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
+ 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
+ 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
+ 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
+ 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
+ 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
+ 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
+ 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
+ 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
+ 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
+ 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
+ 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
+ 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
+ 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
+ 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255};
+
+ u32 xtal = state->cfg.bw->xtal_hz / 1000;
+ int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz;
+ int k;
+ int coef_re[8],coef_im[8];
+ int bw_khz = bw;
+ u32 pha;
+
+ dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
+
+
+ if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
+ return;
+
+ bw_khz /= 100;
+
+ dib7000p_write_word(state, 142 ,0x0610);
+
+ for (k = 0; k < 8; k++) {
+ pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
+
+ if (pha==0) {
+ coef_re[k] = 256;
+ coef_im[k] = 0;
+ } else if(pha < 256) {
+ coef_re[k] = sine[256-(pha&0xff)];
+ coef_im[k] = sine[pha&0xff];
+ } else if (pha == 256) {
+ coef_re[k] = 0;
+ coef_im[k] = 256;
+ } else if (pha < 512) {
+ coef_re[k] = -sine[pha&0xff];
+ coef_im[k] = sine[256 - (pha&0xff)];
+ } else if (pha == 512) {
+ coef_re[k] = -256;
+ coef_im[k] = 0;
+ } else if (pha < 768) {
+ coef_re[k] = -sine[256-(pha&0xff)];
+ coef_im[k] = -sine[pha&0xff];
+ } else if (pha == 768) {
+ coef_re[k] = 0;
+ coef_im[k] = -256;
+ } else {
+ coef_re[k] = sine[pha&0xff];
+ coef_im[k] = -sine[256 - (pha&0xff)];
+ }
+
+ coef_re[k] *= notch[k];
+ coef_re[k] += (1<<14);
+ if (coef_re[k] >= (1<<24))
+ coef_re[k] = (1<<24) - 1;
+ coef_re[k] /= (1<<15);
+
+ coef_im[k] *= notch[k];
+ coef_im[k] += (1<<14);
+ if (coef_im[k] >= (1<<24))
+ coef_im[k] = (1<<24)-1;
+ coef_im[k] /= (1<<15);
+
+ dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
+
+ dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+ dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
+ dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+ }
+ dib7000p_write_word(state,143 ,0);
+}
+
+static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000p_state *state = demod->demodulator_priv;
u16 tmp = 0;
@@ -535,7 +990,15 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
msleep(45);
/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
- dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+ tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
+ if (state->sfn_workaround_active) {
+ dprintk( "SFN workaround is active");
+ tmp |= (1 << 9);
+ dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
+ } else {
+ dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
+ }
+ dib7000p_write_word(state, 29, tmp);
// never achieved a lock with that bandwidth so far - wait for osc-freq to update
if (state->timf == 0)
@@ -545,28 +1008,31 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
tmp = (6 << 8) | 0x80;
- switch (ch->nfft) {
- case 0: tmp |= (7 << 12); break;
- case 1: tmp |= (9 << 12); break;
- case 2: tmp |= (8 << 12); break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
+ case /* 4K MODE */ 255: tmp |= (8 << 12); break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
}
dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
tmp = (0 << 4);
- switch (ch->nfft) {
- case 0: tmp |= 0x6; break;
- case 1: tmp |= 0x8; break;
- case 2: tmp |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
+ case /* 4K MODE */ 255: tmp |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
dib7000p_write_word(state, 32, tmp);
/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
tmp = (0 << 4);
- switch (ch->nfft) {
- case 0: tmp |= 0x6; break;
- case 1: tmp |= 0x8; break;
- case 2: tmp |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
+ case /* 4K MODE */ 255: tmp |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
dib7000p_write_word(state, 33, tmp);
@@ -582,131 +1048,21 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
// we achieved a lock - it's time to update the osc freq
if ((tmp >> 6) & 0x1)
- dib7000p_update_timf_freq(state);
+ dib7000p_update_timf(state);
+
+ if (state->cfg.spur_protect)
+ dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
return 0;
}
-static int dib7000p_init(struct dvb_frontend *demod)
+static int dib7000p_wakeup(struct dvb_frontend *demod)
{
- struct dibx000_agc_config *agc;
struct dib7000p_state *state = demod->demodulator_priv;
- int ret = 0;
-
- // Demodulator default configuration
- agc = state->cfg.agc;
-
dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-
- /* AGC */
- ret |= dib7000p_write_word(state, 75 , agc->setup );
- ret |= dib7000p_write_word(state, 76 , agc->inv_gain );
- ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz );
- ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
-
- // Demod AGC loop configuration
- ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
- ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
-
- /* AGC continued */
- dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
- state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
-
- if (state->wbd_ref != 0)
- ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
- else
- ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
-
- ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
-
- ret |= dib7000p_write_word(state, 107, agc->agc1_max);
- ret |= dib7000p_write_word(state, 108, agc->agc1_min);
- ret |= dib7000p_write_word(state, 109, agc->agc2_max);
- ret |= dib7000p_write_word(state, 110, agc->agc2_min);
- ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
- ret |= dib7000p_write_word(state, 112, agc->agc1_pt3);
- ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
- ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
- ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
-
- /* disable power smoothing */
- ret |= dib7000p_write_word(state, 145, 0);
- ret |= dib7000p_write_word(state, 146, 0);
- ret |= dib7000p_write_word(state, 147, 0);
- ret |= dib7000p_write_word(state, 148, 0);
- ret |= dib7000p_write_word(state, 149, 0);
- ret |= dib7000p_write_word(state, 150, 0);
- ret |= dib7000p_write_word(state, 151, 0);
- ret |= dib7000p_write_word(state, 152, 0);
-
- // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
- ret |= dib7000p_write_word(state, 26 ,0x6680);
-
- // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
- ret |= dib7000p_write_word(state, 142,0x0410);
- // P_fft_freq_dir=1, P_fft_nb_to_cut=0
- ret |= dib7000p_write_word(state, 154,1 << 13);
- // P_pha3_thres, default 0x3000
- ret |= dib7000p_write_word(state, 168,0x0ccd);
- // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
- //ret |= dib7000p_write_word(state, 169,0x0010);
- // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
- ret |= dib7000p_write_word(state, 183,0x200f);
- // P_adp_regul_cnt=573, default: 410
- ret |= dib7000p_write_word(state, 187,0x023d);
- // P_adp_noise_cnt=
- ret |= dib7000p_write_word(state, 188,0x00a4);
- // P_adp_regul_ext
- ret |= dib7000p_write_word(state, 189,0x00a4);
- // P_adp_noise_ext
- ret |= dib7000p_write_word(state, 190,0x7ff0);
- // P_adp_fil
- ret |= dib7000p_write_word(state, 191,0x3ccc);
-
- ret |= dib7000p_write_word(state, 222,0x0010);
- // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
- ret |= dib7000p_write_word(state, 235,0x0062);
-
- // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
- if(state->cfg.tuner_is_baseband)
- ret |= dib7000p_write_word(state, 36,0x0755);
- else
- ret |= dib7000p_write_word(state, 36,0x1f55);
-
- // auto search configuration
- ret |= dib7000p_write_word(state, 2 ,0x0004);
- ret |= dib7000p_write_word(state, 3 ,0x1000);
-
- /* Equal Lock */
- ret |= dib7000p_write_word(state, 4 ,0x0814);
-
- ret |= dib7000p_write_word(state, 6 ,0x001b);
- ret |= dib7000p_write_word(state, 7 ,0x7740);
- ret |= dib7000p_write_word(state, 8 ,0x005b);
- ret |= dib7000p_write_word(state, 9 ,0x8d80);
- ret |= dib7000p_write_word(state, 10 ,0x01c9);
- ret |= dib7000p_write_word(state, 11 ,0xc380);
- ret |= dib7000p_write_word(state, 12 ,0x0000);
- ret |= dib7000p_write_word(state, 13 ,0x0080);
- ret |= dib7000p_write_word(state, 14 ,0x0000);
- ret |= dib7000p_write_word(state, 15 ,0x0090);
- ret |= dib7000p_write_word(state, 16 ,0x0001);
- ret |= dib7000p_write_word(state, 17 ,0xd4c0);
-
- // P_clk_cfg1
- ret |= dib7000p_write_word(state, 901, 0x0006);
-
- // P_divclksel=3 P_divbitsel=1
- ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
-
- // Tuner IO bank: max drive (14mA) + divout pads max drive
- ret |= dib7000p_write_word(state, 905, 0x2c8e);
-
- ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
- dib7000p_sad_calib(state);
-
- return ret;
+ return 0;
}
static int dib7000p_sleep(struct dvb_frontend *demod)
@@ -718,16 +1074,16 @@ static int dib7000p_sleep(struct dvb_frontend *demod)
static int dib7000p_identify(struct dib7000p_state *st)
{
u16 value;
- dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n",
+ dprintk( "checking demod on I2C address: %d (%x)",
st->i2c_addr, st->i2c_addr);
if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
- dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value);
+ dprintk( "wrong Vendor ID (read=0x%x)",value);
return -EREMOTEIO;
}
if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
- dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value);
+ dprintk( "wrong Device ID (%x)",value);
return -EREMOTEIO;
}
@@ -797,41 +1153,48 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib7000p_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
+ int time;
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+ /* maybe the parameter has been changed */
+ state->sfn_workaround_active = buggy_sfn_workaround;
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, fep);
+ /* start up the AGC */
+ state->agc_state = 0;
+ do {
+ time = dib7000p_agc_startup(fe, fep);
+ if (time != -1)
+ msleep(time);
+ } while (time != -1);
+
if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
fep->u.ofdm.constellation == QAM_AUTO ||
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 800, found;
- dib7000p_autosearch_start(fe, &ch);
+ dib7000p_autosearch_start(fe, fep);
do {
msleep(1);
found = dib7000p_autosearch_is_irq(fe);
} while (found == 0 && i--);
- dprintk("autosearch returns: %d\n",found);
+ dprintk("autosearch returns: %d",found);
if (found == 0 || found == 1)
return 0; // no channel found
dib7000p_get_frontend(fe, fep);
- FEP2DIB(fep, &ch);
}
/* make this a config parameter */
dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib7000p_tune(fe, &ch);
+ return dib7000p_tune(fe, fep);
}
static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -909,7 +1272,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
if (i2c_transfer(i2c_adap, msg, 2) == 2)
if (rx[0] == 0x01 && rx[1] == 0xb3) {
- dprintk("-D- DiB7000PC detected\n");
+ dprintk("-D- DiB7000PC detected");
return 1;
}
@@ -917,11 +1280,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
if (i2c_transfer(i2c_adap, msg, 2) == 2)
if (rx[0] == 0x01 && rx[1] == 0xb3) {
- dprintk("-D- DiB7000PC detected\n");
+ dprintk("-D- DiB7000PC detected");
return 1;
}
- dprintk("-D- DiB7000PC not detected\n");
+ dprintk("-D- DiB7000PC not detected");
return 0;
}
EXPORT_SYMBOL(dib7000pc_detection);
@@ -959,7 +1322,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
/* set new i2c address and force divstart */
dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
- dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+ dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
}
for (k = 0; k < no_of_demods; k++) {
@@ -1030,7 +1393,7 @@ static struct dvb_frontend_ops dib7000p_ops = {
.release = dib7000p_release,
- .init = dib7000p_init,
+ .init = dib7000p_wakeup,
.sleep = dib7000p_sleep,
.set_frontend = dib7000p_set_frontend,
diff --git a/linux/drivers/media/dvb/frontends/dib7000p.h b/linux/drivers/media/dvb/frontends/dib7000p.h
index 94829c1ed..eefcac8b5 100644
--- a/linux/drivers/media/dvb/frontends/dib7000p.h
+++ b/linux/drivers/media/dvb/frontends/dib7000p.h
@@ -9,6 +9,7 @@ struct dib7000p_config {
u8 tuner_is_baseband;
int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+ u8 agc_config_count;
struct dibx000_agc_config *agc;
struct dibx000_bandwidth_config *bw;
@@ -27,20 +28,19 @@ struct dib7000p_config {
u8 quartz_direct;
+ u8 spur_protect;
+
int (*agc_control) (struct dvb_frontend *, u8 before);
};
#define DEFAULT_DIB7000P_I2C_ADDRESS 18
extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+
extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
-/* TODO
-extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
-extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod);
-extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
-extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod);
-*/
+extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
#endif
diff --git a/linux/drivers/media/dvb/frontends/dibx000_common.h b/linux/drivers/media/dvb/frontends/dibx000_common.h
index a1df60436..5e17275af 100644
--- a/linux/drivers/media/dvb/frontends/dibx000_common.h
+++ b/linux/drivers/media/dvb/frontends/dibx000_common.h
@@ -111,6 +111,8 @@ struct dibx000_bandwidth_config {
u32 ifreq;
u32 timf;
+
+ u32 xtal_hz;
};
enum dibx000_adc_states {
@@ -122,56 +124,17 @@ enum dibx000_adc_states {
DIBX000_VBG_DISABLE,
};
-#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \
+#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \
(v) == BANDWIDTH_7_MHZ ? 7000 : \
(v) == BANDWIDTH_6_MHZ ? 6000 : 8000 )
/* Chip output mode. */
-#define OUTMODE_HIGH_Z 0
-#define OUTMODE_MPEG2_PAR_GATED_CLK 1
-#define OUTMODE_MPEG2_PAR_CONT_CLK 2
-#define OUTMODE_MPEG2_SERIAL 7
-#define OUTMODE_DIVERSITY 4
-#define OUTMODE_MPEG2_FIFO 5
-
-/* I hope I can get rid of the following kludge in the near future */
-struct dibx000_ofdm_channel {
- u32 RF_kHz;
- u8 Bw;
- s16 nfft;
- s16 guard;
- s16 nqam;
- s16 vit_hrch;
- s16 vit_select_hp;
- s16 vit_alpha;
- s16 vit_code_rate_hp;
- s16 vit_code_rate_lp;
- u8 intlv_native;
-};
-
-#define FEP2DIB(fep,ch) \
- (ch)->RF_kHz = (fep)->frequency / 1000; \
- (ch)->Bw = (fep)->u.ofdm.bandwidth; \
- (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
- (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
- (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \
- (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \
- (ch)->vit_select_hp = 1; \
- (ch)->vit_alpha = 1; \
- (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
- (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \
- (ch)->intlv_native = 1;
-
-#define INIT_OFDM_CHANNEL(ch) do {\
- (ch)->Bw = 0; \
- (ch)->nfft = -1; \
- (ch)->guard = -1; \
- (ch)->nqam = -1; \
- (ch)->vit_hrch = -1; \
- (ch)->vit_select_hp = -1; \
- (ch)->vit_alpha = -1; \
- (ch)->vit_code_rate_hp = -1; \
- (ch)->vit_code_rate_lp = -1; \
-} while (0)
+#define OUTMODE_HIGH_Z 0
+#define OUTMODE_MPEG2_PAR_GATED_CLK 1
+#define OUTMODE_MPEG2_PAR_CONT_CLK 2
+#define OUTMODE_MPEG2_SERIAL 7
+#define OUTMODE_DIVERSITY 4
+#define OUTMODE_MPEG2_FIFO 5
+#define OUTMODE_ANALOG_ADC 6
#endif
diff --git a/linux/drivers/media/dvb/frontends/mt2266.c b/linux/drivers/media/dvb/frontends/mt2266.c
index 145135778..33b388e8f 100644
--- a/linux/drivers/media/dvb/frontends/mt2266.c
+++ b/linux/drivers/media/dvb/frontends/mt2266.c
@@ -159,7 +159,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
b[3] = tune >> 13;
mt2266_writeregs(priv,b,4);
- dprintk("set_parms: tune=%d band=%d\n",(int)tune,(int)lnaband);
+ dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
b[0] = 0x05;
@@ -176,7 +176,7 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
msleep(10);
i++;
} while (i<10);
- dprintk("Lock when i=%i\n",(int)i);
+ dprintk("Lock when i=%i",(int)i);
return ret;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h
index f4fe889d9..a6a52bae7 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.h
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.h
@@ -538,6 +538,7 @@ struct yuv_frame_info
u32 tru_w;
u32 tru_h;
u32 offset_y;
+ int lace_mode;
};
#define IVTV_YUV_MODE_INTERLACED 0x00
@@ -610,7 +611,6 @@ struct yuv_playback_info
int decode_height;
int frame_interlaced;
- int frame_interlaced_last;
int lace_mode;
int lace_threshold;
@@ -621,6 +621,11 @@ struct yuv_playback_info
u32 yuv_forced_update;
int update_frame;
+
+ int sync_field[4]; /* Field to sync on */
+ int field_delay[4]; /* Flag to extend duration of previous frame */
+ u8 fields_lapsed; /* Counter used when delaying a frame */
+
struct yuv_frame_info new_frame_info[4];
struct yuv_frame_info old_frame_info;
struct yuv_frame_info old_frame_info_args;
diff --git a/linux/drivers/media/video/ivtv/ivtv-fb.c b/linux/drivers/media/video/ivtv/ivtv-fb.c
index 00765da8a..d2cc03172 100644
--- a/linux/drivers/media/video/ivtv/ivtv-fb.c
+++ b/linux/drivers/media/video/ivtv/ivtv-fb.c
@@ -164,11 +164,6 @@ MODULE_LICENSE("GPL");
#define IVTV_OSD_BPP_32 0x04
struct osd_info {
- /* Timing info for modes */
- u32 pixclock;
- u32 hlimit;
- u32 vlimit;
-
/* Physical base address */
unsigned long video_pbase;
/* Relative base address (relative to start of decoder memory) */
@@ -579,10 +574,25 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
{
struct osd_info *oi = itv->osd_info;
- int osd_height_limit = itv->is_50hz ? 576 : 480;
+ int osd_height_limit;
+ u32 pixclock, hlimit, vlimit;
IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
+ /* Set base references for mode calcs. */
+ if (itv->is_50hz) {
+ pixclock = 84316;
+ hlimit = 776;
+ vlimit = 591;
+ osd_height_limit = 576;
+ }
+ else {
+ pixclock = 83926;
+ hlimit = 776;
+ vlimit = 495;
+ osd_height_limit = 480;
+ }
+
/* Check the bits per pixel */
if (osd_compat) {
if (var->bits_per_pixel != 32) {
@@ -723,8 +733,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
}
/* Maintain overall 'size' for a constant refresh rate */
- var->right_margin = oi->hlimit - var->left_margin - var->xres;
- var->lower_margin = oi->vlimit - var->upper_margin - var->yres;
+ var->right_margin = hlimit - var->left_margin - var->xres;
+ var->lower_margin = vlimit - var->upper_margin - var->yres;
/* Fixed sync times */
var->hsync_len = 24;
@@ -733,9 +743,10 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
/* Non-interlaced / interlaced mode is used to switch the OSD filter
on or off. Adjust the clock timings to maintain a constant
vertical refresh rate. */
- var->pixclock = oi->pixclock;
if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
- var->pixclock /= 2;
+ var->pixclock = pixclock / 2;
+ else
+ var->pixclock = pixclock;
IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
var->xres, var->yres,
@@ -875,18 +886,6 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
struct v4l2_rect start_window;
int max_height;
- /* Set base references for mode calcs. */
- if (itv->is_50hz) {
- oi->pixclock = 84316;
- oi->hlimit = 776;
- oi->vlimit = 591;
- }
- else {
- oi->pixclock = 83926;
- oi->hlimit = 776;
- oi->vlimit = 495;
- }
-
/* Color mode */
if (osd_compat) osd_depth = 32;
diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
index e3a05f8fd..d865e3ec5 100644
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -1202,6 +1202,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+ ivtv_set_osd_alpha(itv);
break;
}
@@ -1246,7 +1247,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
IVTV_INFO("Tuner: %s\n",
test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
cx2341x_log_status(&itv->params, itv->name);
- IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
+ IVTV_INFO("Version: %s Status flags: 0x%08lx\n", IVTV_VERSION, itv->i_flags);
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
struct ivtv_stream *s = &itv->streams[i];
diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c
index 405f7e4b7..65622c1e4 100644
--- a/linux/drivers/media/video/ivtv/ivtv-irq.c
+++ b/linux/drivers/media/video/ivtv/ivtv-irq.c
@@ -704,17 +704,21 @@ static void ivtv_irq_vsync(struct ivtv *itv)
if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
- if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) ||
+ if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
+ ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
(frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) {
int next_dma_frame = last_dma_frame;
- if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
- write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
- write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
- write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
- write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
- next_dma_frame = (next_dma_frame + 1) & 0x3;
- atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+ if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {
+ if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
+ write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
+ write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+ write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
+ write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+ next_dma_frame = (next_dma_frame + 1) & 0x3;
+ atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+ itv->yuv_info.fields_lapsed = -1;
+ }
}
}
if (frame != (itv->lastVsyncFrame & 1)) {
@@ -755,6 +759,8 @@ static void ivtv_irq_vsync(struct ivtv *itv)
set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
}
}
+
+ itv->yuv_info.fields_lapsed ++;
}
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-yuv.c b/linux/drivers/media/video/ivtv/ivtv-yuv.c
index bcea09542..fa8c76f3d 100644
--- a/linux/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/linux/drivers/media/video/ivtv/ivtv-yuv.c
@@ -612,7 +612,6 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
itv->yuv_info.v_filter_2 = v_filter_2;
}
- itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced;
}
/* Modify the supplied coordinate information to fit the visible osd area */
@@ -799,6 +798,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
(itv->yuv_info.old_frame_info.src_y != window->src_y) ||
(itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
(itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
+ (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
(itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
(itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
@@ -898,8 +898,21 @@ static void ivtv_yuv_init (struct ivtv *itv)
itv->yuv_info.decode_height = 480;
/* If no visible size set, assume full size */
- if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
- if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+ if (!itv->yuv_info.osd_vis_w)
+ itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
+
+ if (!itv->yuv_info.osd_vis_h) {
+ itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+ } else {
+ /* If output video standard has changed, requested height may
+ not be legal */
+ if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) {
+ IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+ itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset,
+ itv->yuv_info.decode_height);
+ itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+ }
+ }
/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
@@ -927,6 +940,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
int rc = 0;
int got_sig = 0;
int frame, next_fill_frame, last_fill_frame;
+ int register_update = 0;
IVTV_DEBUG_INFO("yuv_prep_frame\n");
@@ -940,6 +954,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
/* Buffers are full - Overwrite the last frame */
next_fill_frame = frame;
frame = (frame - 1) & 3;
+ register_update = itv->yuv_info.new_frame_info[frame].update;
}
/* Take a snapshot of the yuv coordinate information */
@@ -955,6 +970,9 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
+ /* Snapshot field order */
+ itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
+
/* Are we going to offset the Y plane */
if (args->src.height + args->src.top < 512-16)
itv->yuv_info.new_frame_info[frame].offset_y = 1;
@@ -970,6 +988,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
itv->yuv_info.new_frame_info[frame].update = 0;
itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
+ itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
sizeof (itv->yuv_info.new_frame_info[frame]))) {
@@ -978,6 +997,14 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
}
+ itv->yuv_info.new_frame_info[frame].update |= register_update;
+
+ /* Should this frame be delayed ? */
+ if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
+ itv->yuv_info.field_delay[frame] = 1;
+ else
+ itv->yuv_info.field_delay[frame] = 0;
+
/* DMA the frame */
mutex_lock(&itv->udma.lock);