Path: blob/master/drivers/media/dvb/ngene/ngene-cards.c
15112 views
/*1* ngene-cards.c: nGene PCIe bridge driver - card specific info2*3* Copyright (C) 2005-2007 Micronas4*5* Copyright (C) 2008-2009 Ralph Metzler <[email protected]>6* Modifications for new nGene firmware,7* support for EEPROM-copying,8* support for new dual DVB-S2 card prototype9*10*11* This program is free software; you can redistribute it and/or12* modify it under the terms of the GNU General Public License13* version 2 only, as published by the Free Software Foundation.14*15*16* This program is distributed in the hope that it will be useful,17* but WITHOUT ANY WARRANTY; without even the implied warranty of18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the19* GNU General Public License for more details.20*21*22* You should have received a copy of the GNU General Public License23* along with this program; if not, write to the Free Software24* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA25* 02110-1301, USA26* Or, point your browser to http://www.gnu.org/copyleft/gpl.html27*/2829#include <linux/module.h>30#include <linux/init.h>31#include <linux/pci.h>32#include <linux/pci_ids.h>3334#include "ngene.h"3536/* demods/tuners */37#include "stv6110x.h"38#include "stv090x.h"39#include "lnbh24.h"40#include "lgdt330x.h"41#include "mt2131.h"424344/****************************************************************************/45/* Demod/tuner attachment ***************************************************/46/****************************************************************************/4748static int tuner_attach_stv6110(struct ngene_channel *chan)49{50struct i2c_adapter *i2c;51struct stv090x_config *feconf = (struct stv090x_config *)52chan->dev->card_info->fe_config[chan->number];53struct stv6110x_config *tunerconf = (struct stv6110x_config *)54chan->dev->card_info->tuner_config[chan->number];55struct stv6110x_devctl *ctl;5657/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */58if (chan->number < 2)59i2c = &chan->dev->channel[0].i2c_adapter;60else61i2c = &chan->dev->channel[1].i2c_adapter;6263ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c);64if (ctl == NULL) {65printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n");66return -ENODEV;67}6869feconf->tuner_init = ctl->tuner_init;70feconf->tuner_sleep = ctl->tuner_sleep;71feconf->tuner_set_mode = ctl->tuner_set_mode;72feconf->tuner_set_frequency = ctl->tuner_set_frequency;73feconf->tuner_get_frequency = ctl->tuner_get_frequency;74feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;75feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;76feconf->tuner_set_bbgain = ctl->tuner_set_bbgain;77feconf->tuner_get_bbgain = ctl->tuner_get_bbgain;78feconf->tuner_set_refclk = ctl->tuner_set_refclk;79feconf->tuner_get_status = ctl->tuner_get_status;8081return 0;82}838485static int demod_attach_stv0900(struct ngene_channel *chan)86{87struct i2c_adapter *i2c;88struct stv090x_config *feconf = (struct stv090x_config *)89chan->dev->card_info->fe_config[chan->number];9091/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */92/* Note: Both adapters share the same i2c bus, but the demod */93/* driver requires that each demod has its own i2c adapter */94if (chan->number < 2)95i2c = &chan->dev->channel[0].i2c_adapter;96else97i2c = &chan->dev->channel[1].i2c_adapter;9899chan->fe = dvb_attach(stv090x_attach, feconf, i2c,100(chan->number & 1) == 0 ? STV090x_DEMODULATOR_0101: STV090x_DEMODULATOR_1);102if (chan->fe == NULL) {103printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n");104return -ENODEV;105}106107/* store channel info */108if (feconf->tuner_i2c_lock)109chan->fe->analog_demod_priv = chan;110111if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0,1120, chan->dev->card_info->lnb[chan->number])) {113printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");114dvb_frontend_detach(chan->fe);115chan->fe = NULL;116return -ENODEV;117}118119return 0;120}121122static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)123{124struct ngene_channel *chan = fe->analog_demod_priv;125126if (lock)127down(&chan->dev->pll_mutex);128else129up(&chan->dev->pll_mutex);130}131132static int cineS2_probe(struct ngene_channel *chan)133{134struct i2c_adapter *i2c;135struct stv090x_config *fe_conf;136u8 buf[3];137struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };138int rc;139140/* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */141if (chan->number < 2)142i2c = &chan->dev->channel[0].i2c_adapter;143else144i2c = &chan->dev->channel[1].i2c_adapter;145146fe_conf = chan->dev->card_info->fe_config[chan->number];147i2c_msg.addr = fe_conf->address;148149/* probe demod */150i2c_msg.len = 2;151buf[0] = 0xf1;152buf[1] = 0x00;153rc = i2c_transfer(i2c, &i2c_msg, 1);154if (rc != 1)155return -ENODEV;156157/* demod found, attach it */158rc = demod_attach_stv0900(chan);159if (rc < 0 || chan->number < 2)160return rc;161162/* demod #2: reprogram outputs DPN1 & DPN2 */163i2c_msg.len = 3;164buf[0] = 0xf1;165switch (chan->number) {166case 2:167buf[1] = 0x5c;168buf[2] = 0xc2;169break;170case 3:171buf[1] = 0x61;172buf[2] = 0xcc;173break;174default:175return -ENODEV;176}177rc = i2c_transfer(i2c, &i2c_msg, 1);178if (rc != 1) {179printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");180return -EIO;181}182183return 0;184}185186187static struct lgdt330x_config aver_m780 = {188.demod_address = 0xb2 >> 1,189.demod_chip = LGDT3303,190.serial_mpeg = 0x00, /* PARALLEL */191.clock_polarity_flip = 1,192};193194static struct mt2131_config m780_tunerconfig = {1950xc0 >> 1196};197198/* A single func to attach the demo and tuner, rather than199* use two sep funcs like the current design mandates.200*/201static int demod_attach_lg330x(struct ngene_channel *chan)202{203chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter);204if (chan->fe == NULL) {205printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n");206return -ENODEV;207}208209dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter,210&m780_tunerconfig, 0);211212return (chan->fe) ? 0 : -ENODEV;213}214215/****************************************************************************/216/* Switch control (I2C gates, etc.) *****************************************/217/****************************************************************************/218219220static struct stv090x_config fe_cineS2 = {221.device = STV0900,222.demod_mode = STV090x_DUAL,223.clk_mode = STV090x_CLK_EXT,224225.xtal = 27000000,226.address = 0x68,227228.ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED,229.ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED,230231.repeater_level = STV090x_RPTLEVEL_16,232233.adc1_range = STV090x_ADC_1Vpp,234.adc2_range = STV090x_ADC_1Vpp,235236.diseqc_envelope_mode = true,237238.tuner_i2c_lock = cineS2_tuner_i2c_lock,239};240241static struct stv090x_config fe_cineS2_2 = {242.device = STV0900,243.demod_mode = STV090x_DUAL,244.clk_mode = STV090x_CLK_EXT,245246.xtal = 27000000,247.address = 0x69,248249.ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED,250.ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED,251252.repeater_level = STV090x_RPTLEVEL_16,253254.adc1_range = STV090x_ADC_1Vpp,255.adc2_range = STV090x_ADC_1Vpp,256257.diseqc_envelope_mode = true,258259.tuner_i2c_lock = cineS2_tuner_i2c_lock,260};261262static struct stv6110x_config tuner_cineS2_0 = {263.addr = 0x60,264.refclk = 27000000,265.clk_div = 1,266};267268static struct stv6110x_config tuner_cineS2_1 = {269.addr = 0x63,270.refclk = 27000000,271.clk_div = 1,272};273274static struct ngene_info ngene_info_cineS2 = {275.type = NGENE_SIDEWINDER,276.name = "Linux4Media cineS2 DVB-S2 Twin Tuner",277.io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},278.demod_attach = {demod_attach_stv0900, demod_attach_stv0900},279.tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},280.fe_config = {&fe_cineS2, &fe_cineS2},281.tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},282.lnb = {0x0b, 0x08},283.tsf = {3, 3},284.fw_version = 18,285.msi_supported = true,286};287288static struct ngene_info ngene_info_satixS2 = {289.type = NGENE_SIDEWINDER,290.name = "Mystique SaTiX-S2 Dual",291.io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},292.demod_attach = {demod_attach_stv0900, demod_attach_stv0900},293.tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},294.fe_config = {&fe_cineS2, &fe_cineS2},295.tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},296.lnb = {0x0b, 0x08},297.tsf = {3, 3},298.fw_version = 18,299.msi_supported = true,300};301302static struct ngene_info ngene_info_satixS2v2 = {303.type = NGENE_SIDEWINDER,304.name = "Mystique SaTiX-S2 Dual (v2)",305.io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,306NGENE_IO_TSOUT},307.demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},308.tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},309.fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},310.tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},311.lnb = {0x0a, 0x08, 0x0b, 0x09},312.tsf = {3, 3},313.fw_version = 18,314.msi_supported = true,315};316317static struct ngene_info ngene_info_cineS2v5 = {318.type = NGENE_SIDEWINDER,319.name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)",320.io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,321NGENE_IO_TSOUT},322.demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},323.tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},324.fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},325.tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},326.lnb = {0x0a, 0x08, 0x0b, 0x09},327.tsf = {3, 3},328.fw_version = 18,329.msi_supported = true,330};331332333static struct ngene_info ngene_info_duoFlexS2 = {334.type = NGENE_SIDEWINDER,335.name = "Digital Devices DuoFlex S2 miniPCIe",336.io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,337NGENE_IO_TSOUT},338.demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},339.tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},340.fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},341.tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},342.lnb = {0x0a, 0x08, 0x0b, 0x09},343.tsf = {3, 3},344.fw_version = 18,345.msi_supported = true,346};347348static struct ngene_info ngene_info_m780 = {349.type = NGENE_APP,350.name = "Aver M780 ATSC/QAM-B",351352/* Channel 0 is analog, which is currently unsupported */353.io_type = { NGENE_IO_NONE, NGENE_IO_TSIN },354.demod_attach = { NULL, demod_attach_lg330x },355356/* Ensure these are NULL else the frame will call them (as funcs) */357.tuner_attach = { 0, 0, 0, 0 },358.fe_config = { NULL, &aver_m780 },359.avf = { 0 },360361/* A custom electrical interface config for the demod to bridge */362.tsf = { 4, 4 },363.fw_version = 15,364};365366/****************************************************************************/367368369370/****************************************************************************/371/* PCI Subsystem ID *********************************************************/372/****************************************************************************/373374#define NGENE_ID(_subvend, _subdev, _driverdata) { \375.vendor = NGENE_VID, .device = NGENE_PID, \376.subvendor = _subvend, .subdevice = _subdev, \377.driver_data = (unsigned long) &_driverdata }378379/****************************************************************************/380381static const struct pci_device_id ngene_id_tbl[] __devinitdata = {382NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),383NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),384NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),385NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),386NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),387NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2),388NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2),389NGENE_ID(0x1461, 0x062e, ngene_info_m780),390{0}391};392MODULE_DEVICE_TABLE(pci, ngene_id_tbl);393394/****************************************************************************/395/* Init/Exit ****************************************************************/396/****************************************************************************/397398static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,399enum pci_channel_state state)400{401printk(KERN_ERR DEVICE_NAME ": PCI error\n");402if (state == pci_channel_io_perm_failure)403return PCI_ERS_RESULT_DISCONNECT;404if (state == pci_channel_io_frozen)405return PCI_ERS_RESULT_NEED_RESET;406return PCI_ERS_RESULT_CAN_RECOVER;407}408409static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)410{411printk(KERN_INFO DEVICE_NAME ": link reset\n");412return 0;413}414415static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)416{417printk(KERN_INFO DEVICE_NAME ": slot reset\n");418return 0;419}420421static void ngene_resume(struct pci_dev *dev)422{423printk(KERN_INFO DEVICE_NAME ": resume\n");424}425426static struct pci_error_handlers ngene_errors = {427.error_detected = ngene_error_detected,428.link_reset = ngene_link_reset,429.slot_reset = ngene_slot_reset,430.resume = ngene_resume,431};432433static struct pci_driver ngene_pci_driver = {434.name = "ngene",435.id_table = ngene_id_tbl,436.probe = ngene_probe,437.remove = __devexit_p(ngene_remove),438.err_handler = &ngene_errors,439.shutdown = ngene_shutdown,440};441442static __init int module_init_ngene(void)443{444printk(KERN_INFO445"nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");446return pci_register_driver(&ngene_pci_driver);447}448449static __exit void module_exit_ngene(void)450{451pci_unregister_driver(&ngene_pci_driver);452}453454module_init(module_init_ngene);455module_exit(module_exit_ngene);456457MODULE_DESCRIPTION("nGene");458MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");459MODULE_LICENSE("GPL");460461462