Signed-off-by: Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
@@ -58,6 +58,7 @@ struct au8522_config {
enum au8522_if_freq vsb_if;
enum au8522_if_freq qam_if;
+ int flakiness;
};
#if defined(CONFIG_DVB_AU8522) || \
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/time.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "au8522.h"
@@ -36,6 +37,7 @@ static int debug;
static LIST_HEAD(hybrid_tuner_instance_list);
static DEFINE_MUTEX(au8522_list_mutex);
+#define LOCK_DELAY 1
#define dprintk(arg...)\
do { if (debug)\
printk(arg);\
@@ -606,6 +608,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe,
return ret;
state->current_frequency = p->frequency;
+ state->lock_time = get_seconds() + LOCK_DELAY;
return 0;
}
@@ -623,6 +626,7 @@ int au8522_init(struct dvb_frontend *fe)
chip, so that when it gets powered back up it won't think
that it is already tuned */
state->current_frequency = 0;
+ state->lock_time = (unsigned long)-1L;
au8522_writereg(state, 0xa4, 1 << 5);
@@ -736,6 +740,7 @@ int au8522_sleep(struct dvb_frontend *fe)
au8522_writereg(state, 0xa4, 1 << 5);
state->current_frequency = 0;
+ state->lock_time = (unsigned long)-1L;
return 0;
}
@@ -752,15 +757,20 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
dprintk("%s() Checking VSB_8\n", __func__);
reg = au8522_readreg(state, 0x4088);
if ((reg & 0x03) == 0x03)
- *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC | FE_HAS_VITERBI;
} else {
dprintk("%s() Checking QAM\n", __func__);
reg = au8522_readreg(state, 0x4541);
if (reg & 0x80)
*status |= FE_HAS_VITERBI;
if (reg & 0x20)
- *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+ *status |= FE_HAS_SYNC;
}
+ if (*status & FE_HAS_SYNC && (!state->config->flakiness || (*status &
+ FE_HAS_VITERBI && state->lock_time < get_seconds())))
+ *status |= FE_HAS_LOCK;
+ else if (~(*status | ~(FE_HAS_SYNC | FE_HAS_VITERBI)))
+ state->lock_time = get_seconds() + LOCK_DELAY;
switch (state->config->status_mode) {
case AU8522_DEMODLOCKING:
@@ -786,7 +796,7 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
}
state->fe_status = *status;
- if (*status & FE_HAS_LOCK)
+ if (*status & FE_HAS_SYNC)
/* turn on LED, if it isn't on already */
au8522_led_ctrl(state, -1);
else
@@ -53,6 +53,7 @@ struct au8522_state {
struct dvb_frontend frontend;
u32 current_frequency;
+ unsigned long lock_time;
fe_modulation_t current_modulation;
u32 fe_status;
@@ -116,6 +116,15 @@ struct au0828_board au0828_boards[] = {
.tuner_addr = ADDR_UNSET,
.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
},
+ [AU0828_BOARD_SYNTEK_TELEDONGLE] = {
+ .name = "Syntek Teledongle [EXPERIMENTAL]",
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .joined_rx = 1,
+ .i2c_clk_divider = 0x4,
+ .i2c_clk_divider_tx = 0x8,
+ .i2c_clk_divider_rx = 0x20,
+ },
};
/* Tuner callback function for au0828 boards. Currently only needed
@@ -292,6 +301,22 @@ void au0828_gpio_setup(struct au0828_dev *dev)
au0828_write(dev, REG_000, 0xa0);
msleep(250);
break;
+ case AU0828_BOARD_SYNTEK_TELEDONGLE: /* FIXME */
+ au0828_write(dev, REG_003, 0x0);
+ au0828_write(dev, REG_002, 0xec);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_000, 0x0);
+ msleep(750);
+
+ au0828_write(dev, 0x601, 0x1);
+ au0828_write(dev, REG_003, 0x0);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_002, 0xec);
+ au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
+ msleep(100);
+
+ au0828_write(dev, 0x601, 0x5);
+ break;
}
}
@@ -325,6 +350,12 @@ struct usb_device_id au0828_usb_id_table[] = {
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
{ USB_DEVICE(0x2040, 0x8200),
.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
+#if 0
+ { USB_DEVICE(0x05e1, 0x0400),
+ .driver_info = AU0828_BOARD_SYNTEK_TELEDONGLE },
+#endif
+ { USB_DEVICE(0x05e1, 0x0480),
+ .driver_info = AU0828_BOARD_SYNTEK_TELEDONGLE },
{ },
};
@@ -25,3 +25,4 @@
#define AU0828_BOARD_DVICO_FUSIONHDTV7 3
#define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL 4
#define AU0828_BOARD_HAUPPAUGE_WOODBURY 5
+#define AU0828_BOARD_SYNTEK_TELEDONGLE 6
@@ -30,12 +30,17 @@
#include "xc5000.h"
#include "mxl5007t.h"
#include "tda18271.h"
+#include "mt2131.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define _AU0828_BULKPIPE 0x83
#define _BULKPIPESIZE 0xe522
+static int flakiness = -1;
+module_param(flakiness, int, 0644);
+MODULE_PARM_DESC(flakiness, "override whether to delay signal lock report");
+
static u8 hauppauge_hvr950q_led_states[] = {
0x00, /* off */
0x02, /* yellow */
@@ -92,6 +97,17 @@ static struct tda18271_config hauppauge_woodbury_tunerconfig = {
.gate = TDA18271_GATE_DIGITAL,
};
+static struct mt2131_config syntek_mt2130_tunerconfig = {
+ 0x60
+};
+
+static struct au8522_config syntek_teledongle_config = {
+ .demod_address = 0x8e >> 1,
+ .status_mode = AU8522_DEMODLOCKING,
+ .qam_if = AU8522_IF_6MHZ,
+ .vsb_if = AU8522_IF_6MHZ,
+};
+
/*-------------------------------------------------------------------*/
static void urb_completion(struct urb *purb)
{
@@ -381,16 +397,22 @@ int au0828_dvb_register(struct au0828_dev *dev)
switch (dev->boardnr) {
case AU0828_BOARD_HAUPPAUGE_HVR850:
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ memcpy(&dvb->demod_cfg, &hauppauge_hvr950q_config,
+ sizeof(struct au8522_config));
+
dvb->frontend = dvb_attach(au8522_attach,
- &hauppauge_hvr950q_config,
+ &dvb->demod_cfg,
&dev->i2c_adap);
if (dvb->frontend != NULL)
dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap,
&hauppauge_hvr950q_tunerconfig);
break;
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+ memcpy(&dvb->demod_cfg, &hauppauge_hvr950q_config,
+ sizeof(struct au8522_config));
+
dvb->frontend = dvb_attach(au8522_attach,
- &hauppauge_hvr950q_config,
+ &dvb->demod_cfg,
&dev->i2c_adap);
if (dvb->frontend != NULL)
dvb_attach(mxl5007t_attach, dvb->frontend,
@@ -398,8 +420,11 @@ int au0828_dvb_register(struct au0828_dev *dev)
&mxl5007t_hvr950q_config);
break;
case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+ memcpy(&dvb->demod_cfg, &hauppauge_woodbury_config,
+ sizeof(struct au8522_config));
+
dvb->frontend = dvb_attach(au8522_attach,
- &hauppauge_woodbury_config,
+ &dvb->demod_cfg,
&dev->i2c_adap);
if (dvb->frontend != NULL)
dvb_attach(tda18271_attach, dvb->frontend,
@@ -407,8 +432,11 @@ int au0828_dvb_register(struct au0828_dev *dev)
&hauppauge_woodbury_tunerconfig);
break;
case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ memcpy(&dvb->demod_cfg, &fusionhdtv7usb_config,
+ sizeof(struct au8522_config));
+
dvb->frontend = dvb_attach(au8522_attach,
- &fusionhdtv7usb_config,
+ &dvb->demod_cfg,
&dev->i2c_adap);
if (dvb->frontend != NULL) {
dvb_attach(xc5000_attach, dvb->frontend,
@@ -416,6 +444,36 @@ int au0828_dvb_register(struct au0828_dev *dev)
&hauppauge_hvr950q_tunerconfig);
}
break;
+ case AU0828_BOARD_SYNTEK_TELEDONGLE:
+ /* hauppauge_woodbury_config is used for TDA18271c2 + AU8522
+ * frontends, but we will need to use a different configuration
+ * if the tuner is an MT2131 rather than TDA18271 */
+ memcpy(&dvb->demod_cfg, &hauppauge_woodbury_config,
+ sizeof(struct au8522_config));
+
+ dvb->demod_cfg.flakiness = 1;
+ dvb->frontend = dvb_attach(au8522_attach,
+ &dvb->demod_cfg, &dev->i2c_adap);
+ if (dvb->frontend != NULL) {
+ if (dvb_attach(tda18271_attach, dvb->frontend,
+ 0x60, &dev->i2c_adap,
+ &hauppauge_woodbury_tunerconfig) != NULL)
+ break;
+ /* FIXME:
+ * I have tested various au8522 configurations in
+ * combination with the mt2131. The driver finds the
+ * hardware and attaches correctly, but it is unable
+ * to lock on to any services. */
+ if (dvb_attach(mt2131_attach, dvb->frontend,
+ &dev->i2c_adap,
+ &syntek_mt2130_tunerconfig, 0) != NULL)
+ /* replace the demod configuration with the
+ * AU8522 + MT2131 configuration */
+ memcpy(&dvb->demod_cfg,
+ &syntek_teledongle_config,
+ sizeof(struct au8522_config));
+ }
+ break;
default:
printk(KERN_WARNING "The frontend of your DVB/ATSC card "
"isn't supported yet\n");
@@ -426,6 +484,8 @@ int au0828_dvb_register(struct au0828_dev *dev)
__func__);
return -1;
}
+ if (flakiness + 1)
+ dvb->demod_cfg.flakiness = flakiness;
/* define general-purpose callback pointer */
dvb->frontend->callback = au0828_tuner_callback;
@@ -141,13 +141,16 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
{
int i, strobe = 0;
struct au0828_dev *dev = i2c_adap->algo_data;
+ unsigned char clk_divider = joined_rlen ?
+ dev->board.i2c_clk_divider_rx : dev->board.i2c_clk_divider_tx;
dprintk(4, "%s()\n", __func__);
au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
/* Set the I2C clock */
- au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+ au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, clk_divider &&
+ msg->addr == 0x60 ? clk_divider :
dev->board.i2c_clk_divider);
/* Hardware needs 8 bit addresses */
@@ -204,7 +207,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
}
}
- if (!i2c_wait_done(i2c_adap))
+ if (!(joined_rlen && dev->board.joined_rx) && !i2c_wait_done(i2c_adap))
return -EIO;
dprintk(4, "\n");
@@ -221,14 +224,18 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
dprintk(4, "%s()\n", __func__);
- au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
+ if (!joined || !dev->board.joined_rx) {
+ au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
- /* Set the I2C clock */
- au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
- dev->board.i2c_clk_divider);
+ /* Set the I2C clock */
+ au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+ dev->board.i2c_clk_divider_rx && msg->addr ==
+ 0x60 ? dev->board.i2c_clk_divider_rx :
+ dev->board.i2c_clk_divider);
- /* Hardware needs 8 bit addresses */
- au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
+ }
dprintk(4, " RECV:\n");
@@ -40,6 +40,8 @@
#include "au0828-reg.h"
#include "au0828-cards.h"
+#include "au8522.h"
+
#define DRIVER_NAME "au0828"
#define URB_COUNT 16
#define URB_BUFSIZE (0xe522)
@@ -79,9 +81,9 @@ struct au0828_input {
struct au0828_board {
char *name;
- unsigned int tuner_type;
+ unsigned int tuner_type, joined_rx;
unsigned char tuner_addr;
- unsigned char i2c_clk_divider;
+ unsigned char i2c_clk_divider, i2c_clk_divider_rx, i2c_clk_divider_tx;
struct au0828_input input[AU0828_MAX_INPUT];
};
@@ -95,6 +97,7 @@ struct au0828_dvb {
struct dmx_frontend fe_hw;
struct dmx_frontend fe_mem;
struct dvb_net net;
+ struct au8522_config demod_cfg;
int feeding;
};