162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ngene-cards.c: nGene PCIe bridge driver - card specific info
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2005-2007 Micronas
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
862306a36Sopenharmony_ci *                         Modifications for new nGene firmware,
962306a36Sopenharmony_ci *                         support for EEPROM-copying,
1062306a36Sopenharmony_ci *                         support for new dual DVB-S2 card prototype
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/pci.h>
1862306a36Sopenharmony_ci#include <linux/pci_ids.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "ngene.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* demods/tuners */
2362306a36Sopenharmony_ci#include "stv6110x.h"
2462306a36Sopenharmony_ci#include "stv090x.h"
2562306a36Sopenharmony_ci#include "lnbh24.h"
2662306a36Sopenharmony_ci#include "lgdt330x.h"
2762306a36Sopenharmony_ci#include "mt2131.h"
2862306a36Sopenharmony_ci#include "tda18271c2dd.h"
2962306a36Sopenharmony_ci#include "drxk.h"
3062306a36Sopenharmony_ci#include "drxd.h"
3162306a36Sopenharmony_ci#include "dvb-pll.h"
3262306a36Sopenharmony_ci#include "stv0367.h"
3362306a36Sopenharmony_ci#include "stv0367_priv.h"
3462306a36Sopenharmony_ci#include "tda18212.h"
3562306a36Sopenharmony_ci#include "cxd2841er.h"
3662306a36Sopenharmony_ci#include "stv0910.h"
3762306a36Sopenharmony_ci#include "stv6111.h"
3862306a36Sopenharmony_ci#include "lnbh25.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/****************************************************************************/
4162306a36Sopenharmony_ci/* I2C transfer functions used for demod/tuner probing***********************/
4262306a36Sopenharmony_ci/****************************************************************************/
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int i2c_io(struct i2c_adapter *adapter, u8 adr,
4562306a36Sopenharmony_ci		  u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct i2c_msg msgs[2] = {{.addr = adr,  .flags = 0,
4862306a36Sopenharmony_ci				   .buf  = wbuf, .len   = wlen },
4962306a36Sopenharmony_ci				  {.addr = adr,  .flags = I2C_M_RD,
5062306a36Sopenharmony_ci				   .buf  = rbuf,  .len   = rlen } };
5162306a36Sopenharmony_ci	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct i2c_msg msg = {.addr = adr, .flags = 0,
5762306a36Sopenharmony_ci			      .buf = data, .len = len};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int i2c_write_reg(struct i2c_adapter *adap, u8 adr,
6362306a36Sopenharmony_ci			 u8 reg, u8 val)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	u8 msg[2] = {reg, val};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	return i2c_write(adap, adr, msg, 2);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
7362306a36Sopenharmony_ci				   .buf  = val,  .len   = 1 } };
7462306a36Sopenharmony_ci	return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
7862306a36Sopenharmony_ci			  u16 reg, u8 *val)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	u8 msg[2] = {reg >> 8, reg & 0xff};
8162306a36Sopenharmony_ci	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
8262306a36Sopenharmony_ci				   .buf  = msg, .len   = 2},
8362306a36Sopenharmony_ci				  {.addr = adr, .flags = I2C_M_RD,
8462306a36Sopenharmony_ci				   .buf  = val, .len   = 1} };
8562306a36Sopenharmony_ci	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int i2c_read_regs(struct i2c_adapter *adapter,
8962306a36Sopenharmony_ci			 u8 adr, u8 reg, u8 *val, u8 len)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct i2c_msg msgs[2] = {{.addr = adr,  .flags = 0,
9262306a36Sopenharmony_ci				   .buf  = &reg, .len   = 1},
9362306a36Sopenharmony_ci				  {.addr = adr,  .flags = I2C_M_RD,
9462306a36Sopenharmony_ci				   .buf  = val,  .len   = len} };
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	return i2c_read_regs(adapter, adr, reg, val, 1);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/****************************************************************************/
10562306a36Sopenharmony_ci/* Demod/tuner attachment ***************************************************/
10662306a36Sopenharmony_ci/****************************************************************************/
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic struct i2c_adapter *i2c_adapter_from_chan(struct ngene_channel *chan)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
11162306a36Sopenharmony_ci	if (chan->number < 2)
11262306a36Sopenharmony_ci		return &chan->dev->channel[0].i2c_adapter;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return &chan->dev->channel[1].i2c_adapter;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int tuner_attach_stv6110(struct ngene_channel *chan)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
12062306a36Sopenharmony_ci	struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
12162306a36Sopenharmony_ci	struct stv090x_config *feconf = (struct stv090x_config *)
12262306a36Sopenharmony_ci		chan->dev->card_info->fe_config[chan->number];
12362306a36Sopenharmony_ci	struct stv6110x_config *tunerconf = (struct stv6110x_config *)
12462306a36Sopenharmony_ci		chan->dev->card_info->tuner_config[chan->number];
12562306a36Sopenharmony_ci	const struct stv6110x_devctl *ctl;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c);
12862306a36Sopenharmony_ci	if (ctl == NULL) {
12962306a36Sopenharmony_ci		dev_err(pdev, "No STV6110X found!\n");
13062306a36Sopenharmony_ci		return -ENODEV;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	feconf->tuner_init          = ctl->tuner_init;
13462306a36Sopenharmony_ci	feconf->tuner_sleep         = ctl->tuner_sleep;
13562306a36Sopenharmony_ci	feconf->tuner_set_mode      = ctl->tuner_set_mode;
13662306a36Sopenharmony_ci	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
13762306a36Sopenharmony_ci	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
13862306a36Sopenharmony_ci	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
13962306a36Sopenharmony_ci	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
14062306a36Sopenharmony_ci	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
14162306a36Sopenharmony_ci	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
14262306a36Sopenharmony_ci	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
14362306a36Sopenharmony_ci	feconf->tuner_get_status    = ctl->tuner_get_status;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return 0;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int tuner_attach_stv6111(struct ngene_channel *chan)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
15162306a36Sopenharmony_ci	struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
15262306a36Sopenharmony_ci	struct dvb_frontend *fe;
15362306a36Sopenharmony_ci	u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr);
15662306a36Sopenharmony_ci	if (!fe) {
15762306a36Sopenharmony_ci		fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4);
15862306a36Sopenharmony_ci		if (!fe) {
15962306a36Sopenharmony_ci			dev_err(pdev, "stv6111_attach() failed!\n");
16062306a36Sopenharmony_ci			return -ENODEV;
16162306a36Sopenharmony_ci		}
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	return 0;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct ngene_channel *chan = fe->sec_priv;
16962306a36Sopenharmony_ci	int status;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (enable) {
17262306a36Sopenharmony_ci		down(&chan->dev->pll_mutex);
17362306a36Sopenharmony_ci		status = chan->gate_ctrl(fe, 1);
17462306a36Sopenharmony_ci	} else {
17562306a36Sopenharmony_ci		status = chan->gate_ctrl(fe, 0);
17662306a36Sopenharmony_ci		up(&chan->dev->pll_mutex);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci	return status;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int tuner_attach_tda18271(struct ngene_channel *chan)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
18462306a36Sopenharmony_ci	struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
18562306a36Sopenharmony_ci	struct dvb_frontend *fe;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (chan->fe->ops.i2c_gate_ctrl)
18862306a36Sopenharmony_ci		chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
18962306a36Sopenharmony_ci	fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60);
19062306a36Sopenharmony_ci	if (chan->fe->ops.i2c_gate_ctrl)
19162306a36Sopenharmony_ci		chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
19262306a36Sopenharmony_ci	if (!fe) {
19362306a36Sopenharmony_ci		dev_err(pdev, "No TDA18271 found!\n");
19462306a36Sopenharmony_ci		return -ENODEV;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return 0;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic int tuner_tda18212_ping(struct ngene_channel *chan,
20162306a36Sopenharmony_ci			       struct i2c_adapter *i2c,
20262306a36Sopenharmony_ci			       unsigned short adr)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
20562306a36Sopenharmony_ci	u8 tda_id[2];
20662306a36Sopenharmony_ci	u8 subaddr = 0x00;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	dev_dbg(pdev, "stv0367-tda18212 tuner ping\n");
20962306a36Sopenharmony_ci	if (chan->fe->ops.i2c_gate_ctrl)
21062306a36Sopenharmony_ci		chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0)
21362306a36Sopenharmony_ci		dev_dbg(pdev, "tda18212 ping 1 fail\n");
21462306a36Sopenharmony_ci	if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0)
21562306a36Sopenharmony_ci		dev_warn(pdev, "tda18212 ping failed, expect problems\n");
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (chan->fe->ops.i2c_gate_ctrl)
21862306a36Sopenharmony_ci		chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return 0;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
22662306a36Sopenharmony_ci	struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
22762306a36Sopenharmony_ci	struct i2c_client *client;
22862306a36Sopenharmony_ci	struct tda18212_config config = {
22962306a36Sopenharmony_ci		.fe = chan->fe,
23062306a36Sopenharmony_ci		.if_dvbt_6 = 3550,
23162306a36Sopenharmony_ci		.if_dvbt_7 = 3700,
23262306a36Sopenharmony_ci		.if_dvbt_8 = 4150,
23362306a36Sopenharmony_ci		.if_dvbt2_6 = 3250,
23462306a36Sopenharmony_ci		.if_dvbt2_7 = 4000,
23562306a36Sopenharmony_ci		.if_dvbt2_8 = 4000,
23662306a36Sopenharmony_ci		.if_dvbc = 5000,
23762306a36Sopenharmony_ci	};
23862306a36Sopenharmony_ci	u8 addr = (chan->number & 1) ? 0x63 : 0x60;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/*
24162306a36Sopenharmony_ci	 * due to a hardware quirk with the I2C gate on the stv0367+tda18212
24262306a36Sopenharmony_ci	 * combo, the tda18212 must be probed by reading it's id _twice_ when
24362306a36Sopenharmony_ci	 * cold started, or it very likely will fail.
24462306a36Sopenharmony_ci	 */
24562306a36Sopenharmony_ci	if (dmdtype == DEMOD_TYPE_STV0367)
24662306a36Sopenharmony_ci		tuner_tda18212_ping(chan, i2c, addr);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* perform tuner probe/init/attach */
24962306a36Sopenharmony_ci	client = dvb_module_probe("tda18212", NULL, i2c, addr, &config);
25062306a36Sopenharmony_ci	if (!client)
25162306a36Sopenharmony_ci		goto err;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	chan->i2c_client[0] = client;
25462306a36Sopenharmony_ci	chan->i2c_client_fe = 1;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return 0;
25762306a36Sopenharmony_cierr:
25862306a36Sopenharmony_ci	dev_err(pdev, "TDA18212 tuner not found. Device is not fully operational.\n");
25962306a36Sopenharmony_ci	return -ENODEV;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic int tuner_attach_probe(struct ngene_channel *chan)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	switch (chan->demod_type) {
26562306a36Sopenharmony_ci	case DEMOD_TYPE_STV090X:
26662306a36Sopenharmony_ci		return tuner_attach_stv6110(chan);
26762306a36Sopenharmony_ci	case DEMOD_TYPE_DRXK:
26862306a36Sopenharmony_ci		return tuner_attach_tda18271(chan);
26962306a36Sopenharmony_ci	case DEMOD_TYPE_STV0367:
27062306a36Sopenharmony_ci	case DEMOD_TYPE_SONY_CT2:
27162306a36Sopenharmony_ci	case DEMOD_TYPE_SONY_ISDBT:
27262306a36Sopenharmony_ci	case DEMOD_TYPE_SONY_C2T2:
27362306a36Sopenharmony_ci	case DEMOD_TYPE_SONY_C2T2I:
27462306a36Sopenharmony_ci		return tuner_attach_tda18212(chan, chan->demod_type);
27562306a36Sopenharmony_ci	case DEMOD_TYPE_STV0910:
27662306a36Sopenharmony_ci		return tuner_attach_stv6111(chan);
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return -EINVAL;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int demod_attach_stv0900(struct ngene_channel *chan)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
28562306a36Sopenharmony_ci	struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
28662306a36Sopenharmony_ci	struct stv090x_config *feconf = (struct stv090x_config *)
28762306a36Sopenharmony_ci		chan->dev->card_info->fe_config[chan->number];
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	chan->fe = dvb_attach(stv090x_attach, feconf, i2c,
29062306a36Sopenharmony_ci			(chan->number & 1) == 0 ? STV090x_DEMODULATOR_0
29162306a36Sopenharmony_ci						: STV090x_DEMODULATOR_1);
29262306a36Sopenharmony_ci	if (chan->fe == NULL) {
29362306a36Sopenharmony_ci		dev_err(pdev, "No STV0900 found!\n");
29462306a36Sopenharmony_ci		return -ENODEV;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* store channel info */
29862306a36Sopenharmony_ci	if (feconf->tuner_i2c_lock)
29962306a36Sopenharmony_ci		chan->fe->analog_demod_priv = chan;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0,
30262306a36Sopenharmony_ci			0, chan->dev->card_info->lnb[chan->number])) {
30362306a36Sopenharmony_ci		dev_err(pdev, "No LNBH24 found!\n");
30462306a36Sopenharmony_ci		dvb_frontend_detach(chan->fe);
30562306a36Sopenharmony_ci		chan->fe = NULL;
30662306a36Sopenharmony_ci		return -ENODEV;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	return 0;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic struct stv0910_cfg stv0910_p = {
31362306a36Sopenharmony_ci	.adr      = 0x68,
31462306a36Sopenharmony_ci	.parallel = 1,
31562306a36Sopenharmony_ci	.rptlvl   = 4,
31662306a36Sopenharmony_ci	.clk      = 30000000,
31762306a36Sopenharmony_ci	.tsspeed  = 0x28,
31862306a36Sopenharmony_ci};
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic struct lnbh25_config lnbh25_cfg = {
32162306a36Sopenharmony_ci	.i2c_address = 0x0c << 1,
32262306a36Sopenharmony_ci	.data2_config = LNBH25_TEN
32362306a36Sopenharmony_ci};
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int demod_attach_stv0910(struct ngene_channel *chan,
32662306a36Sopenharmony_ci				struct i2c_adapter *i2c)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
32962306a36Sopenharmony_ci	struct stv0910_cfg cfg = stv0910_p;
33062306a36Sopenharmony_ci	struct lnbh25_config lnbcfg = lnbh25_cfg;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	chan->fe = dvb_attach(stv0910_attach, i2c, &cfg, (chan->number & 1));
33362306a36Sopenharmony_ci	if (!chan->fe) {
33462306a36Sopenharmony_ci		cfg.adr = 0x6c;
33562306a36Sopenharmony_ci		chan->fe = dvb_attach(stv0910_attach, i2c,
33662306a36Sopenharmony_ci				      &cfg, (chan->number & 1));
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	if (!chan->fe) {
33962306a36Sopenharmony_ci		dev_err(pdev, "stv0910_attach() failed!\n");
34062306a36Sopenharmony_ci		return -ENODEV;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/*
34462306a36Sopenharmony_ci	 * attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit
34562306a36Sopenharmony_ci	 * i2c addresses
34662306a36Sopenharmony_ci	 */
34762306a36Sopenharmony_ci	lnbcfg.i2c_address = (((chan->number & 1) ? 0x0d : 0x0c) << 1);
34862306a36Sopenharmony_ci	if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) {
34962306a36Sopenharmony_ci		lnbcfg.i2c_address = (((chan->number & 1) ? 0x09 : 0x08) << 1);
35062306a36Sopenharmony_ci		if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) {
35162306a36Sopenharmony_ci			dev_err(pdev, "lnbh25_attach() failed!\n");
35262306a36Sopenharmony_ci			dvb_frontend_detach(chan->fe);
35362306a36Sopenharmony_ci			chan->fe = NULL;
35462306a36Sopenharmony_ci			return -ENODEV;
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return 0;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic struct stv0367_config ddb_stv0367_config[] = {
36262306a36Sopenharmony_ci	{
36362306a36Sopenharmony_ci		.demod_address = 0x1f,
36462306a36Sopenharmony_ci		.xtal = 27000000,
36562306a36Sopenharmony_ci		.if_khz = 0,
36662306a36Sopenharmony_ci		.if_iq_mode = FE_TER_NORMAL_IF_TUNER,
36762306a36Sopenharmony_ci		.ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
36862306a36Sopenharmony_ci		.clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
36962306a36Sopenharmony_ci	}, {
37062306a36Sopenharmony_ci		.demod_address = 0x1e,
37162306a36Sopenharmony_ci		.xtal = 27000000,
37262306a36Sopenharmony_ci		.if_khz = 0,
37362306a36Sopenharmony_ci		.if_iq_mode = FE_TER_NORMAL_IF_TUNER,
37462306a36Sopenharmony_ci		.ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
37562306a36Sopenharmony_ci		.clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
37662306a36Sopenharmony_ci	},
37762306a36Sopenharmony_ci};
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic int demod_attach_stv0367(struct ngene_channel *chan,
38062306a36Sopenharmony_ci				struct i2c_adapter *i2c)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	chan->fe = dvb_attach(stv0367ddb_attach,
38562306a36Sopenharmony_ci			      &ddb_stv0367_config[(chan->number & 1)], i2c);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (!chan->fe) {
38862306a36Sopenharmony_ci		dev_err(pdev, "stv0367ddb_attach() failed!\n");
38962306a36Sopenharmony_ci		return -ENODEV;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	chan->fe->sec_priv = chan;
39362306a36Sopenharmony_ci	chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
39462306a36Sopenharmony_ci	chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
39562306a36Sopenharmony_ci	return 0;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int demod_attach_cxd28xx(struct ngene_channel *chan,
39962306a36Sopenharmony_ci				struct i2c_adapter *i2c, int osc24)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
40262306a36Sopenharmony_ci	struct cxd2841er_config cfg;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/* the cxd2841er driver expects 8bit/shifted I2C addresses */
40562306a36Sopenharmony_ci	cfg.i2c_addr = ((chan->number & 1) ? 0x6d : 0x6c) << 1;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500;
40862306a36Sopenharmony_ci	cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE |
40962306a36Sopenharmony_ci		CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG |
41062306a36Sopenharmony_ci		CXD2841ER_TSBITS | CXD2841ER_TS_SERIAL;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* attach frontend */
41362306a36Sopenharmony_ci	chan->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (!chan->fe) {
41662306a36Sopenharmony_ci		dev_err(pdev, "CXD28XX attach failed!\n");
41762306a36Sopenharmony_ci		return -ENODEV;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	chan->fe->sec_priv = chan;
42162306a36Sopenharmony_ci	chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
42262306a36Sopenharmony_ci	chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	struct ngene_channel *chan = fe->analog_demod_priv;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (lock)
43162306a36Sopenharmony_ci		down(&chan->dev->pll_mutex);
43262306a36Sopenharmony_ci	else
43362306a36Sopenharmony_ci		up(&chan->dev->pll_mutex);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int port_has_stv0900(struct i2c_adapter *i2c, int port)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	u8 val;
43962306a36Sopenharmony_ci	if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
44062306a36Sopenharmony_ci		return 0;
44162306a36Sopenharmony_ci	return 1;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic int port_has_drxk(struct i2c_adapter *i2c, int port)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	u8 val;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (i2c_read(i2c, 0x29+port, &val) < 0)
44962306a36Sopenharmony_ci		return 0;
45062306a36Sopenharmony_ci	return 1;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int port_has_stv0367(struct i2c_adapter *i2c)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	u8 val;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (i2c_read_reg16(i2c, 0x1e, 0xf000, &val) < 0)
45862306a36Sopenharmony_ci		return 0;
45962306a36Sopenharmony_ci	if (val != 0x60)
46062306a36Sopenharmony_ci		return 0;
46162306a36Sopenharmony_ci	if (i2c_read_reg16(i2c, 0x1f, 0xf000, &val) < 0)
46262306a36Sopenharmony_ci		return 0;
46362306a36Sopenharmony_ci	if (val != 0x60)
46462306a36Sopenharmony_ci		return 0;
46562306a36Sopenharmony_ci	return 1;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ciint ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	u8 val;
47162306a36Sopenharmony_ci	u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4];
47262306a36Sopenharmony_ci	struct i2c_msg msgs[2] = {{ .addr = 0x40,  .flags = 0,
47362306a36Sopenharmony_ci				    .buf  = probe, .len   = 4 },
47462306a36Sopenharmony_ci				  { .addr = 0x40,  .flags = I2C_M_RD,
47562306a36Sopenharmony_ci				    .buf  = data,  .len   = 4 } };
47662306a36Sopenharmony_ci	val = i2c_transfer(i2c, msgs, 2);
47762306a36Sopenharmony_ci	if (val != 2)
47862306a36Sopenharmony_ci		return 0;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43)
48162306a36Sopenharmony_ci		*type = 2;
48262306a36Sopenharmony_ci	else
48362306a36Sopenharmony_ci		*type = 1;
48462306a36Sopenharmony_ci	return 1;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int demod_attach_drxk(struct ngene_channel *chan,
48862306a36Sopenharmony_ci			     struct i2c_adapter *i2c)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
49162306a36Sopenharmony_ci	struct drxk_config config;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	memset(&config, 0, sizeof(config));
49462306a36Sopenharmony_ci	config.microcode_name = "drxk_a3.mc";
49562306a36Sopenharmony_ci	config.qam_demod_parameter_count = 4;
49662306a36Sopenharmony_ci	config.adr = 0x29 + (chan->number ^ 2);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	chan->fe = dvb_attach(drxk_attach, &config, i2c);
49962306a36Sopenharmony_ci	if (!chan->fe) {
50062306a36Sopenharmony_ci		dev_err(pdev, "No DRXK found!\n");
50162306a36Sopenharmony_ci		return -ENODEV;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci	chan->fe->sec_priv = chan;
50462306a36Sopenharmony_ci	chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
50562306a36Sopenharmony_ci	chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
50662306a36Sopenharmony_ci	return 0;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/****************************************************************************/
51062306a36Sopenharmony_ci/* XO2 related lists and functions ******************************************/
51162306a36Sopenharmony_ci/****************************************************************************/
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic char *xo2names[] = {
51462306a36Sopenharmony_ci	"DUAL DVB-S2",
51562306a36Sopenharmony_ci	"DUAL DVB-C/T/T2",
51662306a36Sopenharmony_ci	"DUAL DVB-ISDBT",
51762306a36Sopenharmony_ci	"DUAL DVB-C/C2/T/T2",
51862306a36Sopenharmony_ci	"DUAL ATSC",
51962306a36Sopenharmony_ci	"DUAL DVB-C/C2/T/T2/I",
52062306a36Sopenharmony_ci};
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int init_xo2(struct ngene_channel *chan, struct i2c_adapter *i2c)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
52562306a36Sopenharmony_ci	u8 addr = 0x10;
52662306a36Sopenharmony_ci	u8 val, data[2];
52762306a36Sopenharmony_ci	int res;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	res = i2c_read_regs(i2c, addr, 0x04, data, 2);
53062306a36Sopenharmony_ci	if (res < 0)
53162306a36Sopenharmony_ci		return res;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (data[0] != 0x01)  {
53462306a36Sopenharmony_ci		dev_info(pdev, "Invalid XO2 on channel %d\n", chan->number);
53562306a36Sopenharmony_ci		return -1;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	i2c_read_reg(i2c, addr, 0x08, &val);
53962306a36Sopenharmony_ci	if (val != 0) {
54062306a36Sopenharmony_ci		i2c_write_reg(i2c, addr, 0x08, 0x00);
54162306a36Sopenharmony_ci		msleep(100);
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci	/* Enable tuner power, disable pll, reset demods */
54462306a36Sopenharmony_ci	i2c_write_reg(i2c, addr, 0x08, 0x04);
54562306a36Sopenharmony_ci	usleep_range(2000, 3000);
54662306a36Sopenharmony_ci	/* Release demod resets */
54762306a36Sopenharmony_ci	i2c_write_reg(i2c, addr, 0x08, 0x07);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/*
55062306a36Sopenharmony_ci	 * speed: 0=55,1=75,2=90,3=104 MBit/s
55162306a36Sopenharmony_ci	 * Note: The ngene hardware must be run at 75 MBit/s compared
55262306a36Sopenharmony_ci	 * to more modern ddbridge hardware which runs at 90 MBit/s,
55362306a36Sopenharmony_ci	 * else there will be issues with the data transport and non-
55462306a36Sopenharmony_ci	 * working secondary/slave demods/tuners.
55562306a36Sopenharmony_ci	 */
55662306a36Sopenharmony_ci	i2c_write_reg(i2c, addr, 0x09, 1);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	i2c_write_reg(i2c, addr, 0x0a, 0x01);
55962306a36Sopenharmony_ci	i2c_write_reg(i2c, addr, 0x0b, 0x01);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	usleep_range(2000, 3000);
56262306a36Sopenharmony_ci	/* Start XO2 PLL */
56362306a36Sopenharmony_ci	i2c_write_reg(i2c, addr, 0x08, 0x87);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	return 0;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	u8 probe[1] = { 0x00 }, data[4];
57162306a36Sopenharmony_ci	u8 addr = 0x10;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	*type = NGENE_XO2_TYPE_NONE;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (i2c_io(i2c, addr, probe, 1, data, 4))
57662306a36Sopenharmony_ci		return 0;
57762306a36Sopenharmony_ci	if (data[0] == 'D' && data[1] == 'F') {
57862306a36Sopenharmony_ci		*id = data[2];
57962306a36Sopenharmony_ci		*type = NGENE_XO2_TYPE_DUOFLEX;
58062306a36Sopenharmony_ci		return 1;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci	if (data[0] == 'C' && data[1] == 'I') {
58362306a36Sopenharmony_ci		*id = data[2];
58462306a36Sopenharmony_ci		*type = NGENE_XO2_TYPE_CI;
58562306a36Sopenharmony_ci		return 1;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci	return 0;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/****************************************************************************/
59162306a36Sopenharmony_ci/* Probing and port/channel handling ****************************************/
59262306a36Sopenharmony_ci/****************************************************************************/
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic int cineS2_probe(struct ngene_channel *chan)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
59762306a36Sopenharmony_ci	struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
59862306a36Sopenharmony_ci	struct stv090x_config *fe_conf;
59962306a36Sopenharmony_ci	u8 buf[3];
60062306a36Sopenharmony_ci	u8 xo2_type, xo2_id, xo2_demodtype;
60162306a36Sopenharmony_ci	u8 sony_osc24 = 0;
60262306a36Sopenharmony_ci	struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };
60362306a36Sopenharmony_ci	int rc;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (port_has_xo2(i2c, &xo2_type, &xo2_id)) {
60662306a36Sopenharmony_ci		xo2_id >>= 2;
60762306a36Sopenharmony_ci		dev_dbg(pdev, "XO2 on channel %d (type %d, id %d)\n",
60862306a36Sopenharmony_ci			chan->number, xo2_type, xo2_id);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		switch (xo2_type) {
61162306a36Sopenharmony_ci		case NGENE_XO2_TYPE_DUOFLEX:
61262306a36Sopenharmony_ci			if (chan->number & 1)
61362306a36Sopenharmony_ci				dev_dbg(pdev,
61462306a36Sopenharmony_ci					"skipping XO2 init on odd channel %d",
61562306a36Sopenharmony_ci					chan->number);
61662306a36Sopenharmony_ci			else
61762306a36Sopenharmony_ci				init_xo2(chan, i2c);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci			xo2_demodtype = DEMOD_TYPE_XO2 + xo2_id;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci			switch (xo2_demodtype) {
62262306a36Sopenharmony_ci			case DEMOD_TYPE_SONY_CT2:
62362306a36Sopenharmony_ci			case DEMOD_TYPE_SONY_ISDBT:
62462306a36Sopenharmony_ci			case DEMOD_TYPE_SONY_C2T2:
62562306a36Sopenharmony_ci			case DEMOD_TYPE_SONY_C2T2I:
62662306a36Sopenharmony_ci				dev_info(pdev, "%s (XO2) on channel %d\n",
62762306a36Sopenharmony_ci					 xo2names[xo2_id], chan->number);
62862306a36Sopenharmony_ci				chan->demod_type = xo2_demodtype;
62962306a36Sopenharmony_ci				if (xo2_demodtype == DEMOD_TYPE_SONY_C2T2I)
63062306a36Sopenharmony_ci					sony_osc24 = 1;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci				demod_attach_cxd28xx(chan, i2c, sony_osc24);
63362306a36Sopenharmony_ci				break;
63462306a36Sopenharmony_ci			case DEMOD_TYPE_STV0910:
63562306a36Sopenharmony_ci				dev_info(pdev, "%s (XO2) on channel %d\n",
63662306a36Sopenharmony_ci					 xo2names[xo2_id], chan->number);
63762306a36Sopenharmony_ci				chan->demod_type = xo2_demodtype;
63862306a36Sopenharmony_ci				demod_attach_stv0910(chan, i2c);
63962306a36Sopenharmony_ci				break;
64062306a36Sopenharmony_ci			default:
64162306a36Sopenharmony_ci				dev_warn(pdev,
64262306a36Sopenharmony_ci					 "Unsupported XO2 module on channel %d\n",
64362306a36Sopenharmony_ci					 chan->number);
64462306a36Sopenharmony_ci				return -ENODEV;
64562306a36Sopenharmony_ci			}
64662306a36Sopenharmony_ci			break;
64762306a36Sopenharmony_ci		case NGENE_XO2_TYPE_CI:
64862306a36Sopenharmony_ci			dev_info(pdev, "DuoFlex CI modules not supported\n");
64962306a36Sopenharmony_ci			return -ENODEV;
65062306a36Sopenharmony_ci		default:
65162306a36Sopenharmony_ci			dev_info(pdev, "Unsupported XO2 module type\n");
65262306a36Sopenharmony_ci			return -ENODEV;
65362306a36Sopenharmony_ci		}
65462306a36Sopenharmony_ci	} else if (port_has_stv0900(i2c, chan->number)) {
65562306a36Sopenharmony_ci		chan->demod_type = DEMOD_TYPE_STV090X;
65662306a36Sopenharmony_ci		fe_conf = chan->dev->card_info->fe_config[chan->number];
65762306a36Sopenharmony_ci		/* demod found, attach it */
65862306a36Sopenharmony_ci		rc = demod_attach_stv0900(chan);
65962306a36Sopenharmony_ci		if (rc < 0 || chan->number < 2)
66062306a36Sopenharmony_ci			return rc;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		/* demod #2: reprogram outputs DPN1 & DPN2 */
66362306a36Sopenharmony_ci		i2c_msg.addr = fe_conf->address;
66462306a36Sopenharmony_ci		i2c_msg.len = 3;
66562306a36Sopenharmony_ci		buf[0] = 0xf1;
66662306a36Sopenharmony_ci		switch (chan->number) {
66762306a36Sopenharmony_ci		case 2:
66862306a36Sopenharmony_ci			buf[1] = 0x5c;
66962306a36Sopenharmony_ci			buf[2] = 0xc2;
67062306a36Sopenharmony_ci			break;
67162306a36Sopenharmony_ci		case 3:
67262306a36Sopenharmony_ci			buf[1] = 0x61;
67362306a36Sopenharmony_ci			buf[2] = 0xcc;
67462306a36Sopenharmony_ci			break;
67562306a36Sopenharmony_ci		default:
67662306a36Sopenharmony_ci			return -ENODEV;
67762306a36Sopenharmony_ci		}
67862306a36Sopenharmony_ci		rc = i2c_transfer(i2c, &i2c_msg, 1);
67962306a36Sopenharmony_ci		if (rc != 1) {
68062306a36Sopenharmony_ci			dev_err(pdev, "Could not setup DPNx\n");
68162306a36Sopenharmony_ci			return -EIO;
68262306a36Sopenharmony_ci		}
68362306a36Sopenharmony_ci	} else if (port_has_drxk(i2c, chan->number^2)) {
68462306a36Sopenharmony_ci		chan->demod_type = DEMOD_TYPE_DRXK;
68562306a36Sopenharmony_ci		demod_attach_drxk(chan, i2c);
68662306a36Sopenharmony_ci	} else if (port_has_stv0367(i2c)) {
68762306a36Sopenharmony_ci		chan->demod_type = DEMOD_TYPE_STV0367;
68862306a36Sopenharmony_ci		dev_info(pdev, "STV0367 on channel %d\n", chan->number);
68962306a36Sopenharmony_ci		demod_attach_stv0367(chan, i2c);
69062306a36Sopenharmony_ci	} else {
69162306a36Sopenharmony_ci		dev_info(pdev, "No demod found on chan %d\n", chan->number);
69262306a36Sopenharmony_ci		return -ENODEV;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci	return 0;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic struct lgdt330x_config aver_m780 = {
69962306a36Sopenharmony_ci	.demod_chip    = LGDT3303,
70062306a36Sopenharmony_ci	.serial_mpeg   = 0x00, /* PARALLEL */
70162306a36Sopenharmony_ci	.clock_polarity_flip = 1,
70262306a36Sopenharmony_ci};
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic struct mt2131_config m780_tunerconfig = {
70562306a36Sopenharmony_ci	0xc0 >> 1
70662306a36Sopenharmony_ci};
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci/* A single func to attach the demo and tuner, rather than
70962306a36Sopenharmony_ci * use two sep funcs like the current design mandates.
71062306a36Sopenharmony_ci */
71162306a36Sopenharmony_cistatic int demod_attach_lg330x(struct ngene_channel *chan)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	chan->fe = dvb_attach(lgdt330x_attach, &aver_m780,
71662306a36Sopenharmony_ci			      0xb2 >> 1, &chan->i2c_adapter);
71762306a36Sopenharmony_ci	if (chan->fe == NULL) {
71862306a36Sopenharmony_ci		dev_err(pdev, "No LGDT330x found!\n");
71962306a36Sopenharmony_ci		return -ENODEV;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter,
72362306a36Sopenharmony_ci		   &m780_tunerconfig, 0);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	return (chan->fe) ? 0 : -ENODEV;
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cistatic int demod_attach_drxd(struct ngene_channel *chan)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
73162306a36Sopenharmony_ci	struct drxd_config *feconf;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	feconf = chan->dev->card_info->fe_config[chan->number];
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	chan->fe = dvb_attach(drxd_attach, feconf, chan,
73662306a36Sopenharmony_ci			&chan->i2c_adapter, &chan->dev->pci_dev->dev);
73762306a36Sopenharmony_ci	if (!chan->fe) {
73862306a36Sopenharmony_ci		dev_err(pdev, "No DRXD found!\n");
73962306a36Sopenharmony_ci		return -ENODEV;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci	return 0;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_cistatic int tuner_attach_dtt7520x(struct ngene_channel *chan)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
74762306a36Sopenharmony_ci	struct drxd_config *feconf;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	feconf = chan->dev->card_info->fe_config[chan->number];
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address,
75262306a36Sopenharmony_ci			&chan->i2c_adapter,
75362306a36Sopenharmony_ci			feconf->pll_type)) {
75462306a36Sopenharmony_ci		dev_err(pdev, "No pll(%d) found!\n", feconf->pll_type);
75562306a36Sopenharmony_ci		return -ENODEV;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci	return 0;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci/****************************************************************************/
76162306a36Sopenharmony_ci/* EEPROM TAGS **************************************************************/
76262306a36Sopenharmony_ci/****************************************************************************/
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci#define MICNG_EE_START      0x0100
76562306a36Sopenharmony_ci#define MICNG_EE_END        0x0FF0
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci#define MICNG_EETAG_END0    0x0000
76862306a36Sopenharmony_ci#define MICNG_EETAG_END1    0xFFFF
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci/* 0x0001 - 0x000F reserved for housekeeping */
77162306a36Sopenharmony_ci/* 0xFFFF - 0xFFFE reserved for housekeeping */
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci/* Micronas assigned tags
77462306a36Sopenharmony_ci   EEProm tags for hardware support */
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci#define MICNG_EETAG_DRXD1_OSCDEVIATION  0x1000  /* 2 Bytes data */
77762306a36Sopenharmony_ci#define MICNG_EETAG_DRXD2_OSCDEVIATION  0x1001  /* 2 Bytes data */
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci#define MICNG_EETAG_MT2060_1_1STIF      0x1100  /* 2 Bytes data */
78062306a36Sopenharmony_ci#define MICNG_EETAG_MT2060_2_1STIF      0x1101  /* 2 Bytes data */
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci/* Tag range for OEMs */
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci#define MICNG_EETAG_OEM_FIRST  0xC000
78562306a36Sopenharmony_ci#define MICNG_EETAG_OEM_LAST   0xFFEF
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int i2c_write_eeprom(struct i2c_adapter *adapter,
78862306a36Sopenharmony_ci			    u8 adr, u16 reg, u8 data)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct device *pdev = adapter->dev.parent;
79162306a36Sopenharmony_ci	u8 m[3] = {(reg >> 8), (reg & 0xff), data};
79262306a36Sopenharmony_ci	struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m,
79362306a36Sopenharmony_ci			      .len = sizeof(m)};
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (i2c_transfer(adapter, &msg, 1) != 1) {
79662306a36Sopenharmony_ci		dev_err(pdev, "Error writing EEPROM!\n");
79762306a36Sopenharmony_ci		return -EIO;
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci	return 0;
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic int i2c_read_eeprom(struct i2c_adapter *adapter,
80362306a36Sopenharmony_ci			   u8 adr, u16 reg, u8 *data, int len)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	struct device *pdev = adapter->dev.parent;
80662306a36Sopenharmony_ci	u8 msg[2] = {(reg >> 8), (reg & 0xff)};
80762306a36Sopenharmony_ci	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
80862306a36Sopenharmony_ci				   .buf = msg, .len = 2 },
80962306a36Sopenharmony_ci				  {.addr = adr, .flags = I2C_M_RD,
81062306a36Sopenharmony_ci				   .buf = data, .len = len} };
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	if (i2c_transfer(adapter, msgs, 2) != 2) {
81362306a36Sopenharmony_ci		dev_err(pdev, "Error reading EEPROM\n");
81462306a36Sopenharmony_ci		return -EIO;
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci	return 0;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int ReadEEProm(struct i2c_adapter *adapter,
82062306a36Sopenharmony_ci		      u16 Tag, u32 MaxLen, u8 *data, u32 *pLength)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	struct device *pdev = adapter->dev.parent;
82362306a36Sopenharmony_ci	int status = 0;
82462306a36Sopenharmony_ci	u16 Addr = MICNG_EE_START, Length, tag = 0;
82562306a36Sopenharmony_ci	u8  EETag[3];
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	while (Addr + sizeof(u16) + 1 < MICNG_EE_END) {
82862306a36Sopenharmony_ci		if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag)))
82962306a36Sopenharmony_ci			return -1;
83062306a36Sopenharmony_ci		tag = (EETag[0] << 8) | EETag[1];
83162306a36Sopenharmony_ci		if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1)
83262306a36Sopenharmony_ci			return -1;
83362306a36Sopenharmony_ci		if (tag == Tag)
83462306a36Sopenharmony_ci			break;
83562306a36Sopenharmony_ci		Addr += sizeof(u16) + 1 + EETag[2];
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci	if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
83862306a36Sopenharmony_ci		dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n",
83962306a36Sopenharmony_ci			tag, EETag[2]);
84062306a36Sopenharmony_ci		return -1;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	Length = EETag[2];
84362306a36Sopenharmony_ci	if (Length > MaxLen)
84462306a36Sopenharmony_ci		Length = (u16) MaxLen;
84562306a36Sopenharmony_ci	if (Length > 0) {
84662306a36Sopenharmony_ci		Addr += sizeof(u16) + 1;
84762306a36Sopenharmony_ci		status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length);
84862306a36Sopenharmony_ci		if (!status) {
84962306a36Sopenharmony_ci			*pLength = EETag[2];
85062306a36Sopenharmony_ci#if 0
85162306a36Sopenharmony_ci			if (Length < EETag[2])
85262306a36Sopenharmony_ci				status = STATUS_BUFFER_OVERFLOW;
85362306a36Sopenharmony_ci#endif
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci	return status;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_cistatic int WriteEEProm(struct i2c_adapter *adapter,
86062306a36Sopenharmony_ci		       u16 Tag, u32 Length, u8 *data)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	struct device *pdev = adapter->dev.parent;
86362306a36Sopenharmony_ci	int status = 0;
86462306a36Sopenharmony_ci	u16 Addr = MICNG_EE_START;
86562306a36Sopenharmony_ci	u8 EETag[3];
86662306a36Sopenharmony_ci	u16 tag = 0;
86762306a36Sopenharmony_ci	int retry, i;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	while (Addr + sizeof(u16) + 1 < MICNG_EE_END) {
87062306a36Sopenharmony_ci		if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag)))
87162306a36Sopenharmony_ci			return -1;
87262306a36Sopenharmony_ci		tag = (EETag[0] << 8) | EETag[1];
87362306a36Sopenharmony_ci		if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1)
87462306a36Sopenharmony_ci			return -1;
87562306a36Sopenharmony_ci		if (tag == Tag)
87662306a36Sopenharmony_ci			break;
87762306a36Sopenharmony_ci		Addr += sizeof(u16) + 1 + EETag[2];
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci	if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
88062306a36Sopenharmony_ci		dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n",
88162306a36Sopenharmony_ci			tag, EETag[2]);
88262306a36Sopenharmony_ci		return -1;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	if (Length > EETag[2])
88662306a36Sopenharmony_ci		return -EINVAL;
88762306a36Sopenharmony_ci	/* Note: We write the data one byte at a time to avoid
88862306a36Sopenharmony_ci	   issues with page sizes. (which are different for
88962306a36Sopenharmony_ci	   each manufacture and eeprom size)
89062306a36Sopenharmony_ci	 */
89162306a36Sopenharmony_ci	Addr += sizeof(u16) + 1;
89262306a36Sopenharmony_ci	for (i = 0; i < Length; i++, Addr++) {
89362306a36Sopenharmony_ci		status = i2c_write_eeprom(adapter, 0x50, Addr, data[i]);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		if (status)
89662306a36Sopenharmony_ci			break;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci		/* Poll for finishing write cycle */
89962306a36Sopenharmony_ci		retry = 10;
90062306a36Sopenharmony_ci		while (retry) {
90162306a36Sopenharmony_ci			u8 Tmp;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci			msleep(50);
90462306a36Sopenharmony_ci			status = i2c_read_eeprom(adapter, 0x50, Addr, &Tmp, 1);
90562306a36Sopenharmony_ci			if (status)
90662306a36Sopenharmony_ci				break;
90762306a36Sopenharmony_ci			if (Tmp != data[i])
90862306a36Sopenharmony_ci				dev_err(pdev, "eeprom write error\n");
90962306a36Sopenharmony_ci			retry -= 1;
91062306a36Sopenharmony_ci		}
91162306a36Sopenharmony_ci		if (status) {
91262306a36Sopenharmony_ci			dev_err(pdev, "Timeout polling eeprom\n");
91362306a36Sopenharmony_ci			break;
91462306a36Sopenharmony_ci		}
91562306a36Sopenharmony_ci	}
91662306a36Sopenharmony_ci	return status;
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	int stat;
92262306a36Sopenharmony_ci	u8 buf[2];
92362306a36Sopenharmony_ci	u32 len = 0;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	stat = ReadEEProm(adapter, tag, 2, buf, &len);
92662306a36Sopenharmony_ci	if (stat)
92762306a36Sopenharmony_ci		return stat;
92862306a36Sopenharmony_ci	if (len != 2)
92962306a36Sopenharmony_ci		return -EINVAL;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	*data = (buf[0] << 8) | buf[1];
93262306a36Sopenharmony_ci	return 0;
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_cistatic int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	u8 buf[2];
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	buf[0] = data >> 8;
94062306a36Sopenharmony_ci	buf[1] = data & 0xff;
94162306a36Sopenharmony_ci	return WriteEEProm(adapter, tag, 2, buf);
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic s16 osc_deviation(void *priv, s16 deviation, int flag)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct ngene_channel *chan = priv;
94762306a36Sopenharmony_ci	struct device *pdev = &chan->dev->pci_dev->dev;
94862306a36Sopenharmony_ci	struct i2c_adapter *adap = &chan->i2c_adapter;
94962306a36Sopenharmony_ci	u16 data = 0;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (flag) {
95262306a36Sopenharmony_ci		data = (u16) deviation;
95362306a36Sopenharmony_ci		dev_info(pdev, "write deviation %d\n",
95462306a36Sopenharmony_ci			 deviation);
95562306a36Sopenharmony_ci		eeprom_write_ushort(adap, 0x1000 + chan->number, data);
95662306a36Sopenharmony_ci	} else {
95762306a36Sopenharmony_ci		if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data))
95862306a36Sopenharmony_ci			data = 0;
95962306a36Sopenharmony_ci		dev_info(pdev, "read deviation %d\n",
96062306a36Sopenharmony_ci			 (s16)data);
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	return (s16) data;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci/****************************************************************************/
96762306a36Sopenharmony_ci/* Switch control (I2C gates, etc.) *****************************************/
96862306a36Sopenharmony_ci/****************************************************************************/
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic struct stv090x_config fe_cineS2 = {
97262306a36Sopenharmony_ci	.device         = STV0900,
97362306a36Sopenharmony_ci	.demod_mode     = STV090x_DUAL,
97462306a36Sopenharmony_ci	.clk_mode       = STV090x_CLK_EXT,
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	.xtal           = 27000000,
97762306a36Sopenharmony_ci	.address        = 0x68,
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
98062306a36Sopenharmony_ci	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	.repeater_level = STV090x_RPTLEVEL_16,
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	.adc1_range	= STV090x_ADC_1Vpp,
98562306a36Sopenharmony_ci	.adc2_range	= STV090x_ADC_1Vpp,
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	.diseqc_envelope_mode = true,
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	.tuner_i2c_lock = cineS2_tuner_i2c_lock,
99062306a36Sopenharmony_ci};
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic struct stv090x_config fe_cineS2_2 = {
99362306a36Sopenharmony_ci	.device         = STV0900,
99462306a36Sopenharmony_ci	.demod_mode     = STV090x_DUAL,
99562306a36Sopenharmony_ci	.clk_mode       = STV090x_CLK_EXT,
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	.xtal           = 27000000,
99862306a36Sopenharmony_ci	.address        = 0x69,
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
100162306a36Sopenharmony_ci	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	.repeater_level = STV090x_RPTLEVEL_16,
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	.adc1_range	= STV090x_ADC_1Vpp,
100662306a36Sopenharmony_ci	.adc2_range	= STV090x_ADC_1Vpp,
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	.diseqc_envelope_mode = true,
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	.tuner_i2c_lock = cineS2_tuner_i2c_lock,
101162306a36Sopenharmony_ci};
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic struct stv6110x_config tuner_cineS2_0 = {
101462306a36Sopenharmony_ci	.addr	= 0x60,
101562306a36Sopenharmony_ci	.refclk	= 27000000,
101662306a36Sopenharmony_ci	.clk_div = 1,
101762306a36Sopenharmony_ci};
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic struct stv6110x_config tuner_cineS2_1 = {
102062306a36Sopenharmony_ci	.addr	= 0x63,
102162306a36Sopenharmony_ci	.refclk	= 27000000,
102262306a36Sopenharmony_ci	.clk_div = 1,
102362306a36Sopenharmony_ci};
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic const struct ngene_info ngene_info_cineS2 = {
102662306a36Sopenharmony_ci	.type		= NGENE_SIDEWINDER,
102762306a36Sopenharmony_ci	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner",
102862306a36Sopenharmony_ci	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
102962306a36Sopenharmony_ci	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
103062306a36Sopenharmony_ci	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
103162306a36Sopenharmony_ci	.fe_config	= {&fe_cineS2, &fe_cineS2},
103262306a36Sopenharmony_ci	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
103362306a36Sopenharmony_ci	.lnb		= {0x0b, 0x08},
103462306a36Sopenharmony_ci	.tsf		= {3, 3},
103562306a36Sopenharmony_ci	.fw_version	= 18,
103662306a36Sopenharmony_ci	.msi_supported	= true,
103762306a36Sopenharmony_ci};
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic const struct ngene_info ngene_info_satixS2 = {
104062306a36Sopenharmony_ci	.type		= NGENE_SIDEWINDER,
104162306a36Sopenharmony_ci	.name		= "Mystique SaTiX-S2 Dual",
104262306a36Sopenharmony_ci	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
104362306a36Sopenharmony_ci	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
104462306a36Sopenharmony_ci	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
104562306a36Sopenharmony_ci	.fe_config	= {&fe_cineS2, &fe_cineS2},
104662306a36Sopenharmony_ci	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
104762306a36Sopenharmony_ci	.lnb		= {0x0b, 0x08},
104862306a36Sopenharmony_ci	.tsf		= {3, 3},
104962306a36Sopenharmony_ci	.fw_version	= 18,
105062306a36Sopenharmony_ci	.msi_supported	= true,
105162306a36Sopenharmony_ci};
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic const struct ngene_info ngene_info_satixS2v2 = {
105462306a36Sopenharmony_ci	.type		= NGENE_SIDEWINDER,
105562306a36Sopenharmony_ci	.name		= "Mystique SaTiX-S2 Dual (v2)",
105662306a36Sopenharmony_ci	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
105762306a36Sopenharmony_ci			   NGENE_IO_TSOUT},
105862306a36Sopenharmony_ci	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
105962306a36Sopenharmony_ci	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
106062306a36Sopenharmony_ci	.fe_config	= {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
106162306a36Sopenharmony_ci	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
106262306a36Sopenharmony_ci	.lnb		= {0x0a, 0x08, 0x0b, 0x09},
106362306a36Sopenharmony_ci	.tsf		= {3, 3},
106462306a36Sopenharmony_ci	.fw_version	= 18,
106562306a36Sopenharmony_ci	.msi_supported	= true,
106662306a36Sopenharmony_ci};
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic const struct ngene_info ngene_info_cineS2v5 = {
106962306a36Sopenharmony_ci	.type		= NGENE_SIDEWINDER,
107062306a36Sopenharmony_ci	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)",
107162306a36Sopenharmony_ci	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
107262306a36Sopenharmony_ci			   NGENE_IO_TSOUT},
107362306a36Sopenharmony_ci	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
107462306a36Sopenharmony_ci	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
107562306a36Sopenharmony_ci	.fe_config	= {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
107662306a36Sopenharmony_ci	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
107762306a36Sopenharmony_ci	.lnb		= {0x0a, 0x08, 0x0b, 0x09},
107862306a36Sopenharmony_ci	.tsf		= {3, 3},
107962306a36Sopenharmony_ci	.fw_version	= 18,
108062306a36Sopenharmony_ci	.msi_supported	= true,
108162306a36Sopenharmony_ci};
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic const struct ngene_info ngene_info_duoFlex = {
108562306a36Sopenharmony_ci	.type           = NGENE_SIDEWINDER,
108662306a36Sopenharmony_ci	.name           = "Digital Devices DuoFlex PCIe or miniPCIe",
108762306a36Sopenharmony_ci	.io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
108862306a36Sopenharmony_ci			   NGENE_IO_TSOUT},
108962306a36Sopenharmony_ci	.demod_attach   = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},
109062306a36Sopenharmony_ci	.tuner_attach   = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe},
109162306a36Sopenharmony_ci	.fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
109262306a36Sopenharmony_ci	.tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
109362306a36Sopenharmony_ci	.lnb            = {0x0a, 0x08, 0x0b, 0x09},
109462306a36Sopenharmony_ci	.tsf            = {3, 3},
109562306a36Sopenharmony_ci	.fw_version     = 18,
109662306a36Sopenharmony_ci	.msi_supported	= true,
109762306a36Sopenharmony_ci};
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic const struct ngene_info ngene_info_m780 = {
110062306a36Sopenharmony_ci	.type           = NGENE_APP,
110162306a36Sopenharmony_ci	.name           = "Aver M780 ATSC/QAM-B",
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	/* Channel 0 is analog, which is currently unsupported */
110462306a36Sopenharmony_ci	.io_type        = { NGENE_IO_NONE, NGENE_IO_TSIN },
110562306a36Sopenharmony_ci	.demod_attach   = { NULL, demod_attach_lg330x },
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	/* Ensure these are NULL else the frame will call them (as funcs) */
110862306a36Sopenharmony_ci	.tuner_attach   = { NULL, NULL, NULL, NULL },
110962306a36Sopenharmony_ci	.fe_config      = { NULL, &aver_m780 },
111062306a36Sopenharmony_ci	.avf            = { 0 },
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/* A custom electrical interface config for the demod to bridge */
111362306a36Sopenharmony_ci	.tsf		= { 4, 4 },
111462306a36Sopenharmony_ci	.fw_version	= 15,
111562306a36Sopenharmony_ci};
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic struct drxd_config fe_terratec_dvbt_0 = {
111862306a36Sopenharmony_ci	.index          = 0,
111962306a36Sopenharmony_ci	.demod_address  = 0x70,
112062306a36Sopenharmony_ci	.demod_revision = 0xa2,
112162306a36Sopenharmony_ci	.demoda_address = 0x00,
112262306a36Sopenharmony_ci	.pll_address    = 0x60,
112362306a36Sopenharmony_ci	.pll_type       = DVB_PLL_THOMSON_DTT7520X,
112462306a36Sopenharmony_ci	.clock          = 20000,
112562306a36Sopenharmony_ci	.osc_deviation  = osc_deviation,
112662306a36Sopenharmony_ci};
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic struct drxd_config fe_terratec_dvbt_1 = {
112962306a36Sopenharmony_ci	.index          = 1,
113062306a36Sopenharmony_ci	.demod_address  = 0x71,
113162306a36Sopenharmony_ci	.demod_revision = 0xa2,
113262306a36Sopenharmony_ci	.demoda_address = 0x00,
113362306a36Sopenharmony_ci	.pll_address    = 0x60,
113462306a36Sopenharmony_ci	.pll_type       = DVB_PLL_THOMSON_DTT7520X,
113562306a36Sopenharmony_ci	.clock          = 20000,
113662306a36Sopenharmony_ci	.osc_deviation  = osc_deviation,
113762306a36Sopenharmony_ci};
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_cistatic const struct ngene_info ngene_info_terratec = {
114062306a36Sopenharmony_ci	.type           = NGENE_TERRATEC,
114162306a36Sopenharmony_ci	.name           = "Terratec Integra/Cinergy2400i Dual DVB-T",
114262306a36Sopenharmony_ci	.io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN},
114362306a36Sopenharmony_ci	.demod_attach   = {demod_attach_drxd, demod_attach_drxd},
114462306a36Sopenharmony_ci	.tuner_attach	= {tuner_attach_dtt7520x, tuner_attach_dtt7520x},
114562306a36Sopenharmony_ci	.fe_config      = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1},
114662306a36Sopenharmony_ci	.i2c_access     = 1,
114762306a36Sopenharmony_ci};
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci/****************************************************************************/
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci/****************************************************************************/
115462306a36Sopenharmony_ci/* PCI Subsystem ID *********************************************************/
115562306a36Sopenharmony_ci/****************************************************************************/
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci#define NGENE_ID(_subvend, _subdev, _driverdata) { \
115862306a36Sopenharmony_ci	.vendor = NGENE_VID, .device = NGENE_PID, \
115962306a36Sopenharmony_ci	.subvendor = _subvend, .subdevice = _subdev, \
116062306a36Sopenharmony_ci	.driver_data = (unsigned long) &_driverdata }
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci/****************************************************************************/
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic const struct pci_device_id ngene_id_tbl[] = {
116562306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xab04, ngene_info_cineS2),
116662306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xab05, ngene_info_cineS2v5),
116762306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
116862306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
116962306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
117062306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
117162306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
117262306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex),
117362306a36Sopenharmony_ci	NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
117462306a36Sopenharmony_ci	NGENE_ID(0x1461, 0x062e, ngene_info_m780),
117562306a36Sopenharmony_ci	NGENE_ID(0x153b, 0x1167, ngene_info_terratec),
117662306a36Sopenharmony_ci	{0}
117762306a36Sopenharmony_ci};
117862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ngene_id_tbl);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci/****************************************************************************/
118162306a36Sopenharmony_ci/* Init/Exit ****************************************************************/
118262306a36Sopenharmony_ci/****************************************************************************/
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_cistatic pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
118562306a36Sopenharmony_ci					     pci_channel_state_t state)
118662306a36Sopenharmony_ci{
118762306a36Sopenharmony_ci	dev_err(&dev->dev, "PCI error\n");
118862306a36Sopenharmony_ci	if (state == pci_channel_io_perm_failure)
118962306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
119062306a36Sopenharmony_ci	if (state == pci_channel_io_frozen)
119162306a36Sopenharmony_ci		return PCI_ERS_RESULT_NEED_RESET;
119262306a36Sopenharmony_ci	return PCI_ERS_RESULT_CAN_RECOVER;
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cistatic pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	dev_info(&dev->dev, "slot reset\n");
119862306a36Sopenharmony_ci	return 0;
119962306a36Sopenharmony_ci}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_cistatic void ngene_resume(struct pci_dev *dev)
120262306a36Sopenharmony_ci{
120362306a36Sopenharmony_ci	dev_info(&dev->dev, "resume\n");
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic const struct pci_error_handlers ngene_errors = {
120762306a36Sopenharmony_ci	.error_detected = ngene_error_detected,
120862306a36Sopenharmony_ci	.slot_reset = ngene_slot_reset,
120962306a36Sopenharmony_ci	.resume = ngene_resume,
121062306a36Sopenharmony_ci};
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_cistatic struct pci_driver ngene_pci_driver = {
121362306a36Sopenharmony_ci	.name        = "ngene",
121462306a36Sopenharmony_ci	.id_table    = ngene_id_tbl,
121562306a36Sopenharmony_ci	.probe       = ngene_probe,
121662306a36Sopenharmony_ci	.remove      = ngene_remove,
121762306a36Sopenharmony_ci	.err_handler = &ngene_errors,
121862306a36Sopenharmony_ci	.shutdown    = ngene_shutdown,
121962306a36Sopenharmony_ci};
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_cistatic __init int module_init_ngene(void)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	/* pr_*() since we don't have a device to use with dev_*() yet */
122462306a36Sopenharmony_ci	pr_info("nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	return pci_register_driver(&ngene_pci_driver);
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cistatic __exit void module_exit_ngene(void)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	pci_unregister_driver(&ngene_pci_driver);
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cimodule_init(module_init_ngene);
123562306a36Sopenharmony_cimodule_exit(module_exit_ngene);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ciMODULE_DESCRIPTION("nGene");
123862306a36Sopenharmony_ciMODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
123962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1240