|
@@ -50,6 +50,32 @@
|
|
|
/* I2C transfer functions used for demod/tuner probing***********************/
|
|
|
/****************************************************************************/
|
|
|
|
|
|
+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_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 i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
|
|
|
{
|
|
|
struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
|
|
@@ -78,6 +104,12 @@ static int i2c_read_regs(struct i2c_adapter *adapter,
|
|
|
|
|
|
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
|
|
}
|
|
|
+
|
|
|
+static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
|
|
|
+{
|
|
|
+ return i2c_read_regs(adapter, adr, reg, val, 1);
|
|
|
+}
|
|
|
+
|
|
|
/****************************************************************************/
|
|
|
/* Demod/tuner attachment ***************************************************/
|
|
|
/****************************************************************************/
|
|
@@ -390,12 +422,98 @@ static int demod_attach_drxk(struct ngene_channel *chan,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/****************************************************************************/
|
|
|
+/* XO2 related lists and functions ******************************************/
|
|
|
+/****************************************************************************/
|
|
|
+
|
|
|
+static char __maybe_unused *xo2names[] = {
|
|
|
+ "DUAL DVB-S2",
|
|
|
+ "DUAL DVB-C/T/T2",
|
|
|
+ "DUAL DVB-ISDBT",
|
|
|
+ "DUAL DVB-C/C2/T/T2",
|
|
|
+ "DUAL ATSC",
|
|
|
+ "DUAL DVB-C/C2/T/T2/I",
|
|
|
+};
|
|
|
+
|
|
|
+static int init_xo2(struct ngene_channel *chan, struct i2c_adapter *i2c)
|
|
|
+{
|
|
|
+ struct device *pdev = &chan->dev->pci_dev->dev;
|
|
|
+ u8 addr = 0x10;
|
|
|
+ u8 val, data[2];
|
|
|
+ int res;
|
|
|
+
|
|
|
+ res = i2c_read_regs(i2c, addr, 0x04, data, 2);
|
|
|
+ if (res < 0)
|
|
|
+ return res;
|
|
|
+
|
|
|
+ if (data[0] != 0x01) {
|
|
|
+ dev_info(pdev, "Invalid XO2 on channel %d\n", chan->number);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ i2c_read_reg(i2c, addr, 0x08, &val);
|
|
|
+ if (val != 0) {
|
|
|
+ i2c_write_reg(i2c, addr, 0x08, 0x00);
|
|
|
+ msleep(100);
|
|
|
+ }
|
|
|
+ /* Enable tuner power, disable pll, reset demods */
|
|
|
+ i2c_write_reg(i2c, addr, 0x08, 0x04);
|
|
|
+ usleep_range(2000, 3000);
|
|
|
+ /* Release demod resets */
|
|
|
+ i2c_write_reg(i2c, addr, 0x08, 0x07);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * speed: 0=55,1=75,2=90,3=104 MBit/s
|
|
|
+ * Note: The ngene hardware must be run at 75 MBit/s compared
|
|
|
+ * to more modern ddbridge hardware which runs at 90 MBit/s,
|
|
|
+ * else there will be issues with the data transport and non-
|
|
|
+ * working secondary/slave demods/tuners.
|
|
|
+ */
|
|
|
+ i2c_write_reg(i2c, addr, 0x09, 1);
|
|
|
+
|
|
|
+ i2c_write_reg(i2c, addr, 0x0a, 0x01);
|
|
|
+ i2c_write_reg(i2c, addr, 0x0b, 0x01);
|
|
|
+
|
|
|
+ usleep_range(2000, 3000);
|
|
|
+ /* Start XO2 PLL */
|
|
|
+ i2c_write_reg(i2c, addr, 0x08, 0x87);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id)
|
|
|
+{
|
|
|
+ u8 probe[1] = { 0x00 }, data[4];
|
|
|
+ u8 addr = 0x10;
|
|
|
+
|
|
|
+ *type = NGENE_XO2_TYPE_NONE;
|
|
|
+
|
|
|
+ if (i2c_io(i2c, addr, probe, 1, data, 4))
|
|
|
+ return 0;
|
|
|
+ if (data[0] == 'D' && data[1] == 'F') {
|
|
|
+ *id = data[2];
|
|
|
+ *type = NGENE_XO2_TYPE_DUOFLEX;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ if (data[0] == 'C' && data[1] == 'I') {
|
|
|
+ *id = data[2];
|
|
|
+ *type = NGENE_XO2_TYPE_CI;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/****************************************************************************/
|
|
|
+/* Probing and port/channel handling ****************************************/
|
|
|
+/****************************************************************************/
|
|
|
+
|
|
|
static int cineS2_probe(struct ngene_channel *chan)
|
|
|
{
|
|
|
struct device *pdev = &chan->dev->pci_dev->dev;
|
|
|
struct i2c_adapter *i2c;
|
|
|
struct stv090x_config *fe_conf;
|
|
|
u8 buf[3];
|
|
|
+ u8 xo2_type, xo2_id;
|
|
|
struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };
|
|
|
int rc;
|
|
|
|
|
@@ -405,7 +523,31 @@ static int cineS2_probe(struct ngene_channel *chan)
|
|
|
else
|
|
|
i2c = &chan->dev->channel[1].i2c_adapter;
|
|
|
|
|
|
- if (port_has_stv0900(i2c, chan->number)) {
|
|
|
+ if (port_has_xo2(i2c, &xo2_type, &xo2_id)) {
|
|
|
+ xo2_id >>= 2;
|
|
|
+ dev_dbg(pdev, "XO2 on channel %d (type %d, id %d)\n",
|
|
|
+ chan->number, xo2_type, xo2_id);
|
|
|
+
|
|
|
+ switch (xo2_type) {
|
|
|
+ case NGENE_XO2_TYPE_DUOFLEX:
|
|
|
+ if (chan->number & 1)
|
|
|
+ dev_dbg(pdev,
|
|
|
+ "skipping XO2 init on odd channel %d",
|
|
|
+ chan->number);
|
|
|
+ else
|
|
|
+ init_xo2(chan, i2c);
|
|
|
+
|
|
|
+ /* TODO: implement support for XO2 module types */
|
|
|
+ dev_warn(pdev, "XO2 not supported\n");
|
|
|
+ return -ENODEV;
|
|
|
+ case NGENE_XO2_TYPE_CI:
|
|
|
+ dev_info(pdev, "DuoFlex CI modules not supported\n");
|
|
|
+ return -ENODEV;
|
|
|
+ default:
|
|
|
+ dev_info(pdev, "Unsupported XO2 module type\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+ } else if (port_has_stv0900(i2c, chan->number)) {
|
|
|
chan->demod_type = DEMOD_TYPE_STV090X;
|
|
|
fe_conf = chan->dev->card_info->fe_config[chan->number];
|
|
|
/* demod found, attach it */
|