diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index fef9932d071c4f919352a5f986d6b572d97d18f2..1ec49621349c797e515a4529398becf8ef499c6f 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -43,6 +43,10 @@
 #include "stv0367_priv.h"
 #include "tda18212.h"
 
+static int xo2_speed = 2;
+module_param(xo2_speed, int, 0444);
+MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards");
+
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* MSI had problems with lost interrupts, fixed but needs testing */
@@ -50,6 +54,24 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /******************************************************************************/
 
+static int i2c_io(struct i2c_adapter *adapter, u8 adr,
+		  u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
+{
+	struct i2c_msg msgs[2] = {{.addr = adr,  .flags = 0,
+				   .buf  = wbuf, .len   = wlen },
+				  {.addr = adr,  .flags = I2C_M_RD,
+				   .buf  = rbuf,  .len   = rlen } };
+	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+{
+	struct i2c_msg msg = {.addr = adr, .flags = 0,
+			      .buf = data, .len = len};
+
+	return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1;
+}
+
 static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
 {
 	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
@@ -83,6 +105,14 @@ static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
 	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
 }
 
+static int i2c_write_reg(struct i2c_adapter *adap, u8 adr,
+			 u8 reg, u8 val)
+{
+	u8 msg[2] = {reg, val};
+
+	return i2c_write(adap, adr, msg, 2);
+}
+
 static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
 {
 	struct ddb *dev = i2c->dev;
@@ -1273,6 +1303,70 @@ static void ddb_ports_detach(struct ddb *dev)
 /****************************************************************************/
 /****************************************************************************/
 
+static int init_xo2(struct ddb_port *port)
+{
+	struct i2c_adapter *i2c = &port->i2c->adap;
+	u8 val, data[2];
+	int res;
+
+	res = i2c_read_regs(i2c, 0x10, 0x04, data, 2);
+	if (res < 0)
+		return res;
+
+	if (data[0] != 0x01)  {
+		pr_info("Port %d: invalid XO2\n", port->nr);
+		return -1;
+	}
+
+	i2c_read_reg(i2c, 0x10, 0x08, &val);
+	if (val != 0) {
+		i2c_write_reg(i2c, 0x10, 0x08, 0x00);
+		msleep(100);
+	}
+	/* Enable tuner power, disable pll, reset demods */
+	i2c_write_reg(i2c, 0x10, 0x08, 0x04);
+	usleep_range(2000, 3000);
+	/* Release demod resets */
+	i2c_write_reg(i2c, 0x10, 0x08, 0x07);
+
+	/* speed: 0=55,1=75,2=90,3=104 MBit/s */
+	i2c_write_reg(i2c, 0x10, 0x09,
+		((xo2_speed >= 0 && xo2_speed <= 3) ? xo2_speed : 2));
+
+	i2c_write_reg(i2c, 0x10, 0x0a, 0x01);
+	i2c_write_reg(i2c, 0x10, 0x0b, 0x01);
+
+	usleep_range(2000, 3000);
+	/* Start XO2 PLL */
+	i2c_write_reg(i2c, 0x10, 0x08, 0x87);
+
+	return 0;
+}
+
+static int port_has_xo2(struct ddb_port *port, u8 *type, u8 *id)
+{
+	u8 probe[1] = { 0x00 }, data[4];
+
+	*type = DDB_XO2_TYPE_NONE;
+
+	if (i2c_io(&port->i2c->adap, 0x10, probe, 1, data, 4))
+		return 0;
+	if (data[0] == 'D' && data[1] == 'F') {
+		*id = data[2];
+		*type = DDB_XO2_TYPE_DUOFLEX;
+		return 1;
+	}
+	if (data[0] == 'C' && data[1] == 'I') {
+		*id = data[2];
+		*type = DDB_XO2_TYPE_CI;
+		return 1;
+	}
+	return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
 static int port_has_ci(struct ddb_port *port)
 {
 	u8 val;
@@ -1323,6 +1417,7 @@ static void ddb_port_probe(struct ddb_port *port)
 {
 	struct ddb *dev = port->dev;
 	char *modname = "NO MODULE";
+	u8 xo2_type, xo2_id;
 
 	port->class = DDB_PORT_NONE;
 
@@ -1330,6 +1425,58 @@ static void ddb_port_probe(struct ddb_port *port)
 		modname = "CI";
 		port->class = DDB_PORT_CI;
 		ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+	} else if (port_has_xo2(port, &xo2_type, &xo2_id)) {
+		printk(KERN_INFO "Port %d (TAB %d): XO2 type: %d, id: %d\n",
+			port->nr, port->nr+1, xo2_type, xo2_id);
+
+		ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+
+		switch (xo2_type) {
+		case DDB_XO2_TYPE_DUOFLEX:
+			init_xo2(port);
+			switch (xo2_id >> 2) {
+			case 0:
+				modname = "DUAL DVB-S2 (unsupported)";
+				port->class = DDB_PORT_NONE;
+				port->type = DDB_TUNER_XO2_DVBS_STV0910;
+				break;
+			case 1:
+				modname = "DUAL DVB-C/T/T2 (unsupported)";
+				port->class = DDB_PORT_NONE;
+				port->type = DDB_TUNER_XO2_DVBCT2_SONY;
+				break;
+			case 2:
+				modname = "DUAL DVB-ISDBT (unsupported)";
+				port->class = DDB_PORT_NONE;
+				port->type = DDB_TUNER_XO2_ISDBT_SONY;
+				break;
+			case 3:
+				modname = "DUAL DVB-C/C2/T/T2 (unsupported)";
+				port->class = DDB_PORT_NONE;
+				port->type = DDB_TUNER_XO2_DVBC2T2_SONY;
+				break;
+			case 4:
+				modname = "DUAL ATSC (unsupported)";
+				port->class = DDB_PORT_NONE;
+				port->type = DDB_TUNER_XO2_ATSC_ST;
+				break;
+			case 5:
+				modname = "DUAL DVB-C/C2/T/T2/ISDBT (unsupported)";
+				port->class = DDB_PORT_NONE;
+				port->type = DDB_TUNER_XO2_DVBC2T2I_SONY;
+				break;
+			default:
+				modname = "Unknown XO2 DuoFlex module\n";
+				break;
+			}
+			break;
+		case DDB_XO2_TYPE_CI:
+			printk(KERN_INFO "DuoFlex CI modules not supported\n");
+			break;
+		default:
+			printk(KERN_INFO "Unknown XO2 DuoFlex module\n");
+			break;
+		}
 	} else if (port_has_stv0900(port)) {
 		modname = "DUAL DVB-S2";
 		port->class = DDB_PORT_TUNER;
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 734e18eff1278efd8526eddcefb05a1291bbbc79..4e49faa7af80b0593abd736cc56c11c7a196b6b3 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -48,6 +48,10 @@
 
 #define DDB_LINK_TAG(_x) (_x << DDB_LINK_SHIFT)
 
+#define DDB_XO2_TYPE_NONE	0
+#define DDB_XO2_TYPE_DUOFLEX	1
+#define DDB_XO2_TYPE_CI		2
+
 struct ddb_info {
 	int   type;
 #define DDB_NONE         0
@@ -154,6 +158,13 @@ struct ddb_port {
 #define DDB_TUNER_DVBS_ST_AA    2
 #define DDB_TUNER_DVBCT_TR     16
 #define DDB_TUNER_DVBCT_ST     17
+#define DDB_TUNER_XO2_DVBS_STV0910	32
+#define DDB_TUNER_XO2_DVBCT2_SONY	33
+#define DDB_TUNER_XO2_ISDBT_SONY	34
+#define DDB_TUNER_XO2_DVBC2T2_SONY	35
+#define DDB_TUNER_XO2_ATSC_ST		36
+#define DDB_TUNER_XO2_DVBC2T2I_SONY	37
+
 	u32                    adr;
 
 	struct ddb_input      *input[2];