#include "drxk.h"
 #include "stv0367.h"
 #include "stv0367_priv.h"
+#include "cxd2841er.h"
 #include "tda18212.h"
 
 static int xo2_speed = 2;
        return 0;
 }
 
+static int demod_attach_cxd28xx(struct ddb_input *input, int par, int osc24)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct cxd2841er_config cfg;
+
+       /* the cxd2841er driver expects 8bit/shifted I2C addresses */
+       cfg.i2c_addr = ((input->nr & 1) ? 0x6d : 0x6c) << 1;
+
+       cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500;
+       cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE |
+               CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG |
+               CXD2841ER_TSBITS;
+
+       if (!par)
+               cfg.flags |= CXD2841ER_TS_SERIAL;
+
+       /* attach frontend */
+       input->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c);
+
+       if (!input->fe) {
+               printk(KERN_ERR "No Sony CXD28xx found!\n");
+               return -ENODEV;
+       }
+
+       input->fe->sec_priv = input;
+       input->gate_ctrl = input->fe->ops.i2c_gate_ctrl;
+       input->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+       return 0;
+}
+
 static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype)
 {
        struct i2c_adapter *adapter = &input->port->i2c->adap;
        struct ddb_port *port = input->port;
        struct dvb_adapter *adap = &input->adap;
        struct dvb_demux *dvbdemux = &input->demux;
+       int sony_osc24 = 0, sony_tspar = 0;
 
        ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE,
                                   &input->port->dev->pdev->dev,
                                return -ENODEV;
                }
                break;
+       case DDB_TUNER_DVBC2T2I_SONY_P:
+       case DDB_TUNER_DVBCT2_SONY_P:
+       case DDB_TUNER_DVBC2T2_SONY_P:
+       case DDB_TUNER_ISDBT_SONY_P:
+               if (port->type == DDB_TUNER_DVBC2T2I_SONY_P)
+                       sony_osc24 = 1;
+               if (input->port->dev->info->ts_quirks & TS_QUIRK_ALT_OSC)
+                       sony_osc24 = 0;
+               if (input->port->dev->info->ts_quirks & TS_QUIRK_SERIAL)
+                       sony_tspar = 0;
+               else
+                       sony_tspar = 1;
+
+               if (demod_attach_cxd28xx(input, sony_tspar, sony_osc24) < 0)
+                       return -ENODEV;
+               if (tuner_attach_tda18212(input, port->type) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               break;
+       case DDB_TUNER_XO2_DVBC2T2I_SONY:
+       case DDB_TUNER_XO2_DVBCT2_SONY:
+       case DDB_TUNER_XO2_DVBC2T2_SONY:
+       case DDB_TUNER_XO2_ISDBT_SONY:
+               if (port->type == DDB_TUNER_XO2_DVBC2T2I_SONY)
+                       sony_osc24 = 1;
+
+               if (demod_attach_cxd28xx(input, 0, sony_osc24) < 0)
+                       return -ENODEV;
+               if (tuner_attach_tda18212(input, port->type) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               break;
        }
 
        input->attached = 5;
        return 1;
 }
 
+static int port_has_cxd28xx(struct ddb_port *port, u8 *id)
+{
+       struct i2c_adapter *i2c = &port->i2c->adap;
+       int status;
+
+       status = i2c_write_reg(&port->i2c->adap, 0x6e, 0, 0);
+       if (status)
+               return 0;
+       status = i2c_read_reg(i2c, 0x6e, 0xfd, id);
+       if (status)
+               return 0;
+       return 1;
+}
+
 static void ddb_port_probe(struct ddb_port *port)
 {
        struct ddb *dev = port->dev;
        char *modname = "NO MODULE";
-       u8 xo2_type, xo2_id;
+       u8 xo2_type, xo2_id, cxd_id;
 
        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;
+                               modname = "DUAL DVB-C/T/T2";
+                               port->class = DDB_PORT_TUNER;
                                port->type = DDB_TUNER_XO2_DVBCT2_SONY;
                                break;
                        case 2:
-                               modname = "DUAL DVB-ISDBT (unsupported)";
-                               port->class = DDB_PORT_NONE;
+                               modname = "DUAL DVB-ISDBT";
+                               port->class = DDB_PORT_TUNER;
                                port->type = DDB_TUNER_XO2_ISDBT_SONY;
                                break;
                        case 3:
-                               modname = "DUAL DVB-C/C2/T/T2 (unsupported)";
-                               port->class = DDB_PORT_NONE;
+                               modname = "DUAL DVB-C/C2/T/T2";
+                               port->class = DDB_PORT_TUNER;
                                port->type = DDB_TUNER_XO2_DVBC2T2_SONY;
                                break;
                        case 4:
                                port->type = DDB_TUNER_XO2_ATSC_ST;
                                break;
                        case 5:
-                               modname = "DUAL DVB-C/C2/T/T2/ISDBT (unsupported)";
-                               port->class = DDB_PORT_NONE;
+                               modname = "DUAL DVB-C/C2/T/T2/ISDBT";
+                               port->class = DDB_PORT_TUNER;
                                port->type = DDB_TUNER_XO2_DVBC2T2I_SONY;
                                break;
                        default:
                        printk(KERN_INFO "Unknown XO2 DuoFlex module\n");
                        break;
                }
+       } else if (port_has_cxd28xx(port, &cxd_id)) {
+               switch (cxd_id) {
+               case 0xa4:
+                       modname = "DUAL DVB-C2T2 CXD2843";
+                       port->class = DDB_PORT_TUNER;
+                       port->type = DDB_TUNER_DVBC2T2_SONY_P;
+                       break;
+               case 0xb1:
+                       modname = "DUAL DVB-CT2 CXD2837";
+                       port->class = DDB_PORT_TUNER;
+                       port->type = DDB_TUNER_DVBCT2_SONY_P;
+                       break;
+               case 0xb0:
+                       modname = "DUAL ISDB-T CXD2838";
+                       port->class = DDB_PORT_TUNER;
+                       port->type = DDB_TUNER_ISDBT_SONY_P;
+                       break;
+               case 0xc1:
+                       modname = "DUAL DVB-C2T2 ISDB-T CXD2854";
+                       port->class = DDB_PORT_TUNER;
+                       port->type = DDB_TUNER_DVBC2T2I_SONY_P;
+                       break;
+               default:
+                       modname = "Unknown CXD28xx tuner";
+                       break;
+               }
+               ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
        } else if (port_has_stv0900(port)) {
                modname = "DUAL DVB-S2";
                port->class = DDB_PORT_TUNER;