Commit e933a6f1 authored by Daniel Scheller's avatar Daniel Scheller Committed by Mauro Carvalho Chehab

[media] ddbridge: add I2C functions, add XO2 module support

Some Flex modules (mostly with anyof C/C2/T/T2 demods based on the Sony
CXD28xxER series) are equipped with an interface named XO2 (which
appears to be the Lattice MachXO2). Add functionality to detect such
links and initialise them, so any tuner module with such an interface can
be used.

This also adds dummy detection for any possible connected module, telling
the user it isn't supported at this very moment.

Also adds i2c_io(), i2c_write() and i2c_write_reg(), all required for the
XO2 handling functionality.
Signed-off-by: default avatarDaniel Scheller <d.scheller@gmx.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 1b58a5a4
...@@ -43,6 +43,10 @@ ...@@ -43,6 +43,10 @@
#include "stv0367_priv.h" #include "stv0367_priv.h"
#include "tda18212.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); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* MSI had problems with lost interrupts, fixed but needs testing */ /* MSI had problems with lost interrupts, fixed but needs testing */
...@@ -50,6 +54,24 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); ...@@ -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) static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
{ {
struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, 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, ...@@ -83,6 +105,14 @@ static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; 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) static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
{ {
struct ddb *dev = i2c->dev; struct ddb *dev = i2c->dev;
...@@ -1273,6 +1303,70 @@ static void ddb_ports_detach(struct ddb *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) static int port_has_ci(struct ddb_port *port)
{ {
u8 val; u8 val;
...@@ -1323,6 +1417,7 @@ static void ddb_port_probe(struct ddb_port *port) ...@@ -1323,6 +1417,7 @@ static void ddb_port_probe(struct ddb_port *port)
{ {
struct ddb *dev = port->dev; struct ddb *dev = port->dev;
char *modname = "NO MODULE"; char *modname = "NO MODULE";
u8 xo2_type, xo2_id;
port->class = DDB_PORT_NONE; port->class = DDB_PORT_NONE;
...@@ -1330,6 +1425,58 @@ static void ddb_port_probe(struct ddb_port *port) ...@@ -1330,6 +1425,58 @@ static void ddb_port_probe(struct ddb_port *port)
modname = "CI"; modname = "CI";
port->class = DDB_PORT_CI; port->class = DDB_PORT_CI;
ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); 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)) { } else if (port_has_stv0900(port)) {
modname = "DUAL DVB-S2"; modname = "DUAL DVB-S2";
port->class = DDB_PORT_TUNER; port->class = DDB_PORT_TUNER;
......
...@@ -48,6 +48,10 @@ ...@@ -48,6 +48,10 @@
#define DDB_LINK_TAG(_x) (_x << DDB_LINK_SHIFT) #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 { struct ddb_info {
int type; int type;
#define DDB_NONE 0 #define DDB_NONE 0
...@@ -154,6 +158,13 @@ struct ddb_port { ...@@ -154,6 +158,13 @@ struct ddb_port {
#define DDB_TUNER_DVBS_ST_AA 2 #define DDB_TUNER_DVBS_ST_AA 2
#define DDB_TUNER_DVBCT_TR 16 #define DDB_TUNER_DVBCT_TR 16
#define DDB_TUNER_DVBCT_ST 17 #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; u32 adr;
struct ddb_input *input[2]; struct ddb_input *input[2];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment