162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for the NXP SAA7164 PCIe bridge 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "saa7164.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "tda10048.h" 1162306a36Sopenharmony_ci#include "tda18271.h" 1262306a36Sopenharmony_ci#include "s5h1411.h" 1362306a36Sopenharmony_ci#include "si2157.h" 1462306a36Sopenharmony_ci#include "si2168.h" 1562306a36Sopenharmony_ci#include "lgdt3306a.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define DRIVER_NAME "saa7164" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* addr is in the card struct, get it from there */ 2262306a36Sopenharmony_cistatic struct tda10048_config hauppauge_hvr2200_1_config = { 2362306a36Sopenharmony_ci .demod_address = 0x10 >> 1, 2462306a36Sopenharmony_ci .output_mode = TDA10048_SERIAL_OUTPUT, 2562306a36Sopenharmony_ci .fwbulkwritelen = TDA10048_BULKWRITE_200, 2662306a36Sopenharmony_ci .inversion = TDA10048_INVERSION_ON, 2762306a36Sopenharmony_ci .dtv6_if_freq_khz = TDA10048_IF_3300, 2862306a36Sopenharmony_ci .dtv7_if_freq_khz = TDA10048_IF_3500, 2962306a36Sopenharmony_ci .dtv8_if_freq_khz = TDA10048_IF_4000, 3062306a36Sopenharmony_ci .clk_freq_khz = TDA10048_CLK_16000, 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_cistatic struct tda10048_config hauppauge_hvr2200_2_config = { 3362306a36Sopenharmony_ci .demod_address = 0x12 >> 1, 3462306a36Sopenharmony_ci .output_mode = TDA10048_SERIAL_OUTPUT, 3562306a36Sopenharmony_ci .fwbulkwritelen = TDA10048_BULKWRITE_200, 3662306a36Sopenharmony_ci .inversion = TDA10048_INVERSION_ON, 3762306a36Sopenharmony_ci .dtv6_if_freq_khz = TDA10048_IF_3300, 3862306a36Sopenharmony_ci .dtv7_if_freq_khz = TDA10048_IF_3500, 3962306a36Sopenharmony_ci .dtv8_if_freq_khz = TDA10048_IF_4000, 4062306a36Sopenharmony_ci .clk_freq_khz = TDA10048_CLK_16000, 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic struct tda18271_std_map hauppauge_tda18271_std_map = { 4462306a36Sopenharmony_ci .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3, 4562306a36Sopenharmony_ci .if_lvl = 6, .rfagc_top = 0x37 }, 4662306a36Sopenharmony_ci .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, 4762306a36Sopenharmony_ci .if_lvl = 6, .rfagc_top = 0x37 }, 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic struct tda18271_config hauppauge_hvr22x0_tuner_config = { 5162306a36Sopenharmony_ci .std_map = &hauppauge_tda18271_std_map, 5262306a36Sopenharmony_ci .gate = TDA18271_GATE_ANALOG, 5362306a36Sopenharmony_ci .role = TDA18271_MASTER, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic struct tda18271_config hauppauge_hvr22x0s_tuner_config = { 5762306a36Sopenharmony_ci .std_map = &hauppauge_tda18271_std_map, 5862306a36Sopenharmony_ci .gate = TDA18271_GATE_ANALOG, 5962306a36Sopenharmony_ci .role = TDA18271_SLAVE, 6062306a36Sopenharmony_ci .output_opt = TDA18271_OUTPUT_LT_OFF, 6162306a36Sopenharmony_ci .rf_cal_on_startup = 1 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic struct s5h1411_config hauppauge_s5h1411_config = { 6562306a36Sopenharmony_ci .output_mode = S5H1411_SERIAL_OUTPUT, 6662306a36Sopenharmony_ci .gpio = S5H1411_GPIO_ON, 6762306a36Sopenharmony_ci .qam_if = S5H1411_IF_4000, 6862306a36Sopenharmony_ci .vsb_if = S5H1411_IF_3250, 6962306a36Sopenharmony_ci .inversion = S5H1411_INVERSION_ON, 7062306a36Sopenharmony_ci .status_mode = S5H1411_DEMODLOCKING, 7162306a36Sopenharmony_ci .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct lgdt3306a_config hauppauge_hvr2255a_config = { 7562306a36Sopenharmony_ci .i2c_addr = 0xb2 >> 1, 7662306a36Sopenharmony_ci .qam_if_khz = 4000, 7762306a36Sopenharmony_ci .vsb_if_khz = 3250, 7862306a36Sopenharmony_ci .deny_i2c_rptr = 1, /* Disabled */ 7962306a36Sopenharmony_ci .spectral_inversion = 0, /* Disabled */ 8062306a36Sopenharmony_ci .mpeg_mode = LGDT3306A_MPEG_SERIAL, 8162306a36Sopenharmony_ci .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, 8262306a36Sopenharmony_ci .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, 8362306a36Sopenharmony_ci .xtalMHz = 25, /* 24 or 25 */ 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic struct lgdt3306a_config hauppauge_hvr2255b_config = { 8762306a36Sopenharmony_ci .i2c_addr = 0x1c >> 1, 8862306a36Sopenharmony_ci .qam_if_khz = 4000, 8962306a36Sopenharmony_ci .vsb_if_khz = 3250, 9062306a36Sopenharmony_ci .deny_i2c_rptr = 1, /* Disabled */ 9162306a36Sopenharmony_ci .spectral_inversion = 0, /* Disabled */ 9262306a36Sopenharmony_ci .mpeg_mode = LGDT3306A_MPEG_SERIAL, 9362306a36Sopenharmony_ci .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, 9462306a36Sopenharmony_ci .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, 9562306a36Sopenharmony_ci .xtalMHz = 25, /* 24 or 25 */ 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic struct si2157_config hauppauge_hvr2255_tuner_config = { 9962306a36Sopenharmony_ci .inversion = 1, 10062306a36Sopenharmony_ci .if_port = 1, 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int si2157_attach(struct saa7164_port *port, struct i2c_adapter *adapter, 10462306a36Sopenharmony_ci struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct i2c_board_info bi; 10762306a36Sopenharmony_ci struct i2c_client *tuner; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci cfg->fe = fe; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci memset(&bi, 0, sizeof(bi)); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci strscpy(bi.type, "si2157", I2C_NAME_SIZE); 11462306a36Sopenharmony_ci bi.platform_data = cfg; 11562306a36Sopenharmony_ci bi.addr = addr8bit >> 1; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci request_module(bi.type); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci tuner = i2c_new_client_device(adapter, &bi); 12062306a36Sopenharmony_ci if (!i2c_client_has_driver(tuner)) 12162306a36Sopenharmony_ci return -ENODEV; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (!try_module_get(tuner->dev.driver->owner)) { 12462306a36Sopenharmony_ci i2c_unregister_device(tuner); 12562306a36Sopenharmony_ci return -ENODEV; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci port->i2c_client_tuner = tuner; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int saa7164_dvb_stop_port(struct saa7164_port *port) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 13662306a36Sopenharmony_ci int ret; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 13962306a36Sopenharmony_ci if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 14062306a36Sopenharmony_ci printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", 14162306a36Sopenharmony_ci __func__, ret); 14262306a36Sopenharmony_ci ret = -EIO; 14362306a36Sopenharmony_ci } else { 14462306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Stopped\n", __func__); 14562306a36Sopenharmony_ci ret = 0; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return ret; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int saa7164_dvb_acquire_port(struct saa7164_port *port) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 15462306a36Sopenharmony_ci int ret; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); 15762306a36Sopenharmony_ci if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 15862306a36Sopenharmony_ci printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", 15962306a36Sopenharmony_ci __func__, ret); 16062306a36Sopenharmony_ci ret = -EIO; 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__); 16362306a36Sopenharmony_ci ret = 0; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return ret; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int saa7164_dvb_pause_port(struct saa7164_port *port) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 17262306a36Sopenharmony_ci int ret; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); 17562306a36Sopenharmony_ci if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 17662306a36Sopenharmony_ci printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", 17762306a36Sopenharmony_ci __func__, ret); 17862306a36Sopenharmony_ci ret = -EIO; 17962306a36Sopenharmony_ci } else { 18062306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Paused\n", __func__); 18162306a36Sopenharmony_ci ret = 0; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return ret; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* Firmware is very windows centric, meaning you have to transition 18862306a36Sopenharmony_ci * the part through AVStream / KS Windows stages, forwards or backwards. 18962306a36Sopenharmony_ci * States are: stopped, acquired (h/w), paused, started. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cistatic int saa7164_dvb_stop_streaming(struct saa7164_port *port) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 19462306a36Sopenharmony_ci struct saa7164_buffer *buf; 19562306a36Sopenharmony_ci struct list_head *p, *q; 19662306a36Sopenharmony_ci int ret; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ret = saa7164_dvb_pause_port(port); 20162306a36Sopenharmony_ci ret = saa7164_dvb_acquire_port(port); 20262306a36Sopenharmony_ci ret = saa7164_dvb_stop_port(port); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Mark the hardware buffers as free */ 20562306a36Sopenharmony_ci mutex_lock(&port->dmaqueue_lock); 20662306a36Sopenharmony_ci list_for_each_safe(p, q, &port->dmaqueue.list) { 20762306a36Sopenharmony_ci buf = list_entry(p, struct saa7164_buffer, list); 20862306a36Sopenharmony_ci buf->flags = SAA7164_BUFFER_FREE; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci mutex_unlock(&port->dmaqueue_lock); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return ret; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int saa7164_dvb_start_port(struct saa7164_port *port) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 21862306a36Sopenharmony_ci int ret = 0, result; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci saa7164_buffer_cfg_port(port); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Acquire the hardware */ 22562306a36Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); 22662306a36Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 22762306a36Sopenharmony_ci printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", 22862306a36Sopenharmony_ci __func__, result); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Stop the hardware, regardless */ 23162306a36Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 23262306a36Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 23362306a36Sopenharmony_ci printk(KERN_ERR "%s() acquire/forced stop transition failed, res = 0x%x\n", 23462306a36Sopenharmony_ci __func__, result); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci ret = -EIO; 23762306a36Sopenharmony_ci goto out; 23862306a36Sopenharmony_ci } else 23962306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* Pause the hardware */ 24262306a36Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); 24362306a36Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 24462306a36Sopenharmony_ci printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", 24562306a36Sopenharmony_ci __func__, result); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Stop the hardware, regardless */ 24862306a36Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 24962306a36Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 25062306a36Sopenharmony_ci printk(KERN_ERR "%s() pause/forced stop transition failed, res = 0x%x\n", 25162306a36Sopenharmony_ci __func__, result); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci ret = -EIO; 25562306a36Sopenharmony_ci goto out; 25662306a36Sopenharmony_ci } else 25762306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Paused\n", __func__); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Start the hardware */ 26062306a36Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); 26162306a36Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 26262306a36Sopenharmony_ci printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", 26362306a36Sopenharmony_ci __func__, result); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* Stop the hardware, regardless */ 26662306a36Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 26762306a36Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 26862306a36Sopenharmony_ci printk(KERN_ERR "%s() run/forced stop transition failed, res = 0x%x\n", 26962306a36Sopenharmony_ci __func__, result); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ret = -EIO; 27362306a36Sopenharmony_ci } else 27462306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Running\n", __func__); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ciout: 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct dvb_demux *demux = feed->demux; 28362306a36Sopenharmony_ci struct saa7164_port *port = demux->priv; 28462306a36Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 28562306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 28662306a36Sopenharmony_ci int ret = 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!demux->dmx.frontend) 29162306a36Sopenharmony_ci return -EINVAL; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (dvb) { 29462306a36Sopenharmony_ci mutex_lock(&dvb->lock); 29562306a36Sopenharmony_ci if (dvb->feeding++ == 0) { 29662306a36Sopenharmony_ci /* Start transport */ 29762306a36Sopenharmony_ci ret = saa7164_dvb_start_port(port); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci mutex_unlock(&dvb->lock); 30062306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", 30162306a36Sopenharmony_ci __func__, port->nr, dvb->feeding); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return ret; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct dvb_demux *demux = feed->demux; 31062306a36Sopenharmony_ci struct saa7164_port *port = demux->priv; 31162306a36Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 31262306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 31362306a36Sopenharmony_ci int ret = 0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (dvb) { 31862306a36Sopenharmony_ci mutex_lock(&dvb->lock); 31962306a36Sopenharmony_ci if (--dvb->feeding == 0) { 32062306a36Sopenharmony_ci /* Stop transport */ 32162306a36Sopenharmony_ci ret = saa7164_dvb_stop_streaming(port); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci mutex_unlock(&dvb->lock); 32462306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", 32562306a36Sopenharmony_ci __func__, port->nr, dvb->feeding); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return ret; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int dvb_register(struct saa7164_port *port) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 33462306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 33562306a36Sopenharmony_ci struct saa7164_buffer *buf; 33662306a36Sopenharmony_ci int result, i; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci BUG_ON(port->type != SAA7164_MPEG_DVB); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* Sanity check that the PCI configuration space is active */ 34362306a36Sopenharmony_ci if (port->hwcfg.BARLocation == 0) { 34462306a36Sopenharmony_ci result = -ENOMEM; 34562306a36Sopenharmony_ci printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d), NO PCI configuration\n", 34662306a36Sopenharmony_ci DRIVER_NAME, result); 34762306a36Sopenharmony_ci goto fail_adapter; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* Init and establish defaults */ 35162306a36Sopenharmony_ci port->hw_streamingparams.bitspersample = 8; 35262306a36Sopenharmony_ci port->hw_streamingparams.samplesperline = 188; 35362306a36Sopenharmony_ci port->hw_streamingparams.numberoflines = 35462306a36Sopenharmony_ci (SAA7164_TS_NUMBER_OF_LINES * 188) / 188; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci port->hw_streamingparams.pitch = 188; 35762306a36Sopenharmony_ci port->hw_streamingparams.linethreshold = 0; 35862306a36Sopenharmony_ci port->hw_streamingparams.pagetablelistvirt = NULL; 35962306a36Sopenharmony_ci port->hw_streamingparams.pagetablelistphys = NULL; 36062306a36Sopenharmony_ci port->hw_streamingparams.numpagetables = 2 + 36162306a36Sopenharmony_ci ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci port->hw_streamingparams.numpagetableentries = port->hwcfg.buffercount; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Allocate the PCI resources */ 36662306a36Sopenharmony_ci for (i = 0; i < port->hwcfg.buffercount; i++) { 36762306a36Sopenharmony_ci buf = saa7164_buffer_alloc(port, 36862306a36Sopenharmony_ci port->hw_streamingparams.numberoflines * 36962306a36Sopenharmony_ci port->hw_streamingparams.pitch); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!buf) { 37262306a36Sopenharmony_ci result = -ENOMEM; 37362306a36Sopenharmony_ci printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d), unable to allocate buffers\n", 37462306a36Sopenharmony_ci DRIVER_NAME, result); 37562306a36Sopenharmony_ci goto fail_adapter; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci mutex_lock(&port->dmaqueue_lock); 37962306a36Sopenharmony_ci list_add_tail(&buf->list, &port->dmaqueue.list); 38062306a36Sopenharmony_ci mutex_unlock(&port->dmaqueue_lock); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* register adapter */ 38462306a36Sopenharmony_ci result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, 38562306a36Sopenharmony_ci &dev->pci->dev, adapter_nr); 38662306a36Sopenharmony_ci if (result < 0) { 38762306a36Sopenharmony_ci printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d)\n", 38862306a36Sopenharmony_ci DRIVER_NAME, result); 38962306a36Sopenharmony_ci goto fail_adapter; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci dvb->adapter.priv = port; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* register frontend */ 39462306a36Sopenharmony_ci result = dvb_register_frontend(&dvb->adapter, dvb->frontend); 39562306a36Sopenharmony_ci if (result < 0) { 39662306a36Sopenharmony_ci printk(KERN_ERR "%s: dvb_register_frontend failed (errno = %d)\n", 39762306a36Sopenharmony_ci DRIVER_NAME, result); 39862306a36Sopenharmony_ci goto fail_frontend; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* register demux stuff */ 40262306a36Sopenharmony_ci dvb->demux.dmx.capabilities = 40362306a36Sopenharmony_ci DMX_TS_FILTERING | DMX_SECTION_FILTERING | 40462306a36Sopenharmony_ci DMX_MEMORY_BASED_FILTERING; 40562306a36Sopenharmony_ci dvb->demux.priv = port; 40662306a36Sopenharmony_ci dvb->demux.filternum = 256; 40762306a36Sopenharmony_ci dvb->demux.feednum = 256; 40862306a36Sopenharmony_ci dvb->demux.start_feed = saa7164_dvb_start_feed; 40962306a36Sopenharmony_ci dvb->demux.stop_feed = saa7164_dvb_stop_feed; 41062306a36Sopenharmony_ci result = dvb_dmx_init(&dvb->demux); 41162306a36Sopenharmony_ci if (result < 0) { 41262306a36Sopenharmony_ci printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", 41362306a36Sopenharmony_ci DRIVER_NAME, result); 41462306a36Sopenharmony_ci goto fail_dmx; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci dvb->dmxdev.filternum = 256; 41862306a36Sopenharmony_ci dvb->dmxdev.demux = &dvb->demux.dmx; 41962306a36Sopenharmony_ci dvb->dmxdev.capabilities = 0; 42062306a36Sopenharmony_ci result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); 42162306a36Sopenharmony_ci if (result < 0) { 42262306a36Sopenharmony_ci printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", 42362306a36Sopenharmony_ci DRIVER_NAME, result); 42462306a36Sopenharmony_ci goto fail_dmxdev; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci dvb->fe_hw.source = DMX_FRONTEND_0; 42862306a36Sopenharmony_ci result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); 42962306a36Sopenharmony_ci if (result < 0) { 43062306a36Sopenharmony_ci printk(KERN_ERR "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", 43162306a36Sopenharmony_ci DRIVER_NAME, result); 43262306a36Sopenharmony_ci goto fail_fe_hw; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci dvb->fe_mem.source = DMX_MEMORY_FE; 43662306a36Sopenharmony_ci result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); 43762306a36Sopenharmony_ci if (result < 0) { 43862306a36Sopenharmony_ci printk(KERN_ERR "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", 43962306a36Sopenharmony_ci DRIVER_NAME, result); 44062306a36Sopenharmony_ci goto fail_fe_mem; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); 44462306a36Sopenharmony_ci if (result < 0) { 44562306a36Sopenharmony_ci printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", 44662306a36Sopenharmony_ci DRIVER_NAME, result); 44762306a36Sopenharmony_ci goto fail_fe_conn; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* register network adapter */ 45162306a36Sopenharmony_ci dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cifail_fe_conn: 45562306a36Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); 45662306a36Sopenharmony_cifail_fe_mem: 45762306a36Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); 45862306a36Sopenharmony_cifail_fe_hw: 45962306a36Sopenharmony_ci dvb_dmxdev_release(&dvb->dmxdev); 46062306a36Sopenharmony_cifail_dmxdev: 46162306a36Sopenharmony_ci dvb_dmx_release(&dvb->demux); 46262306a36Sopenharmony_cifail_dmx: 46362306a36Sopenharmony_ci dvb_unregister_frontend(dvb->frontend); 46462306a36Sopenharmony_cifail_frontend: 46562306a36Sopenharmony_ci dvb_frontend_detach(dvb->frontend); 46662306a36Sopenharmony_ci dvb_unregister_adapter(&dvb->adapter); 46762306a36Sopenharmony_cifail_adapter: 46862306a36Sopenharmony_ci return result; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciint saa7164_dvb_unregister(struct saa7164_port *port) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 47462306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 47562306a36Sopenharmony_ci struct saa7164_buffer *b; 47662306a36Sopenharmony_ci struct list_head *c, *n; 47762306a36Sopenharmony_ci struct i2c_client *client; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s()\n", __func__); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci BUG_ON(port->type != SAA7164_MPEG_DVB); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Remove any allocated buffers */ 48462306a36Sopenharmony_ci mutex_lock(&port->dmaqueue_lock); 48562306a36Sopenharmony_ci list_for_each_safe(c, n, &port->dmaqueue.list) { 48662306a36Sopenharmony_ci b = list_entry(c, struct saa7164_buffer, list); 48762306a36Sopenharmony_ci list_del(c); 48862306a36Sopenharmony_ci saa7164_buffer_dealloc(b); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci mutex_unlock(&port->dmaqueue_lock); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (dvb->frontend == NULL) 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci /* remove I2C client for tuner */ 49662306a36Sopenharmony_ci client = port->i2c_client_tuner; 49762306a36Sopenharmony_ci if (client) { 49862306a36Sopenharmony_ci module_put(client->dev.driver->owner); 49962306a36Sopenharmony_ci i2c_unregister_device(client); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* remove I2C client for demodulator */ 50362306a36Sopenharmony_ci client = port->i2c_client_demod; 50462306a36Sopenharmony_ci if (client) { 50562306a36Sopenharmony_ci module_put(client->dev.driver->owner); 50662306a36Sopenharmony_ci i2c_unregister_device(client); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci dvb_net_release(&dvb->net); 51062306a36Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); 51162306a36Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); 51262306a36Sopenharmony_ci dvb_dmxdev_release(&dvb->dmxdev); 51362306a36Sopenharmony_ci dvb_dmx_release(&dvb->demux); 51462306a36Sopenharmony_ci dvb_unregister_frontend(dvb->frontend); 51562306a36Sopenharmony_ci dvb_frontend_detach(dvb->frontend); 51662306a36Sopenharmony_ci dvb_unregister_adapter(&dvb->adapter); 51762306a36Sopenharmony_ci return 0; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/* All the DVB attach calls go here, this function gets modified 52162306a36Sopenharmony_ci * for each new card. 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ciint saa7164_dvb_register(struct saa7164_port *port) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct saa7164_dev *dev = port->dev; 52662306a36Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 52762306a36Sopenharmony_ci struct saa7164_i2c *i2c_bus = NULL; 52862306a36Sopenharmony_ci struct si2168_config si2168_config; 52962306a36Sopenharmony_ci struct si2157_config si2157_config; 53062306a36Sopenharmony_ci struct i2c_adapter *adapter; 53162306a36Sopenharmony_ci struct i2c_board_info info; 53262306a36Sopenharmony_ci struct i2c_client *client_demod; 53362306a36Sopenharmony_ci struct i2c_client *client_tuner; 53462306a36Sopenharmony_ci int ret; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci dprintk(DBGLVL_DVB, "%s()\n", __func__); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* init frontend */ 53962306a36Sopenharmony_ci switch (dev->board) { 54062306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200: 54162306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: 54262306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: 54362306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: 54462306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200_5: 54562306a36Sopenharmony_ci i2c_bus = &dev->i2c_bus[port->nr + 1]; 54662306a36Sopenharmony_ci switch (port->nr) { 54762306a36Sopenharmony_ci case 0: 54862306a36Sopenharmony_ci port->dvb.frontend = dvb_attach(tda10048_attach, 54962306a36Sopenharmony_ci &hauppauge_hvr2200_1_config, 55062306a36Sopenharmony_ci &i2c_bus->i2c_adap); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (port->dvb.frontend != NULL) { 55362306a36Sopenharmony_ci /* TODO: addr is in the card struct */ 55462306a36Sopenharmony_ci dvb_attach(tda18271_attach, port->dvb.frontend, 55562306a36Sopenharmony_ci 0xc0 >> 1, &i2c_bus->i2c_adap, 55662306a36Sopenharmony_ci &hauppauge_hvr22x0_tuner_config); 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci case 1: 56162306a36Sopenharmony_ci port->dvb.frontend = dvb_attach(tda10048_attach, 56262306a36Sopenharmony_ci &hauppauge_hvr2200_2_config, 56362306a36Sopenharmony_ci &i2c_bus->i2c_adap); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (port->dvb.frontend != NULL) { 56662306a36Sopenharmony_ci /* TODO: addr is in the card struct */ 56762306a36Sopenharmony_ci dvb_attach(tda18271_attach, port->dvb.frontend, 56862306a36Sopenharmony_ci 0xc0 >> 1, &i2c_bus->i2c_adap, 56962306a36Sopenharmony_ci &hauppauge_hvr22x0s_tuner_config); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci break; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2250: 57662306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: 57762306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: 57862306a36Sopenharmony_ci i2c_bus = &dev->i2c_bus[port->nr + 1]; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci port->dvb.frontend = dvb_attach(s5h1411_attach, 58162306a36Sopenharmony_ci &hauppauge_s5h1411_config, 58262306a36Sopenharmony_ci &i2c_bus->i2c_adap); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (port->dvb.frontend != NULL) { 58562306a36Sopenharmony_ci if (port->nr == 0) { 58662306a36Sopenharmony_ci /* Master TDA18271 */ 58762306a36Sopenharmony_ci /* TODO: addr is in the card struct */ 58862306a36Sopenharmony_ci dvb_attach(tda18271_attach, port->dvb.frontend, 58962306a36Sopenharmony_ci 0xc0 >> 1, &i2c_bus->i2c_adap, 59062306a36Sopenharmony_ci &hauppauge_hvr22x0_tuner_config); 59162306a36Sopenharmony_ci } else { 59262306a36Sopenharmony_ci /* Slave TDA18271 */ 59362306a36Sopenharmony_ci dvb_attach(tda18271_attach, port->dvb.frontend, 59462306a36Sopenharmony_ci 0xc0 >> 1, &i2c_bus->i2c_adap, 59562306a36Sopenharmony_ci &hauppauge_hvr22x0s_tuner_config); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2255proto: 60162306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2255: 60262306a36Sopenharmony_ci i2c_bus = &dev->i2c_bus[2]; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (port->nr == 0) { 60562306a36Sopenharmony_ci port->dvb.frontend = dvb_attach(lgdt3306a_attach, 60662306a36Sopenharmony_ci &hauppauge_hvr2255a_config, &i2c_bus->i2c_adap); 60762306a36Sopenharmony_ci } else { 60862306a36Sopenharmony_ci port->dvb.frontend = dvb_attach(lgdt3306a_attach, 60962306a36Sopenharmony_ci &hauppauge_hvr2255b_config, &i2c_bus->i2c_adap); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (port->dvb.frontend != NULL) { 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (port->nr == 0) { 61562306a36Sopenharmony_ci si2157_attach(port, &dev->i2c_bus[0].i2c_adap, 61662306a36Sopenharmony_ci port->dvb.frontend, 0xc0, 61762306a36Sopenharmony_ci &hauppauge_hvr2255_tuner_config); 61862306a36Sopenharmony_ci } else { 61962306a36Sopenharmony_ci si2157_attach(port, &dev->i2c_bus[1].i2c_adap, 62062306a36Sopenharmony_ci port->dvb.frontend, 0xc0, 62162306a36Sopenharmony_ci &hauppauge_hvr2255_tuner_config); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2205: 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (port->nr == 0) { 62862306a36Sopenharmony_ci /* attach frontend */ 62962306a36Sopenharmony_ci memset(&si2168_config, 0, sizeof(si2168_config)); 63062306a36Sopenharmony_ci si2168_config.i2c_adapter = &adapter; 63162306a36Sopenharmony_ci si2168_config.fe = &port->dvb.frontend; 63262306a36Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_SERIAL; 63362306a36Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 63462306a36Sopenharmony_ci strscpy(info.type, "si2168", I2C_NAME_SIZE); 63562306a36Sopenharmony_ci info.addr = 0xc8 >> 1; 63662306a36Sopenharmony_ci info.platform_data = &si2168_config; 63762306a36Sopenharmony_ci request_module(info.type); 63862306a36Sopenharmony_ci client_demod = i2c_new_client_device(&dev->i2c_bus[2].i2c_adap, &info); 63962306a36Sopenharmony_ci if (!i2c_client_has_driver(client_demod)) 64062306a36Sopenharmony_ci goto frontend_detach; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (!try_module_get(client_demod->dev.driver->owner)) { 64362306a36Sopenharmony_ci i2c_unregister_device(client_demod); 64462306a36Sopenharmony_ci goto frontend_detach; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci port->i2c_client_demod = client_demod; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* attach tuner */ 64962306a36Sopenharmony_ci memset(&si2157_config, 0, sizeof(si2157_config)); 65062306a36Sopenharmony_ci si2157_config.if_port = 1; 65162306a36Sopenharmony_ci si2157_config.fe = port->dvb.frontend; 65262306a36Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 65362306a36Sopenharmony_ci strscpy(info.type, "si2157", I2C_NAME_SIZE); 65462306a36Sopenharmony_ci info.addr = 0xc0 >> 1; 65562306a36Sopenharmony_ci info.platform_data = &si2157_config; 65662306a36Sopenharmony_ci request_module(info.type); 65762306a36Sopenharmony_ci client_tuner = i2c_new_client_device(&dev->i2c_bus[0].i2c_adap, &info); 65862306a36Sopenharmony_ci if (!i2c_client_has_driver(client_tuner)) { 65962306a36Sopenharmony_ci module_put(client_demod->dev.driver->owner); 66062306a36Sopenharmony_ci i2c_unregister_device(client_demod); 66162306a36Sopenharmony_ci goto frontend_detach; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci if (!try_module_get(client_tuner->dev.driver->owner)) { 66462306a36Sopenharmony_ci i2c_unregister_device(client_tuner); 66562306a36Sopenharmony_ci module_put(client_demod->dev.driver->owner); 66662306a36Sopenharmony_ci i2c_unregister_device(client_demod); 66762306a36Sopenharmony_ci goto frontend_detach; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci port->i2c_client_tuner = client_tuner; 67062306a36Sopenharmony_ci } else { 67162306a36Sopenharmony_ci /* attach frontend */ 67262306a36Sopenharmony_ci memset(&si2168_config, 0, sizeof(si2168_config)); 67362306a36Sopenharmony_ci si2168_config.i2c_adapter = &adapter; 67462306a36Sopenharmony_ci si2168_config.fe = &port->dvb.frontend; 67562306a36Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_SERIAL; 67662306a36Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 67762306a36Sopenharmony_ci strscpy(info.type, "si2168", I2C_NAME_SIZE); 67862306a36Sopenharmony_ci info.addr = 0xcc >> 1; 67962306a36Sopenharmony_ci info.platform_data = &si2168_config; 68062306a36Sopenharmony_ci request_module(info.type); 68162306a36Sopenharmony_ci client_demod = i2c_new_client_device(&dev->i2c_bus[2].i2c_adap, &info); 68262306a36Sopenharmony_ci if (!i2c_client_has_driver(client_demod)) 68362306a36Sopenharmony_ci goto frontend_detach; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (!try_module_get(client_demod->dev.driver->owner)) { 68662306a36Sopenharmony_ci i2c_unregister_device(client_demod); 68762306a36Sopenharmony_ci goto frontend_detach; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci port->i2c_client_demod = client_demod; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* attach tuner */ 69262306a36Sopenharmony_ci memset(&si2157_config, 0, sizeof(si2157_config)); 69362306a36Sopenharmony_ci si2157_config.fe = port->dvb.frontend; 69462306a36Sopenharmony_ci si2157_config.if_port = 1; 69562306a36Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 69662306a36Sopenharmony_ci strscpy(info.type, "si2157", I2C_NAME_SIZE); 69762306a36Sopenharmony_ci info.addr = 0xc0 >> 1; 69862306a36Sopenharmony_ci info.platform_data = &si2157_config; 69962306a36Sopenharmony_ci request_module(info.type); 70062306a36Sopenharmony_ci client_tuner = i2c_new_client_device(&dev->i2c_bus[1].i2c_adap, &info); 70162306a36Sopenharmony_ci if (!i2c_client_has_driver(client_tuner)) { 70262306a36Sopenharmony_ci module_put(client_demod->dev.driver->owner); 70362306a36Sopenharmony_ci i2c_unregister_device(client_demod); 70462306a36Sopenharmony_ci goto frontend_detach; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci if (!try_module_get(client_tuner->dev.driver->owner)) { 70762306a36Sopenharmony_ci i2c_unregister_device(client_tuner); 70862306a36Sopenharmony_ci module_put(client_demod->dev.driver->owner); 70962306a36Sopenharmony_ci i2c_unregister_device(client_demod); 71062306a36Sopenharmony_ci goto frontend_detach; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci port->i2c_client_tuner = client_tuner; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci break; 71662306a36Sopenharmony_ci default: 71762306a36Sopenharmony_ci printk(KERN_ERR "%s: The frontend isn't supported\n", 71862306a36Sopenharmony_ci dev->name); 71962306a36Sopenharmony_ci break; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci if (NULL == dvb->frontend) { 72262306a36Sopenharmony_ci printk(KERN_ERR "%s() Frontend initialization failed\n", 72362306a36Sopenharmony_ci __func__); 72462306a36Sopenharmony_ci return -1; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* register everything */ 72862306a36Sopenharmony_ci ret = dvb_register(port); 72962306a36Sopenharmony_ci if (ret < 0) { 73062306a36Sopenharmony_ci if (dvb->frontend->ops.release) 73162306a36Sopenharmony_ci dvb->frontend->ops.release(dvb->frontend); 73262306a36Sopenharmony_ci return ret; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cifrontend_detach: 73862306a36Sopenharmony_ci printk(KERN_ERR "%s() Frontend/I2C initialization failed\n", __func__); 73962306a36Sopenharmony_ci return -1; 74062306a36Sopenharmony_ci} 741