Add support for DD DuoFlex C/C2/T/T2 Expansion card. These are for
card revision that has Sony CXD2843ER, CXD2837ER or CXD2838ER
ISDB-T demodulator.

Signed-off-by: Antti Palosaari <[email protected]>
---
 drivers/media/pci/ddbridge/Kconfig         |   2 +
 drivers/media/pci/ddbridge/ddbridge-core.c | 127 +++++++++++++++++++++++++++++
 drivers/media/pci/ddbridge/ddbridge.h      |   3 +
 3 files changed, 132 insertions(+)

diff --git a/drivers/media/pci/ddbridge/Kconfig 
b/drivers/media/pci/ddbridge/Kconfig
index 44e5dc1..15f33a2 100644
--- a/drivers/media/pci/ddbridge/Kconfig
+++ b/drivers/media/pci/ddbridge/Kconfig
@@ -6,6 +6,8 @@ config DVB_DDBRIDGE
        select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT
        select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
        select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_CXD2843 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
        ---help---
          Support for cards with the Digital Devices PCI express bridge:
          - Octopus PCIe Bridge
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c 
b/drivers/media/pci/ddbridge/ddbridge-core.c
index da8f848..9f5837f 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -43,6 +43,8 @@
 #include "stv090x.h"
 #include "lnbh24.h"
 #include "drxk.h"
+#include "cxd2843.h"
+#include "tda18212.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
@@ -78,6 +80,21 @@ static int i2c_read_reg16(struct i2c_adapter *adapter, u8 
adr,
        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_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;
@@ -592,6 +609,30 @@ static int demod_attach_drxk(struct ddb_input *input)
        return 0;
 }
 
+static int demod_attach_cxd2843(struct ddb_input *input)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct dvb_frontend *fe;
+       struct cxd2843_cfg cxd2843_0 = {
+               .adr = 0x6c,
+       };
+       struct cxd2843_cfg cxd2843_1 = {
+               .adr = 0x6d,
+       };
+
+       fe = input->fe = dvb_attach(cxd2843_attach, i2c,
+                                 (input->nr & 1) ?
+                                 &cxd2843_1 : &cxd2843_0);
+       if (!input->fe) {
+               pr_err("No cxd2837/38/43 found!\n");
+               return -ENODEV;
+       }
+       fe->sec_priv = input;
+       input->gate_ctrl = fe->ops.i2c_gate_ctrl;
+       fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+       return 0;
+}
+
 static int tuner_attach_tda18271(struct ddb_input *input)
 {
        struct i2c_adapter *i2c = &input->port->i2c->adap;
@@ -609,6 +650,47 @@ static int tuner_attach_tda18271(struct ddb_input *input)
        return 0;
 }
 
+static struct tda18212_config tda18212_config_60 = {
+       .i2c_address = 0x60,
+       .if_dvbt_6 = 3550,
+       .if_dvbt_7 = 3700,
+       .if_dvbt_8 = 4150,
+       .if_dvbt2_6 = 3250,
+       .if_dvbt2_7 = 4000,
+       .if_dvbt2_8 = 4000,
+       .if_dvbc = 5000,
+};
+
+static struct tda18212_config tda18212_config_63 = {
+       .i2c_address = 0x63,
+       .if_dvbt_6 = 3550,
+       .if_dvbt_7 = 3700,
+       .if_dvbt_8 = 4150,
+       .if_dvbt2_6 = 3250,
+       .if_dvbt2_7 = 4000,
+       .if_dvbt2_8 = 4000,
+       .if_dvbc = 5000,
+};
+
+static int tuner_attach_tda18212(struct ddb_input *input)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct dvb_frontend *fe;
+       struct tda18212_config *config;
+
+       if (input->nr & 1)
+               config = &tda18212_config_63;
+       else
+               config = &tda18212_config_60;
+
+       fe = dvb_attach(tda18212_attach, input->fe, i2c, config);
+       if (!fe) {
+               pr_err("No TDA18212 found!\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
 
/******************************************************************************/
 
/******************************************************************************/
 
/******************************************************************************/
@@ -887,6 +969,18 @@ static int dvb_input_attach(struct ddb_input *input)
                               sizeof(struct dvb_tuner_ops));
                }
                break;
+       case DDB_TUNER_DVBCT2_SONY:
+       case DDB_TUNER_DVBC2T2_SONY:
+       case DDB_TUNER_ISDBT_SONY:
+               if (demod_attach_cxd2843(input) < 0)
+                       return -ENODEV;
+               if (tuner_attach_tda18212(input) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               break;
        }
        input->attached = 5;
        return 0;
@@ -1170,10 +1264,24 @@ static int port_has_drxks(struct ddb_port *port)
        return 1;
 }
 
+static int port_has_cxd28xx(struct ddb_port *port, u8 *id)
+{
+       int status;
+
+       status = i2c_write_reg(&port->i2c->adap, 0x6e, 0, 0);
+       if (status)
+               return 0;
+       status = i2c_read_reg(&port->i2c->adap, 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 id;
 
        port->class = DDB_PORT_NONE;
 
@@ -1196,6 +1304,25 @@ static void ddb_port_probe(struct ddb_port *port)
                port->class = DDB_PORT_TUNER;
                port->type = DDB_TUNER_DVBCT_TR;
                ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+       } else if (port_has_cxd28xx(port, &id)) {
+               switch (id) {
+               case 0xa4:
+                       modname = "DUAL DVB-C2T2 CXD2843";
+                       port->type = DDB_TUNER_DVBC2T2_SONY;
+                       break;
+               case 0xb1:
+                       modname = "DUAL DVB-CT2 CXD2837";
+                       port->type = DDB_TUNER_DVBCT2_SONY;
+                       break;
+               case 0xb0:
+                       modname = "DUAL ISDB-T CXD2838";
+                       port->type = DDB_TUNER_ISDBT_SONY;
+                       break;
+               default:
+                       return;
+               }
+               port->class = DDB_PORT_TUNER;
+               ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
        }
        printk(KERN_INFO "Port %d (TAB %d): %s\n",
                         port->nr, port->nr+1, modname);
diff --git a/drivers/media/pci/ddbridge/ddbridge.h 
b/drivers/media/pci/ddbridge/ddbridge.h
index 8b1b41d..04c56c2 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -147,6 +147,9 @@ 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_DVBCT2_SONY  18
+#define DDB_TUNER_ISDBT_SONY   19
+#define DDB_TUNER_DVBC2T2_SONY 20
        u32                    adr;
 
        struct ddb_input      *input[2];
-- 
http://palosaari.fi/

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to