18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ngene-cards.c: nGene PCIe bridge driver - card specific info 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 Micronas 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de> 88c2ecf20Sopenharmony_ci * Modifications for new nGene firmware, 98c2ecf20Sopenharmony_ci * support for EEPROM-copying, 108c2ecf20Sopenharmony_ci * support for new dual DVB-S2 card prototype 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "ngene.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* demods/tuners */ 238c2ecf20Sopenharmony_ci#include "stv6110x.h" 248c2ecf20Sopenharmony_ci#include "stv090x.h" 258c2ecf20Sopenharmony_ci#include "lnbh24.h" 268c2ecf20Sopenharmony_ci#include "lgdt330x.h" 278c2ecf20Sopenharmony_ci#include "mt2131.h" 288c2ecf20Sopenharmony_ci#include "tda18271c2dd.h" 298c2ecf20Sopenharmony_ci#include "drxk.h" 308c2ecf20Sopenharmony_ci#include "drxd.h" 318c2ecf20Sopenharmony_ci#include "dvb-pll.h" 328c2ecf20Sopenharmony_ci#include "stv0367.h" 338c2ecf20Sopenharmony_ci#include "stv0367_priv.h" 348c2ecf20Sopenharmony_ci#include "tda18212.h" 358c2ecf20Sopenharmony_ci#include "cxd2841er.h" 368c2ecf20Sopenharmony_ci#include "stv0910.h" 378c2ecf20Sopenharmony_ci#include "stv6111.h" 388c2ecf20Sopenharmony_ci#include "lnbh25.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/****************************************************************************/ 418c2ecf20Sopenharmony_ci/* I2C transfer functions used for demod/tuner probing***********************/ 428c2ecf20Sopenharmony_ci/****************************************************************************/ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int i2c_io(struct i2c_adapter *adapter, u8 adr, 458c2ecf20Sopenharmony_ci u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, 488c2ecf20Sopenharmony_ci .buf = wbuf, .len = wlen }, 498c2ecf20Sopenharmony_ci {.addr = adr, .flags = I2C_M_RD, 508c2ecf20Sopenharmony_ci .buf = rbuf, .len = rlen } }; 518c2ecf20Sopenharmony_ci return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct i2c_msg msg = {.addr = adr, .flags = 0, 578c2ecf20Sopenharmony_ci .buf = data, .len = len}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int i2c_write_reg(struct i2c_adapter *adap, u8 adr, 638c2ecf20Sopenharmony_ci u8 reg, u8 val) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci u8 msg[2] = {reg, val}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return i2c_write(adap, adr, msg, 2); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, 738c2ecf20Sopenharmony_ci .buf = val, .len = 1 } }; 748c2ecf20Sopenharmony_ci return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, 788c2ecf20Sopenharmony_ci u16 reg, u8 *val) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci u8 msg[2] = {reg >> 8, reg & 0xff}; 818c2ecf20Sopenharmony_ci struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, 828c2ecf20Sopenharmony_ci .buf = msg, .len = 2}, 838c2ecf20Sopenharmony_ci {.addr = adr, .flags = I2C_M_RD, 848c2ecf20Sopenharmony_ci .buf = val, .len = 1} }; 858c2ecf20Sopenharmony_ci return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int i2c_read_regs(struct i2c_adapter *adapter, 898c2ecf20Sopenharmony_ci u8 adr, u8 reg, u8 *val, u8 len) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, 928c2ecf20Sopenharmony_ci .buf = ®, .len = 1}, 938c2ecf20Sopenharmony_ci {.addr = adr, .flags = I2C_M_RD, 948c2ecf20Sopenharmony_ci .buf = val, .len = len} }; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci return i2c_read_regs(adapter, adr, reg, val, 1); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/****************************************************************************/ 1058c2ecf20Sopenharmony_ci/* Demod/tuner attachment ***************************************************/ 1068c2ecf20Sopenharmony_ci/****************************************************************************/ 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic struct i2c_adapter *i2c_adapter_from_chan(struct ngene_channel *chan) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ 1118c2ecf20Sopenharmony_ci if (chan->number < 2) 1128c2ecf20Sopenharmony_ci return &chan->dev->channel[0].i2c_adapter; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return &chan->dev->channel[1].i2c_adapter; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int tuner_attach_stv6110(struct ngene_channel *chan) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 1208c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); 1218c2ecf20Sopenharmony_ci struct stv090x_config *feconf = (struct stv090x_config *) 1228c2ecf20Sopenharmony_ci chan->dev->card_info->fe_config[chan->number]; 1238c2ecf20Sopenharmony_ci struct stv6110x_config *tunerconf = (struct stv6110x_config *) 1248c2ecf20Sopenharmony_ci chan->dev->card_info->tuner_config[chan->number]; 1258c2ecf20Sopenharmony_ci const struct stv6110x_devctl *ctl; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); 1288c2ecf20Sopenharmony_ci if (ctl == NULL) { 1298c2ecf20Sopenharmony_ci dev_err(pdev, "No STV6110X found!\n"); 1308c2ecf20Sopenharmony_ci return -ENODEV; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci feconf->tuner_init = ctl->tuner_init; 1348c2ecf20Sopenharmony_ci feconf->tuner_sleep = ctl->tuner_sleep; 1358c2ecf20Sopenharmony_ci feconf->tuner_set_mode = ctl->tuner_set_mode; 1368c2ecf20Sopenharmony_ci feconf->tuner_set_frequency = ctl->tuner_set_frequency; 1378c2ecf20Sopenharmony_ci feconf->tuner_get_frequency = ctl->tuner_get_frequency; 1388c2ecf20Sopenharmony_ci feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth; 1398c2ecf20Sopenharmony_ci feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth; 1408c2ecf20Sopenharmony_ci feconf->tuner_set_bbgain = ctl->tuner_set_bbgain; 1418c2ecf20Sopenharmony_ci feconf->tuner_get_bbgain = ctl->tuner_get_bbgain; 1428c2ecf20Sopenharmony_ci feconf->tuner_set_refclk = ctl->tuner_set_refclk; 1438c2ecf20Sopenharmony_ci feconf->tuner_get_status = ctl->tuner_get_status; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int tuner_attach_stv6111(struct ngene_channel *chan) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 1518c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); 1528c2ecf20Sopenharmony_ci struct dvb_frontend *fe; 1538c2ecf20Sopenharmony_ci u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr); 1568c2ecf20Sopenharmony_ci if (!fe) { 1578c2ecf20Sopenharmony_ci fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4); 1588c2ecf20Sopenharmony_ci if (!fe) { 1598c2ecf20Sopenharmony_ci dev_err(pdev, "stv6111_attach() failed!\n"); 1608c2ecf20Sopenharmony_ci return -ENODEV; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct ngene_channel *chan = fe->sec_priv; 1698c2ecf20Sopenharmony_ci int status; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (enable) { 1728c2ecf20Sopenharmony_ci down(&chan->dev->pll_mutex); 1738c2ecf20Sopenharmony_ci status = chan->gate_ctrl(fe, 1); 1748c2ecf20Sopenharmony_ci } else { 1758c2ecf20Sopenharmony_ci status = chan->gate_ctrl(fe, 0); 1768c2ecf20Sopenharmony_ci up(&chan->dev->pll_mutex); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci return status; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int tuner_attach_tda18271(struct ngene_channel *chan) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 1848c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); 1858c2ecf20Sopenharmony_ci struct dvb_frontend *fe; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (chan->fe->ops.i2c_gate_ctrl) 1888c2ecf20Sopenharmony_ci chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); 1898c2ecf20Sopenharmony_ci fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); 1908c2ecf20Sopenharmony_ci if (chan->fe->ops.i2c_gate_ctrl) 1918c2ecf20Sopenharmony_ci chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); 1928c2ecf20Sopenharmony_ci if (!fe) { 1938c2ecf20Sopenharmony_ci dev_err(pdev, "No TDA18271 found!\n"); 1948c2ecf20Sopenharmony_ci return -ENODEV; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int tuner_tda18212_ping(struct ngene_channel *chan, 2018c2ecf20Sopenharmony_ci struct i2c_adapter *i2c, 2028c2ecf20Sopenharmony_ci unsigned short adr) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 2058c2ecf20Sopenharmony_ci u8 tda_id[2]; 2068c2ecf20Sopenharmony_ci u8 subaddr = 0x00; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci dev_dbg(pdev, "stv0367-tda18212 tuner ping\n"); 2098c2ecf20Sopenharmony_ci if (chan->fe->ops.i2c_gate_ctrl) 2108c2ecf20Sopenharmony_ci chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0) 2138c2ecf20Sopenharmony_ci dev_dbg(pdev, "tda18212 ping 1 fail\n"); 2148c2ecf20Sopenharmony_ci if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0) 2158c2ecf20Sopenharmony_ci dev_warn(pdev, "tda18212 ping failed, expect problems\n"); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (chan->fe->ops.i2c_gate_ctrl) 2188c2ecf20Sopenharmony_ci chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 2268c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); 2278c2ecf20Sopenharmony_ci struct i2c_client *client; 2288c2ecf20Sopenharmony_ci struct tda18212_config config = { 2298c2ecf20Sopenharmony_ci .fe = chan->fe, 2308c2ecf20Sopenharmony_ci .if_dvbt_6 = 3550, 2318c2ecf20Sopenharmony_ci .if_dvbt_7 = 3700, 2328c2ecf20Sopenharmony_ci .if_dvbt_8 = 4150, 2338c2ecf20Sopenharmony_ci .if_dvbt2_6 = 3250, 2348c2ecf20Sopenharmony_ci .if_dvbt2_7 = 4000, 2358c2ecf20Sopenharmony_ci .if_dvbt2_8 = 4000, 2368c2ecf20Sopenharmony_ci .if_dvbc = 5000, 2378c2ecf20Sopenharmony_ci }; 2388c2ecf20Sopenharmony_ci u8 addr = (chan->number & 1) ? 0x63 : 0x60; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* 2418c2ecf20Sopenharmony_ci * due to a hardware quirk with the I2C gate on the stv0367+tda18212 2428c2ecf20Sopenharmony_ci * combo, the tda18212 must be probed by reading it's id _twice_ when 2438c2ecf20Sopenharmony_ci * cold started, or it very likely will fail. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci if (dmdtype == DEMOD_TYPE_STV0367) 2468c2ecf20Sopenharmony_ci tuner_tda18212_ping(chan, i2c, addr); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* perform tuner probe/init/attach */ 2498c2ecf20Sopenharmony_ci client = dvb_module_probe("tda18212", NULL, i2c, addr, &config); 2508c2ecf20Sopenharmony_ci if (!client) 2518c2ecf20Sopenharmony_ci goto err; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci chan->i2c_client[0] = client; 2548c2ecf20Sopenharmony_ci chan->i2c_client_fe = 1; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_cierr: 2588c2ecf20Sopenharmony_ci dev_err(pdev, "TDA18212 tuner not found. Device is not fully operational.\n"); 2598c2ecf20Sopenharmony_ci return -ENODEV; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int tuner_attach_probe(struct ngene_channel *chan) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci switch (chan->demod_type) { 2658c2ecf20Sopenharmony_ci case DEMOD_TYPE_STV090X: 2668c2ecf20Sopenharmony_ci return tuner_attach_stv6110(chan); 2678c2ecf20Sopenharmony_ci case DEMOD_TYPE_DRXK: 2688c2ecf20Sopenharmony_ci return tuner_attach_tda18271(chan); 2698c2ecf20Sopenharmony_ci case DEMOD_TYPE_STV0367: 2708c2ecf20Sopenharmony_ci case DEMOD_TYPE_SONY_CT2: 2718c2ecf20Sopenharmony_ci case DEMOD_TYPE_SONY_ISDBT: 2728c2ecf20Sopenharmony_ci case DEMOD_TYPE_SONY_C2T2: 2738c2ecf20Sopenharmony_ci case DEMOD_TYPE_SONY_C2T2I: 2748c2ecf20Sopenharmony_ci return tuner_attach_tda18212(chan, chan->demod_type); 2758c2ecf20Sopenharmony_ci case DEMOD_TYPE_STV0910: 2768c2ecf20Sopenharmony_ci return tuner_attach_stv6111(chan); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return -EINVAL; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int demod_attach_stv0900(struct ngene_channel *chan) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 2858c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); 2868c2ecf20Sopenharmony_ci struct stv090x_config *feconf = (struct stv090x_config *) 2878c2ecf20Sopenharmony_ci chan->dev->card_info->fe_config[chan->number]; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci chan->fe = dvb_attach(stv090x_attach, feconf, i2c, 2908c2ecf20Sopenharmony_ci (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 2918c2ecf20Sopenharmony_ci : STV090x_DEMODULATOR_1); 2928c2ecf20Sopenharmony_ci if (chan->fe == NULL) { 2938c2ecf20Sopenharmony_ci dev_err(pdev, "No STV0900 found!\n"); 2948c2ecf20Sopenharmony_ci return -ENODEV; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* store channel info */ 2988c2ecf20Sopenharmony_ci if (feconf->tuner_i2c_lock) 2998c2ecf20Sopenharmony_ci chan->fe->analog_demod_priv = chan; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, 3028c2ecf20Sopenharmony_ci 0, chan->dev->card_info->lnb[chan->number])) { 3038c2ecf20Sopenharmony_ci dev_err(pdev, "No LNBH24 found!\n"); 3048c2ecf20Sopenharmony_ci dvb_frontend_detach(chan->fe); 3058c2ecf20Sopenharmony_ci chan->fe = NULL; 3068c2ecf20Sopenharmony_ci return -ENODEV; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic struct stv0910_cfg stv0910_p = { 3138c2ecf20Sopenharmony_ci .adr = 0x68, 3148c2ecf20Sopenharmony_ci .parallel = 1, 3158c2ecf20Sopenharmony_ci .rptlvl = 4, 3168c2ecf20Sopenharmony_ci .clk = 30000000, 3178c2ecf20Sopenharmony_ci .tsspeed = 0x28, 3188c2ecf20Sopenharmony_ci}; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic struct lnbh25_config lnbh25_cfg = { 3218c2ecf20Sopenharmony_ci .i2c_address = 0x0c << 1, 3228c2ecf20Sopenharmony_ci .data2_config = LNBH25_TEN 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int demod_attach_stv0910(struct ngene_channel *chan, 3268c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 3298c2ecf20Sopenharmony_ci struct stv0910_cfg cfg = stv0910_p; 3308c2ecf20Sopenharmony_ci struct lnbh25_config lnbcfg = lnbh25_cfg; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci chan->fe = dvb_attach(stv0910_attach, i2c, &cfg, (chan->number & 1)); 3338c2ecf20Sopenharmony_ci if (!chan->fe) { 3348c2ecf20Sopenharmony_ci cfg.adr = 0x6c; 3358c2ecf20Sopenharmony_ci chan->fe = dvb_attach(stv0910_attach, i2c, 3368c2ecf20Sopenharmony_ci &cfg, (chan->number & 1)); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci if (!chan->fe) { 3398c2ecf20Sopenharmony_ci dev_err(pdev, "stv0910_attach() failed!\n"); 3408c2ecf20Sopenharmony_ci return -ENODEV; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit 3458c2ecf20Sopenharmony_ci * i2c addresses 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci lnbcfg.i2c_address = (((chan->number & 1) ? 0x0d : 0x0c) << 1); 3488c2ecf20Sopenharmony_ci if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { 3498c2ecf20Sopenharmony_ci lnbcfg.i2c_address = (((chan->number & 1) ? 0x09 : 0x08) << 1); 3508c2ecf20Sopenharmony_ci if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { 3518c2ecf20Sopenharmony_ci dev_err(pdev, "lnbh25_attach() failed!\n"); 3528c2ecf20Sopenharmony_ci dvb_frontend_detach(chan->fe); 3538c2ecf20Sopenharmony_ci chan->fe = NULL; 3548c2ecf20Sopenharmony_ci return -ENODEV; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic struct stv0367_config ddb_stv0367_config[] = { 3628c2ecf20Sopenharmony_ci { 3638c2ecf20Sopenharmony_ci .demod_address = 0x1f, 3648c2ecf20Sopenharmony_ci .xtal = 27000000, 3658c2ecf20Sopenharmony_ci .if_khz = 0, 3668c2ecf20Sopenharmony_ci .if_iq_mode = FE_TER_NORMAL_IF_TUNER, 3678c2ecf20Sopenharmony_ci .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, 3688c2ecf20Sopenharmony_ci .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, 3698c2ecf20Sopenharmony_ci }, { 3708c2ecf20Sopenharmony_ci .demod_address = 0x1e, 3718c2ecf20Sopenharmony_ci .xtal = 27000000, 3728c2ecf20Sopenharmony_ci .if_khz = 0, 3738c2ecf20Sopenharmony_ci .if_iq_mode = FE_TER_NORMAL_IF_TUNER, 3748c2ecf20Sopenharmony_ci .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, 3758c2ecf20Sopenharmony_ci .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, 3768c2ecf20Sopenharmony_ci }, 3778c2ecf20Sopenharmony_ci}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int demod_attach_stv0367(struct ngene_channel *chan, 3808c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci chan->fe = dvb_attach(stv0367ddb_attach, 3858c2ecf20Sopenharmony_ci &ddb_stv0367_config[(chan->number & 1)], i2c); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (!chan->fe) { 3888c2ecf20Sopenharmony_ci dev_err(pdev, "stv0367ddb_attach() failed!\n"); 3898c2ecf20Sopenharmony_ci return -ENODEV; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci chan->fe->sec_priv = chan; 3938c2ecf20Sopenharmony_ci chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; 3948c2ecf20Sopenharmony_ci chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int demod_attach_cxd28xx(struct ngene_channel *chan, 3998c2ecf20Sopenharmony_ci struct i2c_adapter *i2c, int osc24) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 4028c2ecf20Sopenharmony_ci struct cxd2841er_config cfg; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* the cxd2841er driver expects 8bit/shifted I2C addresses */ 4058c2ecf20Sopenharmony_ci cfg.i2c_addr = ((chan->number & 1) ? 0x6d : 0x6c) << 1; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500; 4088c2ecf20Sopenharmony_ci cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE | 4098c2ecf20Sopenharmony_ci CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG | 4108c2ecf20Sopenharmony_ci CXD2841ER_TSBITS | CXD2841ER_TS_SERIAL; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* attach frontend */ 4138c2ecf20Sopenharmony_ci chan->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (!chan->fe) { 4168c2ecf20Sopenharmony_ci dev_err(pdev, "CXD28XX attach failed!\n"); 4178c2ecf20Sopenharmony_ci return -ENODEV; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci chan->fe->sec_priv = chan; 4218c2ecf20Sopenharmony_ci chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; 4228c2ecf20Sopenharmony_ci chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct ngene_channel *chan = fe->analog_demod_priv; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (lock) 4318c2ecf20Sopenharmony_ci down(&chan->dev->pll_mutex); 4328c2ecf20Sopenharmony_ci else 4338c2ecf20Sopenharmony_ci up(&chan->dev->pll_mutex); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int port_has_stv0900(struct i2c_adapter *i2c, int port) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci u8 val; 4398c2ecf20Sopenharmony_ci if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0) 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci return 1; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int port_has_drxk(struct i2c_adapter *i2c, int port) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci u8 val; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (i2c_read(i2c, 0x29+port, &val) < 0) 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci return 1; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int port_has_stv0367(struct i2c_adapter *i2c) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci u8 val; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (i2c_read_reg16(i2c, 0x1e, 0xf000, &val) < 0) 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci if (val != 0x60) 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci if (i2c_read_reg16(i2c, 0x1f, 0xf000, &val) < 0) 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci if (val != 0x60) 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci return 1; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ciint ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci u8 val; 4718c2ecf20Sopenharmony_ci u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4]; 4728c2ecf20Sopenharmony_ci struct i2c_msg msgs[2] = {{ .addr = 0x40, .flags = 0, 4738c2ecf20Sopenharmony_ci .buf = probe, .len = 4 }, 4748c2ecf20Sopenharmony_ci { .addr = 0x40, .flags = I2C_M_RD, 4758c2ecf20Sopenharmony_ci .buf = data, .len = 4 } }; 4768c2ecf20Sopenharmony_ci val = i2c_transfer(i2c, msgs, 2); 4778c2ecf20Sopenharmony_ci if (val != 2) 4788c2ecf20Sopenharmony_ci return 0; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43) 4818c2ecf20Sopenharmony_ci *type = 2; 4828c2ecf20Sopenharmony_ci else 4838c2ecf20Sopenharmony_ci *type = 1; 4848c2ecf20Sopenharmony_ci return 1; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic int demod_attach_drxk(struct ngene_channel *chan, 4888c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 4918c2ecf20Sopenharmony_ci struct drxk_config config; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci memset(&config, 0, sizeof(config)); 4948c2ecf20Sopenharmony_ci config.microcode_name = "drxk_a3.mc"; 4958c2ecf20Sopenharmony_ci config.qam_demod_parameter_count = 4; 4968c2ecf20Sopenharmony_ci config.adr = 0x29 + (chan->number ^ 2); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci chan->fe = dvb_attach(drxk_attach, &config, i2c); 4998c2ecf20Sopenharmony_ci if (!chan->fe) { 5008c2ecf20Sopenharmony_ci dev_err(pdev, "No DRXK found!\n"); 5018c2ecf20Sopenharmony_ci return -ENODEV; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci chan->fe->sec_priv = chan; 5048c2ecf20Sopenharmony_ci chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; 5058c2ecf20Sopenharmony_ci chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/****************************************************************************/ 5108c2ecf20Sopenharmony_ci/* XO2 related lists and functions ******************************************/ 5118c2ecf20Sopenharmony_ci/****************************************************************************/ 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic char *xo2names[] = { 5148c2ecf20Sopenharmony_ci "DUAL DVB-S2", 5158c2ecf20Sopenharmony_ci "DUAL DVB-C/T/T2", 5168c2ecf20Sopenharmony_ci "DUAL DVB-ISDBT", 5178c2ecf20Sopenharmony_ci "DUAL DVB-C/C2/T/T2", 5188c2ecf20Sopenharmony_ci "DUAL ATSC", 5198c2ecf20Sopenharmony_ci "DUAL DVB-C/C2/T/T2/I", 5208c2ecf20Sopenharmony_ci}; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic int init_xo2(struct ngene_channel *chan, struct i2c_adapter *i2c) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 5258c2ecf20Sopenharmony_ci u8 addr = 0x10; 5268c2ecf20Sopenharmony_ci u8 val, data[2]; 5278c2ecf20Sopenharmony_ci int res; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci res = i2c_read_regs(i2c, addr, 0x04, data, 2); 5308c2ecf20Sopenharmony_ci if (res < 0) 5318c2ecf20Sopenharmony_ci return res; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (data[0] != 0x01) { 5348c2ecf20Sopenharmony_ci dev_info(pdev, "Invalid XO2 on channel %d\n", chan->number); 5358c2ecf20Sopenharmony_ci return -1; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci i2c_read_reg(i2c, addr, 0x08, &val); 5398c2ecf20Sopenharmony_ci if (val != 0) { 5408c2ecf20Sopenharmony_ci i2c_write_reg(i2c, addr, 0x08, 0x00); 5418c2ecf20Sopenharmony_ci msleep(100); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci /* Enable tuner power, disable pll, reset demods */ 5448c2ecf20Sopenharmony_ci i2c_write_reg(i2c, addr, 0x08, 0x04); 5458c2ecf20Sopenharmony_ci usleep_range(2000, 3000); 5468c2ecf20Sopenharmony_ci /* Release demod resets */ 5478c2ecf20Sopenharmony_ci i2c_write_reg(i2c, addr, 0x08, 0x07); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* 5508c2ecf20Sopenharmony_ci * speed: 0=55,1=75,2=90,3=104 MBit/s 5518c2ecf20Sopenharmony_ci * Note: The ngene hardware must be run at 75 MBit/s compared 5528c2ecf20Sopenharmony_ci * to more modern ddbridge hardware which runs at 90 MBit/s, 5538c2ecf20Sopenharmony_ci * else there will be issues with the data transport and non- 5548c2ecf20Sopenharmony_ci * working secondary/slave demods/tuners. 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_ci i2c_write_reg(i2c, addr, 0x09, 1); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci i2c_write_reg(i2c, addr, 0x0a, 0x01); 5598c2ecf20Sopenharmony_ci i2c_write_reg(i2c, addr, 0x0b, 0x01); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci usleep_range(2000, 3000); 5628c2ecf20Sopenharmony_ci /* Start XO2 PLL */ 5638c2ecf20Sopenharmony_ci i2c_write_reg(i2c, addr, 0x08, 0x87); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci u8 probe[1] = { 0x00 }, data[4]; 5718c2ecf20Sopenharmony_ci u8 addr = 0x10; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci *type = NGENE_XO2_TYPE_NONE; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (i2c_io(i2c, addr, probe, 1, data, 4)) 5768c2ecf20Sopenharmony_ci return 0; 5778c2ecf20Sopenharmony_ci if (data[0] == 'D' && data[1] == 'F') { 5788c2ecf20Sopenharmony_ci *id = data[2]; 5798c2ecf20Sopenharmony_ci *type = NGENE_XO2_TYPE_DUOFLEX; 5808c2ecf20Sopenharmony_ci return 1; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci if (data[0] == 'C' && data[1] == 'I') { 5838c2ecf20Sopenharmony_ci *id = data[2]; 5848c2ecf20Sopenharmony_ci *type = NGENE_XO2_TYPE_CI; 5858c2ecf20Sopenharmony_ci return 1; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci/****************************************************************************/ 5918c2ecf20Sopenharmony_ci/* Probing and port/channel handling ****************************************/ 5928c2ecf20Sopenharmony_ci/****************************************************************************/ 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic int cineS2_probe(struct ngene_channel *chan) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 5978c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); 5988c2ecf20Sopenharmony_ci struct stv090x_config *fe_conf; 5998c2ecf20Sopenharmony_ci u8 buf[3]; 6008c2ecf20Sopenharmony_ci u8 xo2_type, xo2_id, xo2_demodtype; 6018c2ecf20Sopenharmony_ci u8 sony_osc24 = 0; 6028c2ecf20Sopenharmony_ci struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; 6038c2ecf20Sopenharmony_ci int rc; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (port_has_xo2(i2c, &xo2_type, &xo2_id)) { 6068c2ecf20Sopenharmony_ci xo2_id >>= 2; 6078c2ecf20Sopenharmony_ci dev_dbg(pdev, "XO2 on channel %d (type %d, id %d)\n", 6088c2ecf20Sopenharmony_ci chan->number, xo2_type, xo2_id); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci switch (xo2_type) { 6118c2ecf20Sopenharmony_ci case NGENE_XO2_TYPE_DUOFLEX: 6128c2ecf20Sopenharmony_ci if (chan->number & 1) 6138c2ecf20Sopenharmony_ci dev_dbg(pdev, 6148c2ecf20Sopenharmony_ci "skipping XO2 init on odd channel %d", 6158c2ecf20Sopenharmony_ci chan->number); 6168c2ecf20Sopenharmony_ci else 6178c2ecf20Sopenharmony_ci init_xo2(chan, i2c); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci xo2_demodtype = DEMOD_TYPE_XO2 + xo2_id; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci switch (xo2_demodtype) { 6228c2ecf20Sopenharmony_ci case DEMOD_TYPE_SONY_CT2: 6238c2ecf20Sopenharmony_ci case DEMOD_TYPE_SONY_ISDBT: 6248c2ecf20Sopenharmony_ci case DEMOD_TYPE_SONY_C2T2: 6258c2ecf20Sopenharmony_ci case DEMOD_TYPE_SONY_C2T2I: 6268c2ecf20Sopenharmony_ci dev_info(pdev, "%s (XO2) on channel %d\n", 6278c2ecf20Sopenharmony_ci xo2names[xo2_id], chan->number); 6288c2ecf20Sopenharmony_ci chan->demod_type = xo2_demodtype; 6298c2ecf20Sopenharmony_ci if (xo2_demodtype == DEMOD_TYPE_SONY_C2T2I) 6308c2ecf20Sopenharmony_ci sony_osc24 = 1; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci demod_attach_cxd28xx(chan, i2c, sony_osc24); 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci case DEMOD_TYPE_STV0910: 6358c2ecf20Sopenharmony_ci dev_info(pdev, "%s (XO2) on channel %d\n", 6368c2ecf20Sopenharmony_ci xo2names[xo2_id], chan->number); 6378c2ecf20Sopenharmony_ci chan->demod_type = xo2_demodtype; 6388c2ecf20Sopenharmony_ci demod_attach_stv0910(chan, i2c); 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci default: 6418c2ecf20Sopenharmony_ci dev_warn(pdev, 6428c2ecf20Sopenharmony_ci "Unsupported XO2 module on channel %d\n", 6438c2ecf20Sopenharmony_ci chan->number); 6448c2ecf20Sopenharmony_ci return -ENODEV; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci case NGENE_XO2_TYPE_CI: 6488c2ecf20Sopenharmony_ci dev_info(pdev, "DuoFlex CI modules not supported\n"); 6498c2ecf20Sopenharmony_ci return -ENODEV; 6508c2ecf20Sopenharmony_ci default: 6518c2ecf20Sopenharmony_ci dev_info(pdev, "Unsupported XO2 module type\n"); 6528c2ecf20Sopenharmony_ci return -ENODEV; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci } else if (port_has_stv0900(i2c, chan->number)) { 6558c2ecf20Sopenharmony_ci chan->demod_type = DEMOD_TYPE_STV090X; 6568c2ecf20Sopenharmony_ci fe_conf = chan->dev->card_info->fe_config[chan->number]; 6578c2ecf20Sopenharmony_ci /* demod found, attach it */ 6588c2ecf20Sopenharmony_ci rc = demod_attach_stv0900(chan); 6598c2ecf20Sopenharmony_ci if (rc < 0 || chan->number < 2) 6608c2ecf20Sopenharmony_ci return rc; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* demod #2: reprogram outputs DPN1 & DPN2 */ 6638c2ecf20Sopenharmony_ci i2c_msg.addr = fe_conf->address; 6648c2ecf20Sopenharmony_ci i2c_msg.len = 3; 6658c2ecf20Sopenharmony_ci buf[0] = 0xf1; 6668c2ecf20Sopenharmony_ci switch (chan->number) { 6678c2ecf20Sopenharmony_ci case 2: 6688c2ecf20Sopenharmony_ci buf[1] = 0x5c; 6698c2ecf20Sopenharmony_ci buf[2] = 0xc2; 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci case 3: 6728c2ecf20Sopenharmony_ci buf[1] = 0x61; 6738c2ecf20Sopenharmony_ci buf[2] = 0xcc; 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci default: 6768c2ecf20Sopenharmony_ci return -ENODEV; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci rc = i2c_transfer(i2c, &i2c_msg, 1); 6798c2ecf20Sopenharmony_ci if (rc != 1) { 6808c2ecf20Sopenharmony_ci dev_err(pdev, "Could not setup DPNx\n"); 6818c2ecf20Sopenharmony_ci return -EIO; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } else if (port_has_drxk(i2c, chan->number^2)) { 6848c2ecf20Sopenharmony_ci chan->demod_type = DEMOD_TYPE_DRXK; 6858c2ecf20Sopenharmony_ci demod_attach_drxk(chan, i2c); 6868c2ecf20Sopenharmony_ci } else if (port_has_stv0367(i2c)) { 6878c2ecf20Sopenharmony_ci chan->demod_type = DEMOD_TYPE_STV0367; 6888c2ecf20Sopenharmony_ci dev_info(pdev, "STV0367 on channel %d\n", chan->number); 6898c2ecf20Sopenharmony_ci demod_attach_stv0367(chan, i2c); 6908c2ecf20Sopenharmony_ci } else { 6918c2ecf20Sopenharmony_ci dev_info(pdev, "No demod found on chan %d\n", chan->number); 6928c2ecf20Sopenharmony_ci return -ENODEV; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci return 0; 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic struct lgdt330x_config aver_m780 = { 6998c2ecf20Sopenharmony_ci .demod_chip = LGDT3303, 7008c2ecf20Sopenharmony_ci .serial_mpeg = 0x00, /* PARALLEL */ 7018c2ecf20Sopenharmony_ci .clock_polarity_flip = 1, 7028c2ecf20Sopenharmony_ci}; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic struct mt2131_config m780_tunerconfig = { 7058c2ecf20Sopenharmony_ci 0xc0 >> 1 7068c2ecf20Sopenharmony_ci}; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci/* A single func to attach the demo and tuner, rather than 7098c2ecf20Sopenharmony_ci * use two sep funcs like the current design mandates. 7108c2ecf20Sopenharmony_ci */ 7118c2ecf20Sopenharmony_cistatic int demod_attach_lg330x(struct ngene_channel *chan) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, 7168c2ecf20Sopenharmony_ci 0xb2 >> 1, &chan->i2c_adapter); 7178c2ecf20Sopenharmony_ci if (chan->fe == NULL) { 7188c2ecf20Sopenharmony_ci dev_err(pdev, "No LGDT330x found!\n"); 7198c2ecf20Sopenharmony_ci return -ENODEV; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci dvb_attach(mt2131_attach, chan->fe, &chan->i2c_adapter, 7238c2ecf20Sopenharmony_ci &m780_tunerconfig, 0); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return (chan->fe) ? 0 : -ENODEV; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic int demod_attach_drxd(struct ngene_channel *chan) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 7318c2ecf20Sopenharmony_ci struct drxd_config *feconf; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci feconf = chan->dev->card_info->fe_config[chan->number]; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci chan->fe = dvb_attach(drxd_attach, feconf, chan, 7368c2ecf20Sopenharmony_ci &chan->i2c_adapter, &chan->dev->pci_dev->dev); 7378c2ecf20Sopenharmony_ci if (!chan->fe) { 7388c2ecf20Sopenharmony_ci dev_err(pdev, "No DRXD found!\n"); 7398c2ecf20Sopenharmony_ci return -ENODEV; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci return 0; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic int tuner_attach_dtt7520x(struct ngene_channel *chan) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 7478c2ecf20Sopenharmony_ci struct drxd_config *feconf; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci feconf = chan->dev->card_info->fe_config[chan->number]; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address, 7528c2ecf20Sopenharmony_ci &chan->i2c_adapter, 7538c2ecf20Sopenharmony_ci feconf->pll_type)) { 7548c2ecf20Sopenharmony_ci dev_err(pdev, "No pll(%d) found!\n", feconf->pll_type); 7558c2ecf20Sopenharmony_ci return -ENODEV; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci return 0; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci/****************************************************************************/ 7618c2ecf20Sopenharmony_ci/* EEPROM TAGS **************************************************************/ 7628c2ecf20Sopenharmony_ci/****************************************************************************/ 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci#define MICNG_EE_START 0x0100 7658c2ecf20Sopenharmony_ci#define MICNG_EE_END 0x0FF0 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci#define MICNG_EETAG_END0 0x0000 7688c2ecf20Sopenharmony_ci#define MICNG_EETAG_END1 0xFFFF 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci/* 0x0001 - 0x000F reserved for housekeeping */ 7718c2ecf20Sopenharmony_ci/* 0xFFFF - 0xFFFE reserved for housekeeping */ 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci/* Micronas assigned tags 7748c2ecf20Sopenharmony_ci EEProm tags for hardware support */ 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci#define MICNG_EETAG_DRXD1_OSCDEVIATION 0x1000 /* 2 Bytes data */ 7778c2ecf20Sopenharmony_ci#define MICNG_EETAG_DRXD2_OSCDEVIATION 0x1001 /* 2 Bytes data */ 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci#define MICNG_EETAG_MT2060_1_1STIF 0x1100 /* 2 Bytes data */ 7808c2ecf20Sopenharmony_ci#define MICNG_EETAG_MT2060_2_1STIF 0x1101 /* 2 Bytes data */ 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci/* Tag range for OEMs */ 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci#define MICNG_EETAG_OEM_FIRST 0xC000 7858c2ecf20Sopenharmony_ci#define MICNG_EETAG_OEM_LAST 0xFFEF 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistatic int i2c_write_eeprom(struct i2c_adapter *adapter, 7888c2ecf20Sopenharmony_ci u8 adr, u16 reg, u8 data) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci struct device *pdev = adapter->dev.parent; 7918c2ecf20Sopenharmony_ci u8 m[3] = {(reg >> 8), (reg & 0xff), data}; 7928c2ecf20Sopenharmony_ci struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, 7938c2ecf20Sopenharmony_ci .len = sizeof(m)}; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (i2c_transfer(adapter, &msg, 1) != 1) { 7968c2ecf20Sopenharmony_ci dev_err(pdev, "Error writing EEPROM!\n"); 7978c2ecf20Sopenharmony_ci return -EIO; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int i2c_read_eeprom(struct i2c_adapter *adapter, 8038c2ecf20Sopenharmony_ci u8 adr, u16 reg, u8 *data, int len) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci struct device *pdev = adapter->dev.parent; 8068c2ecf20Sopenharmony_ci u8 msg[2] = {(reg >> 8), (reg & 0xff)}; 8078c2ecf20Sopenharmony_ci struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, 8088c2ecf20Sopenharmony_ci .buf = msg, .len = 2 }, 8098c2ecf20Sopenharmony_ci {.addr = adr, .flags = I2C_M_RD, 8108c2ecf20Sopenharmony_ci .buf = data, .len = len} }; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (i2c_transfer(adapter, msgs, 2) != 2) { 8138c2ecf20Sopenharmony_ci dev_err(pdev, "Error reading EEPROM\n"); 8148c2ecf20Sopenharmony_ci return -EIO; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci return 0; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic int ReadEEProm(struct i2c_adapter *adapter, 8208c2ecf20Sopenharmony_ci u16 Tag, u32 MaxLen, u8 *data, u32 *pLength) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci struct device *pdev = adapter->dev.parent; 8238c2ecf20Sopenharmony_ci int status = 0; 8248c2ecf20Sopenharmony_ci u16 Addr = MICNG_EE_START, Length, tag = 0; 8258c2ecf20Sopenharmony_ci u8 EETag[3]; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci while (Addr + sizeof(u16) + 1 < MICNG_EE_END) { 8288c2ecf20Sopenharmony_ci if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag))) 8298c2ecf20Sopenharmony_ci return -1; 8308c2ecf20Sopenharmony_ci tag = (EETag[0] << 8) | EETag[1]; 8318c2ecf20Sopenharmony_ci if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1) 8328c2ecf20Sopenharmony_ci return -1; 8338c2ecf20Sopenharmony_ci if (tag == Tag) 8348c2ecf20Sopenharmony_ci break; 8358c2ecf20Sopenharmony_ci Addr += sizeof(u16) + 1 + EETag[2]; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { 8388c2ecf20Sopenharmony_ci dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n", 8398c2ecf20Sopenharmony_ci tag, EETag[2]); 8408c2ecf20Sopenharmony_ci return -1; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci Length = EETag[2]; 8438c2ecf20Sopenharmony_ci if (Length > MaxLen) 8448c2ecf20Sopenharmony_ci Length = (u16) MaxLen; 8458c2ecf20Sopenharmony_ci if (Length > 0) { 8468c2ecf20Sopenharmony_ci Addr += sizeof(u16) + 1; 8478c2ecf20Sopenharmony_ci status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length); 8488c2ecf20Sopenharmony_ci if (!status) { 8498c2ecf20Sopenharmony_ci *pLength = EETag[2]; 8508c2ecf20Sopenharmony_ci#if 0 8518c2ecf20Sopenharmony_ci if (Length < EETag[2]) 8528c2ecf20Sopenharmony_ci status = STATUS_BUFFER_OVERFLOW; 8538c2ecf20Sopenharmony_ci#endif 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci return status; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic int WriteEEProm(struct i2c_adapter *adapter, 8608c2ecf20Sopenharmony_ci u16 Tag, u32 Length, u8 *data) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct device *pdev = adapter->dev.parent; 8638c2ecf20Sopenharmony_ci int status = 0; 8648c2ecf20Sopenharmony_ci u16 Addr = MICNG_EE_START; 8658c2ecf20Sopenharmony_ci u8 EETag[3]; 8668c2ecf20Sopenharmony_ci u16 tag = 0; 8678c2ecf20Sopenharmony_ci int retry, i; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci while (Addr + sizeof(u16) + 1 < MICNG_EE_END) { 8708c2ecf20Sopenharmony_ci if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag))) 8718c2ecf20Sopenharmony_ci return -1; 8728c2ecf20Sopenharmony_ci tag = (EETag[0] << 8) | EETag[1]; 8738c2ecf20Sopenharmony_ci if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1) 8748c2ecf20Sopenharmony_ci return -1; 8758c2ecf20Sopenharmony_ci if (tag == Tag) 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci Addr += sizeof(u16) + 1 + EETag[2]; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) { 8808c2ecf20Sopenharmony_ci dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n", 8818c2ecf20Sopenharmony_ci tag, EETag[2]); 8828c2ecf20Sopenharmony_ci return -1; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (Length > EETag[2]) 8868c2ecf20Sopenharmony_ci return -EINVAL; 8878c2ecf20Sopenharmony_ci /* Note: We write the data one byte at a time to avoid 8888c2ecf20Sopenharmony_ci issues with page sizes. (which are different for 8898c2ecf20Sopenharmony_ci each manufacture and eeprom size) 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_ci Addr += sizeof(u16) + 1; 8928c2ecf20Sopenharmony_ci for (i = 0; i < Length; i++, Addr++) { 8938c2ecf20Sopenharmony_ci status = i2c_write_eeprom(adapter, 0x50, Addr, data[i]); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci if (status) 8968c2ecf20Sopenharmony_ci break; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* Poll for finishing write cycle */ 8998c2ecf20Sopenharmony_ci retry = 10; 9008c2ecf20Sopenharmony_ci while (retry) { 9018c2ecf20Sopenharmony_ci u8 Tmp; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci msleep(50); 9048c2ecf20Sopenharmony_ci status = i2c_read_eeprom(adapter, 0x50, Addr, &Tmp, 1); 9058c2ecf20Sopenharmony_ci if (status) 9068c2ecf20Sopenharmony_ci break; 9078c2ecf20Sopenharmony_ci if (Tmp != data[i]) 9088c2ecf20Sopenharmony_ci dev_err(pdev, "eeprom write error\n"); 9098c2ecf20Sopenharmony_ci retry -= 1; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci if (status) { 9128c2ecf20Sopenharmony_ci dev_err(pdev, "Timeout polling eeprom\n"); 9138c2ecf20Sopenharmony_ci break; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci return status; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci int stat; 9228c2ecf20Sopenharmony_ci u8 buf[2]; 9238c2ecf20Sopenharmony_ci u32 len = 0; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci stat = ReadEEProm(adapter, tag, 2, buf, &len); 9268c2ecf20Sopenharmony_ci if (stat) 9278c2ecf20Sopenharmony_ci return stat; 9288c2ecf20Sopenharmony_ci if (len != 2) 9298c2ecf20Sopenharmony_ci return -EINVAL; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci *data = (buf[0] << 8) | buf[1]; 9328c2ecf20Sopenharmony_ci return 0; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci int stat; 9388c2ecf20Sopenharmony_ci u8 buf[2]; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci buf[0] = data >> 8; 9418c2ecf20Sopenharmony_ci buf[1] = data & 0xff; 9428c2ecf20Sopenharmony_ci stat = WriteEEProm(adapter, tag, 2, buf); 9438c2ecf20Sopenharmony_ci if (stat) 9448c2ecf20Sopenharmony_ci return stat; 9458c2ecf20Sopenharmony_ci return 0; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic s16 osc_deviation(void *priv, s16 deviation, int flag) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct ngene_channel *chan = priv; 9518c2ecf20Sopenharmony_ci struct device *pdev = &chan->dev->pci_dev->dev; 9528c2ecf20Sopenharmony_ci struct i2c_adapter *adap = &chan->i2c_adapter; 9538c2ecf20Sopenharmony_ci u16 data = 0; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (flag) { 9568c2ecf20Sopenharmony_ci data = (u16) deviation; 9578c2ecf20Sopenharmony_ci dev_info(pdev, "write deviation %d\n", 9588c2ecf20Sopenharmony_ci deviation); 9598c2ecf20Sopenharmony_ci eeprom_write_ushort(adap, 0x1000 + chan->number, data); 9608c2ecf20Sopenharmony_ci } else { 9618c2ecf20Sopenharmony_ci if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data)) 9628c2ecf20Sopenharmony_ci data = 0; 9638c2ecf20Sopenharmony_ci dev_info(pdev, "read deviation %d\n", 9648c2ecf20Sopenharmony_ci (s16)data); 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci return (s16) data; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci/****************************************************************************/ 9718c2ecf20Sopenharmony_ci/* Switch control (I2C gates, etc.) *****************************************/ 9728c2ecf20Sopenharmony_ci/****************************************************************************/ 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic struct stv090x_config fe_cineS2 = { 9768c2ecf20Sopenharmony_ci .device = STV0900, 9778c2ecf20Sopenharmony_ci .demod_mode = STV090x_DUAL, 9788c2ecf20Sopenharmony_ci .clk_mode = STV090x_CLK_EXT, 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci .xtal = 27000000, 9818c2ecf20Sopenharmony_ci .address = 0x68, 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, 9848c2ecf20Sopenharmony_ci .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci .repeater_level = STV090x_RPTLEVEL_16, 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci .adc1_range = STV090x_ADC_1Vpp, 9898c2ecf20Sopenharmony_ci .adc2_range = STV090x_ADC_1Vpp, 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci .diseqc_envelope_mode = true, 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci .tuner_i2c_lock = cineS2_tuner_i2c_lock, 9948c2ecf20Sopenharmony_ci}; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic struct stv090x_config fe_cineS2_2 = { 9978c2ecf20Sopenharmony_ci .device = STV0900, 9988c2ecf20Sopenharmony_ci .demod_mode = STV090x_DUAL, 9998c2ecf20Sopenharmony_ci .clk_mode = STV090x_CLK_EXT, 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci .xtal = 27000000, 10028c2ecf20Sopenharmony_ci .address = 0x69, 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, 10058c2ecf20Sopenharmony_ci .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci .repeater_level = STV090x_RPTLEVEL_16, 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci .adc1_range = STV090x_ADC_1Vpp, 10108c2ecf20Sopenharmony_ci .adc2_range = STV090x_ADC_1Vpp, 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci .diseqc_envelope_mode = true, 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci .tuner_i2c_lock = cineS2_tuner_i2c_lock, 10158c2ecf20Sopenharmony_ci}; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cistatic struct stv6110x_config tuner_cineS2_0 = { 10188c2ecf20Sopenharmony_ci .addr = 0x60, 10198c2ecf20Sopenharmony_ci .refclk = 27000000, 10208c2ecf20Sopenharmony_ci .clk_div = 1, 10218c2ecf20Sopenharmony_ci}; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic struct stv6110x_config tuner_cineS2_1 = { 10248c2ecf20Sopenharmony_ci .addr = 0x63, 10258c2ecf20Sopenharmony_ci .refclk = 27000000, 10268c2ecf20Sopenharmony_ci .clk_div = 1, 10278c2ecf20Sopenharmony_ci}; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic const struct ngene_info ngene_info_cineS2 = { 10308c2ecf20Sopenharmony_ci .type = NGENE_SIDEWINDER, 10318c2ecf20Sopenharmony_ci .name = "Linux4Media cineS2 DVB-S2 Twin Tuner", 10328c2ecf20Sopenharmony_ci .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, 10338c2ecf20Sopenharmony_ci .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, 10348c2ecf20Sopenharmony_ci .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, 10358c2ecf20Sopenharmony_ci .fe_config = {&fe_cineS2, &fe_cineS2}, 10368c2ecf20Sopenharmony_ci .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, 10378c2ecf20Sopenharmony_ci .lnb = {0x0b, 0x08}, 10388c2ecf20Sopenharmony_ci .tsf = {3, 3}, 10398c2ecf20Sopenharmony_ci .fw_version = 18, 10408c2ecf20Sopenharmony_ci .msi_supported = true, 10418c2ecf20Sopenharmony_ci}; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic const struct ngene_info ngene_info_satixS2 = { 10448c2ecf20Sopenharmony_ci .type = NGENE_SIDEWINDER, 10458c2ecf20Sopenharmony_ci .name = "Mystique SaTiX-S2 Dual", 10468c2ecf20Sopenharmony_ci .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, 10478c2ecf20Sopenharmony_ci .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, 10488c2ecf20Sopenharmony_ci .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, 10498c2ecf20Sopenharmony_ci .fe_config = {&fe_cineS2, &fe_cineS2}, 10508c2ecf20Sopenharmony_ci .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, 10518c2ecf20Sopenharmony_ci .lnb = {0x0b, 0x08}, 10528c2ecf20Sopenharmony_ci .tsf = {3, 3}, 10538c2ecf20Sopenharmony_ci .fw_version = 18, 10548c2ecf20Sopenharmony_ci .msi_supported = true, 10558c2ecf20Sopenharmony_ci}; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic const struct ngene_info ngene_info_satixS2v2 = { 10588c2ecf20Sopenharmony_ci .type = NGENE_SIDEWINDER, 10598c2ecf20Sopenharmony_ci .name = "Mystique SaTiX-S2 Dual (v2)", 10608c2ecf20Sopenharmony_ci .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, 10618c2ecf20Sopenharmony_ci NGENE_IO_TSOUT}, 10628c2ecf20Sopenharmony_ci .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, 10638c2ecf20Sopenharmony_ci .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, 10648c2ecf20Sopenharmony_ci .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, 10658c2ecf20Sopenharmony_ci .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, 10668c2ecf20Sopenharmony_ci .lnb = {0x0a, 0x08, 0x0b, 0x09}, 10678c2ecf20Sopenharmony_ci .tsf = {3, 3}, 10688c2ecf20Sopenharmony_ci .fw_version = 18, 10698c2ecf20Sopenharmony_ci .msi_supported = true, 10708c2ecf20Sopenharmony_ci}; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic const struct ngene_info ngene_info_cineS2v5 = { 10738c2ecf20Sopenharmony_ci .type = NGENE_SIDEWINDER, 10748c2ecf20Sopenharmony_ci .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", 10758c2ecf20Sopenharmony_ci .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, 10768c2ecf20Sopenharmony_ci NGENE_IO_TSOUT}, 10778c2ecf20Sopenharmony_ci .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, 10788c2ecf20Sopenharmony_ci .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe}, 10798c2ecf20Sopenharmony_ci .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, 10808c2ecf20Sopenharmony_ci .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, 10818c2ecf20Sopenharmony_ci .lnb = {0x0a, 0x08, 0x0b, 0x09}, 10828c2ecf20Sopenharmony_ci .tsf = {3, 3}, 10838c2ecf20Sopenharmony_ci .fw_version = 18, 10848c2ecf20Sopenharmony_ci .msi_supported = true, 10858c2ecf20Sopenharmony_ci}; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic const struct ngene_info ngene_info_duoFlex = { 10898c2ecf20Sopenharmony_ci .type = NGENE_SIDEWINDER, 10908c2ecf20Sopenharmony_ci .name = "Digital Devices DuoFlex PCIe or miniPCIe", 10918c2ecf20Sopenharmony_ci .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, 10928c2ecf20Sopenharmony_ci NGENE_IO_TSOUT}, 10938c2ecf20Sopenharmony_ci .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, 10948c2ecf20Sopenharmony_ci .tuner_attach = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe}, 10958c2ecf20Sopenharmony_ci .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, 10968c2ecf20Sopenharmony_ci .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, 10978c2ecf20Sopenharmony_ci .lnb = {0x0a, 0x08, 0x0b, 0x09}, 10988c2ecf20Sopenharmony_ci .tsf = {3, 3}, 10998c2ecf20Sopenharmony_ci .fw_version = 18, 11008c2ecf20Sopenharmony_ci .msi_supported = true, 11018c2ecf20Sopenharmony_ci}; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic const struct ngene_info ngene_info_m780 = { 11048c2ecf20Sopenharmony_ci .type = NGENE_APP, 11058c2ecf20Sopenharmony_ci .name = "Aver M780 ATSC/QAM-B", 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* Channel 0 is analog, which is currently unsupported */ 11088c2ecf20Sopenharmony_ci .io_type = { NGENE_IO_NONE, NGENE_IO_TSIN }, 11098c2ecf20Sopenharmony_ci .demod_attach = { NULL, demod_attach_lg330x }, 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* Ensure these are NULL else the frame will call them (as funcs) */ 11128c2ecf20Sopenharmony_ci .tuner_attach = { NULL, NULL, NULL, NULL }, 11138c2ecf20Sopenharmony_ci .fe_config = { NULL, &aver_m780 }, 11148c2ecf20Sopenharmony_ci .avf = { 0 }, 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* A custom electrical interface config for the demod to bridge */ 11178c2ecf20Sopenharmony_ci .tsf = { 4, 4 }, 11188c2ecf20Sopenharmony_ci .fw_version = 15, 11198c2ecf20Sopenharmony_ci}; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic struct drxd_config fe_terratec_dvbt_0 = { 11228c2ecf20Sopenharmony_ci .index = 0, 11238c2ecf20Sopenharmony_ci .demod_address = 0x70, 11248c2ecf20Sopenharmony_ci .demod_revision = 0xa2, 11258c2ecf20Sopenharmony_ci .demoda_address = 0x00, 11268c2ecf20Sopenharmony_ci .pll_address = 0x60, 11278c2ecf20Sopenharmony_ci .pll_type = DVB_PLL_THOMSON_DTT7520X, 11288c2ecf20Sopenharmony_ci .clock = 20000, 11298c2ecf20Sopenharmony_ci .osc_deviation = osc_deviation, 11308c2ecf20Sopenharmony_ci}; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic struct drxd_config fe_terratec_dvbt_1 = { 11338c2ecf20Sopenharmony_ci .index = 1, 11348c2ecf20Sopenharmony_ci .demod_address = 0x71, 11358c2ecf20Sopenharmony_ci .demod_revision = 0xa2, 11368c2ecf20Sopenharmony_ci .demoda_address = 0x00, 11378c2ecf20Sopenharmony_ci .pll_address = 0x60, 11388c2ecf20Sopenharmony_ci .pll_type = DVB_PLL_THOMSON_DTT7520X, 11398c2ecf20Sopenharmony_ci .clock = 20000, 11408c2ecf20Sopenharmony_ci .osc_deviation = osc_deviation, 11418c2ecf20Sopenharmony_ci}; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic const struct ngene_info ngene_info_terratec = { 11448c2ecf20Sopenharmony_ci .type = NGENE_TERRATEC, 11458c2ecf20Sopenharmony_ci .name = "Terratec Integra/Cinergy2400i Dual DVB-T", 11468c2ecf20Sopenharmony_ci .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, 11478c2ecf20Sopenharmony_ci .demod_attach = {demod_attach_drxd, demod_attach_drxd}, 11488c2ecf20Sopenharmony_ci .tuner_attach = {tuner_attach_dtt7520x, tuner_attach_dtt7520x}, 11498c2ecf20Sopenharmony_ci .fe_config = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1}, 11508c2ecf20Sopenharmony_ci .i2c_access = 1, 11518c2ecf20Sopenharmony_ci}; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci/****************************************************************************/ 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci/****************************************************************************/ 11588c2ecf20Sopenharmony_ci/* PCI Subsystem ID *********************************************************/ 11598c2ecf20Sopenharmony_ci/****************************************************************************/ 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci#define NGENE_ID(_subvend, _subdev, _driverdata) { \ 11628c2ecf20Sopenharmony_ci .vendor = NGENE_VID, .device = NGENE_PID, \ 11638c2ecf20Sopenharmony_ci .subvendor = _subvend, .subdevice = _subdev, \ 11648c2ecf20Sopenharmony_ci .driver_data = (unsigned long) &_driverdata } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci/****************************************************************************/ 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_cistatic const struct pci_device_id ngene_id_tbl[] = { 11698c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xab04, ngene_info_cineS2), 11708c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xab05, ngene_info_cineS2v5), 11718c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), 11728c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), 11738c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), 11748c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2), 11758c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5), 11768c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex), 11778c2ecf20Sopenharmony_ci NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex), 11788c2ecf20Sopenharmony_ci NGENE_ID(0x1461, 0x062e, ngene_info_m780), 11798c2ecf20Sopenharmony_ci NGENE_ID(0x153b, 0x1167, ngene_info_terratec), 11808c2ecf20Sopenharmony_ci {0} 11818c2ecf20Sopenharmony_ci}; 11828c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ngene_id_tbl); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci/****************************************************************************/ 11858c2ecf20Sopenharmony_ci/* Init/Exit ****************************************************************/ 11868c2ecf20Sopenharmony_ci/****************************************************************************/ 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic pci_ers_result_t ngene_error_detected(struct pci_dev *dev, 11898c2ecf20Sopenharmony_ci pci_channel_state_t state) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci dev_err(&dev->dev, "PCI error\n"); 11928c2ecf20Sopenharmony_ci if (state == pci_channel_io_perm_failure) 11938c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 11948c2ecf20Sopenharmony_ci if (state == pci_channel_io_frozen) 11958c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 11968c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_CAN_RECOVER; 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic pci_ers_result_t ngene_slot_reset(struct pci_dev *dev) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci dev_info(&dev->dev, "slot reset\n"); 12028c2ecf20Sopenharmony_ci return 0; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cistatic void ngene_resume(struct pci_dev *dev) 12068c2ecf20Sopenharmony_ci{ 12078c2ecf20Sopenharmony_ci dev_info(&dev->dev, "resume\n"); 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_cistatic const struct pci_error_handlers ngene_errors = { 12118c2ecf20Sopenharmony_ci .error_detected = ngene_error_detected, 12128c2ecf20Sopenharmony_ci .slot_reset = ngene_slot_reset, 12138c2ecf20Sopenharmony_ci .resume = ngene_resume, 12148c2ecf20Sopenharmony_ci}; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic struct pci_driver ngene_pci_driver = { 12178c2ecf20Sopenharmony_ci .name = "ngene", 12188c2ecf20Sopenharmony_ci .id_table = ngene_id_tbl, 12198c2ecf20Sopenharmony_ci .probe = ngene_probe, 12208c2ecf20Sopenharmony_ci .remove = ngene_remove, 12218c2ecf20Sopenharmony_ci .err_handler = &ngene_errors, 12228c2ecf20Sopenharmony_ci .shutdown = ngene_shutdown, 12238c2ecf20Sopenharmony_ci}; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic __init int module_init_ngene(void) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci /* pr_*() since we don't have a device to use with dev_*() yet */ 12288c2ecf20Sopenharmony_ci pr_info("nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n"); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci return pci_register_driver(&ngene_pci_driver); 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic __exit void module_exit_ngene(void) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci pci_unregister_driver(&ngene_pci_driver); 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cimodule_init(module_init_ngene); 12398c2ecf20Sopenharmony_cimodule_exit(module_exit_ngene); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("nGene"); 12428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel"); 12438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1244