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 = ®, .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