18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci DVB device driver for cx231xx 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (C) 2008 <srinivasa.deevi at conexant dot com> 68c2ecf20Sopenharmony_ci Based on em28xx driver 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "cx231xx.h" 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <media/dvbdev.h> 158c2ecf20Sopenharmony_ci#include <media/dmxdev.h> 168c2ecf20Sopenharmony_ci#include <media/dvb_demux.h> 178c2ecf20Sopenharmony_ci#include <media/dvb_net.h> 188c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 198c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 208c2ecf20Sopenharmony_ci#include <media/tuner.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "xc5000.h" 238c2ecf20Sopenharmony_ci#include "s5h1432.h" 248c2ecf20Sopenharmony_ci#include "tda18271.h" 258c2ecf20Sopenharmony_ci#include "s5h1411.h" 268c2ecf20Sopenharmony_ci#include "lgdt3305.h" 278c2ecf20Sopenharmony_ci#include "si2165.h" 288c2ecf20Sopenharmony_ci#include "si2168.h" 298c2ecf20Sopenharmony_ci#include "mb86a20s.h" 308c2ecf20Sopenharmony_ci#include "si2157.h" 318c2ecf20Sopenharmony_ci#include "lgdt3306a.h" 328c2ecf20Sopenharmony_ci#include "r820t.h" 338c2ecf20Sopenharmony_ci#include "mn88473.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("driver for cx231xx based DVB cards"); 368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>"); 378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic unsigned int debug; 408c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "enable debug messages [dvb]"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define CX231XX_DVB_NUM_BUFS 5 468c2ecf20Sopenharmony_ci#define CX231XX_DVB_MAX_PACKETSIZE 564 478c2ecf20Sopenharmony_ci#define CX231XX_DVB_MAX_PACKETS 64 488c2ecf20Sopenharmony_ci#define CX231XX_DVB_MAX_FRONTENDS 2 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct cx231xx_dvb { 518c2ecf20Sopenharmony_ci struct dvb_frontend *frontend[CX231XX_DVB_MAX_FRONTENDS]; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* feed count management */ 548c2ecf20Sopenharmony_ci struct mutex lock; 558c2ecf20Sopenharmony_ci int nfeeds; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* general boilerplate stuff */ 588c2ecf20Sopenharmony_ci struct dvb_adapter adapter; 598c2ecf20Sopenharmony_ci struct dvb_demux demux; 608c2ecf20Sopenharmony_ci struct dmxdev dmxdev; 618c2ecf20Sopenharmony_ci struct dmx_frontend fe_hw; 628c2ecf20Sopenharmony_ci struct dmx_frontend fe_mem; 638c2ecf20Sopenharmony_ci struct dvb_net net; 648c2ecf20Sopenharmony_ci struct i2c_client *i2c_client_demod[2]; 658c2ecf20Sopenharmony_ci struct i2c_client *i2c_client_tuner; 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic struct s5h1432_config dvico_s5h1432_config = { 698c2ecf20Sopenharmony_ci .output_mode = S5H1432_SERIAL_OUTPUT, 708c2ecf20Sopenharmony_ci .gpio = S5H1432_GPIO_ON, 718c2ecf20Sopenharmony_ci .qam_if = S5H1432_IF_4000, 728c2ecf20Sopenharmony_ci .vsb_if = S5H1432_IF_4000, 738c2ecf20Sopenharmony_ci .inversion = S5H1432_INVERSION_OFF, 748c2ecf20Sopenharmony_ci .status_mode = S5H1432_DEMODLOCKING, 758c2ecf20Sopenharmony_ci .mpeg_timing = S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { 798c2ecf20Sopenharmony_ci .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, 808c2ecf20Sopenharmony_ci .if_lvl = 1, .rfagc_top = 0x37, }, 818c2ecf20Sopenharmony_ci .dvbt_7 = { .if_freq = 4000, .agc_mode = 3, .std = 5, 828c2ecf20Sopenharmony_ci .if_lvl = 1, .rfagc_top = 0x37, }, 838c2ecf20Sopenharmony_ci .dvbt_8 = { .if_freq = 4000, .agc_mode = 3, .std = 6, 848c2ecf20Sopenharmony_ci .if_lvl = 1, .rfagc_top = 0x37, }, 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic struct tda18271_std_map mb86a20s_tda18271_config = { 888c2ecf20Sopenharmony_ci .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, 898c2ecf20Sopenharmony_ci .if_lvl = 0, .rfagc_top = 0x37, }, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic struct tda18271_config cnxt_rde253s_tunerconfig = { 938c2ecf20Sopenharmony_ci .std_map = &cnxt_rde253s_tda18271_std_map, 948c2ecf20Sopenharmony_ci .gate = TDA18271_GATE_ANALOG, 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic struct s5h1411_config tda18271_s5h1411_config = { 988c2ecf20Sopenharmony_ci .output_mode = S5H1411_SERIAL_OUTPUT, 998c2ecf20Sopenharmony_ci .gpio = S5H1411_GPIO_OFF, 1008c2ecf20Sopenharmony_ci .vsb_if = S5H1411_IF_3250, 1018c2ecf20Sopenharmony_ci .qam_if = S5H1411_IF_4000, 1028c2ecf20Sopenharmony_ci .inversion = S5H1411_INVERSION_ON, 1038c2ecf20Sopenharmony_ci .status_mode = S5H1411_DEMODLOCKING, 1048c2ecf20Sopenharmony_ci .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_cistatic struct s5h1411_config xc5000_s5h1411_config = { 1078c2ecf20Sopenharmony_ci .output_mode = S5H1411_SERIAL_OUTPUT, 1088c2ecf20Sopenharmony_ci .gpio = S5H1411_GPIO_OFF, 1098c2ecf20Sopenharmony_ci .vsb_if = S5H1411_IF_3250, 1108c2ecf20Sopenharmony_ci .qam_if = S5H1411_IF_3250, 1118c2ecf20Sopenharmony_ci .inversion = S5H1411_INVERSION_OFF, 1128c2ecf20Sopenharmony_ci .status_mode = S5H1411_DEMODLOCKING, 1138c2ecf20Sopenharmony_ci .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic struct lgdt3305_config hcw_lgdt3305_config = { 1178c2ecf20Sopenharmony_ci .i2c_addr = 0x0e, 1188c2ecf20Sopenharmony_ci .mpeg_mode = LGDT3305_MPEG_SERIAL, 1198c2ecf20Sopenharmony_ci .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, 1208c2ecf20Sopenharmony_ci .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, 1218c2ecf20Sopenharmony_ci .deny_i2c_rptr = 1, 1228c2ecf20Sopenharmony_ci .spectral_inversion = 1, 1238c2ecf20Sopenharmony_ci .qam_if_khz = 4000, 1248c2ecf20Sopenharmony_ci .vsb_if_khz = 3250, 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic struct tda18271_std_map hauppauge_tda18271_std_map = { 1288c2ecf20Sopenharmony_ci .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, 1298c2ecf20Sopenharmony_ci .if_lvl = 1, .rfagc_top = 0x58, }, 1308c2ecf20Sopenharmony_ci .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, 1318c2ecf20Sopenharmony_ci .if_lvl = 1, .rfagc_top = 0x58, }, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic struct tda18271_config hcw_tda18271_config = { 1358c2ecf20Sopenharmony_ci .std_map = &hauppauge_tda18271_std_map, 1368c2ecf20Sopenharmony_ci .gate = TDA18271_GATE_DIGITAL, 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const struct mb86a20s_config pv_mb86a20s_config = { 1408c2ecf20Sopenharmony_ci .demod_address = 0x10, 1418c2ecf20Sopenharmony_ci .is_serial = true, 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic struct tda18271_config pv_tda18271_config = { 1458c2ecf20Sopenharmony_ci .std_map = &mb86a20s_tda18271_config, 1468c2ecf20Sopenharmony_ci .gate = TDA18271_GATE_DIGITAL, 1478c2ecf20Sopenharmony_ci .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic const struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { 1518c2ecf20Sopenharmony_ci .qam_if_khz = 4000, 1528c2ecf20Sopenharmony_ci .vsb_if_khz = 3250, 1538c2ecf20Sopenharmony_ci .spectral_inversion = 1, 1548c2ecf20Sopenharmony_ci .mpeg_mode = LGDT3306A_MPEG_SERIAL, 1558c2ecf20Sopenharmony_ci .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, 1568c2ecf20Sopenharmony_ci .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, 1578c2ecf20Sopenharmony_ci .xtalMHz = 25, 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic struct r820t_config astrometa_t2hybrid_r820t_config = { 1618c2ecf20Sopenharmony_ci .i2c_addr = 0x3a, /* 0x74 >> 1 */ 1628c2ecf20Sopenharmony_ci .xtal = 16000000, 1638c2ecf20Sopenharmony_ci .rafael_chip = CHIP_R828D, 1648c2ecf20Sopenharmony_ci .max_i2c_msg_len = 2, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic inline void print_err_status(struct cx231xx *dev, int packet, int status) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci char *errmsg = "Unknown"; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci switch (status) { 1728c2ecf20Sopenharmony_ci case -ENOENT: 1738c2ecf20Sopenharmony_ci errmsg = "unlinked synchronously"; 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci case -ECONNRESET: 1768c2ecf20Sopenharmony_ci errmsg = "unlinked asynchronously"; 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci case -ENOSR: 1798c2ecf20Sopenharmony_ci errmsg = "Buffer error (overrun)"; 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci case -EPIPE: 1828c2ecf20Sopenharmony_ci errmsg = "Stalled (device not responding)"; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case -EOVERFLOW: 1858c2ecf20Sopenharmony_ci errmsg = "Babble (bad cable?)"; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case -EPROTO: 1888c2ecf20Sopenharmony_ci errmsg = "Bit-stuff error (bad cable?)"; 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci case -EILSEQ: 1918c2ecf20Sopenharmony_ci errmsg = "CRC/Timeout (could be anything)"; 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci case -ETIME: 1948c2ecf20Sopenharmony_ci errmsg = "Device does not respond"; 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci if (packet < 0) { 1988c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 1998c2ecf20Sopenharmony_ci "URB status %d [%s].\n", status, errmsg); 2008c2ecf20Sopenharmony_ci } else { 2018c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 2028c2ecf20Sopenharmony_ci "URB packet %d, status %d [%s].\n", 2038c2ecf20Sopenharmony_ci packet, status, errmsg); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci int i; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (!dev) 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (dev->state & DEV_DISCONNECTED) 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (urb->status < 0) { 2188c2ecf20Sopenharmony_ci print_err_status(dev, -1, urb->status); 2198c2ecf20Sopenharmony_ci if (urb->status == -ENOENT) 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci for (i = 0; i < urb->number_of_packets; i++) { 2248c2ecf20Sopenharmony_ci int status = urb->iso_frame_desc[i].status; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (status < 0) { 2278c2ecf20Sopenharmony_ci print_err_status(dev, i, status); 2288c2ecf20Sopenharmony_ci if (urb->iso_frame_desc[i].status != -EPROTO) 2298c2ecf20Sopenharmony_ci continue; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci dvb_dmx_swfilter(&dev->dvb->demux, 2338c2ecf20Sopenharmony_ci urb->transfer_buffer + 2348c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].offset, 2358c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].actual_length); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci if (!dev) 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (dev->state & DEV_DISCONNECTED) 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (urb->status < 0) { 2508c2ecf20Sopenharmony_ci print_err_status(dev, -1, urb->status); 2518c2ecf20Sopenharmony_ci if (urb->status == -ENOENT) 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Feed the transport payload into the kernel demux */ 2568c2ecf20Sopenharmony_ci dvb_dmx_swfilter(&dev->dvb->demux, 2578c2ecf20Sopenharmony_ci urb->transfer_buffer, urb->actual_length); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return 0; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int start_streaming(struct cx231xx_dvb *dvb) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci int rc; 2658c2ecf20Sopenharmony_ci struct cx231xx *dev = dvb->adapter.priv; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (dev->USE_ISO) { 2688c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "DVB transfer mode is ISO.\n"); 2698c2ecf20Sopenharmony_ci cx231xx_set_alt_setting(dev, INDEX_TS1, 5); 2708c2ecf20Sopenharmony_ci rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); 2718c2ecf20Sopenharmony_ci if (rc < 0) 2728c2ecf20Sopenharmony_ci return rc; 2738c2ecf20Sopenharmony_ci dev->mode_tv = 1; 2748c2ecf20Sopenharmony_ci return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS, 2758c2ecf20Sopenharmony_ci CX231XX_DVB_NUM_BUFS, 2768c2ecf20Sopenharmony_ci dev->ts1_mode.max_pkt_size, 2778c2ecf20Sopenharmony_ci dvb_isoc_copy); 2788c2ecf20Sopenharmony_ci } else { 2798c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "DVB transfer mode is BULK.\n"); 2808c2ecf20Sopenharmony_ci cx231xx_set_alt_setting(dev, INDEX_TS1, 0); 2818c2ecf20Sopenharmony_ci rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); 2828c2ecf20Sopenharmony_ci if (rc < 0) 2838c2ecf20Sopenharmony_ci return rc; 2848c2ecf20Sopenharmony_ci dev->mode_tv = 1; 2858c2ecf20Sopenharmony_ci return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS, 2868c2ecf20Sopenharmony_ci CX231XX_DVB_NUM_BUFS, 2878c2ecf20Sopenharmony_ci dev->ts1_mode.max_pkt_size, 2888c2ecf20Sopenharmony_ci dvb_bulk_copy); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic int stop_streaming(struct cx231xx_dvb *dvb) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct cx231xx *dev = dvb->adapter.priv; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (dev->USE_ISO) 2988c2ecf20Sopenharmony_ci cx231xx_uninit_isoc(dev); 2998c2ecf20Sopenharmony_ci else 3008c2ecf20Sopenharmony_ci cx231xx_uninit_bulk(dev); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci cx231xx_set_mode(dev, CX231XX_SUSPEND); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int start_feed(struct dvb_demux_feed *feed) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct dvb_demux *demux = feed->demux; 3108c2ecf20Sopenharmony_ci struct cx231xx_dvb *dvb = demux->priv; 3118c2ecf20Sopenharmony_ci int rc, ret; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (!demux->dmx.frontend) 3148c2ecf20Sopenharmony_ci return -EINVAL; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci mutex_lock(&dvb->lock); 3178c2ecf20Sopenharmony_ci dvb->nfeeds++; 3188c2ecf20Sopenharmony_ci rc = dvb->nfeeds; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (dvb->nfeeds == 1) { 3218c2ecf20Sopenharmony_ci ret = start_streaming(dvb); 3228c2ecf20Sopenharmony_ci if (ret < 0) 3238c2ecf20Sopenharmony_ci rc = ret; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci mutex_unlock(&dvb->lock); 3278c2ecf20Sopenharmony_ci return rc; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int stop_feed(struct dvb_demux_feed *feed) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct dvb_demux *demux = feed->demux; 3338c2ecf20Sopenharmony_ci struct cx231xx_dvb *dvb = demux->priv; 3348c2ecf20Sopenharmony_ci int err = 0; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci mutex_lock(&dvb->lock); 3378c2ecf20Sopenharmony_ci dvb->nfeeds--; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (0 == dvb->nfeeds) 3408c2ecf20Sopenharmony_ci err = stop_streaming(dvb); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci mutex_unlock(&dvb->lock); 3438c2ecf20Sopenharmony_ci return err; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 3478c2ecf20Sopenharmony_cistatic int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct cx231xx *dev = fe->dvb->priv; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (acquire) 3528c2ecf20Sopenharmony_ci return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); 3538c2ecf20Sopenharmony_ci else 3548c2ecf20Sopenharmony_ci return cx231xx_set_mode(dev, CX231XX_SUSPEND); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic struct xc5000_config cnxt_rde250_tunerconfig = { 3608c2ecf20Sopenharmony_ci .i2c_address = 0x61, 3618c2ecf20Sopenharmony_ci .if_khz = 4000, 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_cistatic struct xc5000_config cnxt_rdu250_tunerconfig = { 3648c2ecf20Sopenharmony_ci .i2c_address = 0x61, 3658c2ecf20Sopenharmony_ci .if_khz = 3250, 3668c2ecf20Sopenharmony_ci}; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 3698c2ecf20Sopenharmony_ci#if 0 3708c2ecf20Sopenharmony_cistatic int attach_xc5000(u8 addr, struct cx231xx *dev) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci struct dvb_frontend *fe; 3748c2ecf20Sopenharmony_ci struct xc5000_config cfg; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 3778c2ecf20Sopenharmony_ci cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master); 3788c2ecf20Sopenharmony_ci cfg.i2c_addr = addr; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (!dev->dvb->frontend[0]) { 3818c2ecf20Sopenharmony_ci dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n", 3828c2ecf20Sopenharmony_ci dev->name); 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg); 3878c2ecf20Sopenharmony_ci if (!fe) { 3888c2ecf20Sopenharmony_ci dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name); 3898c2ecf20Sopenharmony_ci dvb_frontend_detach(dev->dvb->frontend[0]); 3908c2ecf20Sopenharmony_ci dev->dvb->frontend[0] = NULL; 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci dev_info(dev->dev, "%s/2: xc5000 attached\n", dev->name); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci#endif 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ciint cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci if (dev->dvb && dev->dvb->frontend[0]) { 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (dops->set_analog_params != NULL) { 4078c2ecf20Sopenharmony_ci struct analog_parameters params; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci params.frequency = freq; 4108c2ecf20Sopenharmony_ci params.std = dev->norm; 4118c2ecf20Sopenharmony_ci params.mode = 0; /* 0- Air; 1 - cable */ 4128c2ecf20Sopenharmony_ci /*params.audmode = ; */ 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* Set the analog parameters to set the frequency */ 4158c2ecf20Sopenharmony_ci dops->set_analog_params(dev->dvb->frontend[0], ¶ms); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ciint cx231xx_reset_analog_tuner(struct cx231xx *dev) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci int status = 0; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (dev->dvb && dev->dvb->frontend[0]) { 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (dops->init != NULL && !dev->xc_fw_load_done) { 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 4348c2ecf20Sopenharmony_ci "Reloading firmware for XC5000\n"); 4358c2ecf20Sopenharmony_ci status = dops->init(dev->dvb->frontend[0]); 4368c2ecf20Sopenharmony_ci if (status == 0) { 4378c2ecf20Sopenharmony_ci dev->xc_fw_load_done = 1; 4388c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 4398c2ecf20Sopenharmony_ci "XC5000 firmware download completed\n"); 4408c2ecf20Sopenharmony_ci } else { 4418c2ecf20Sopenharmony_ci dev->xc_fw_load_done = 0; 4428c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 4438c2ecf20Sopenharmony_ci "XC5000 firmware download failed !!!\n"); 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return status; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */ 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int register_dvb(struct cx231xx_dvb *dvb, 4558c2ecf20Sopenharmony_ci struct module *module, 4568c2ecf20Sopenharmony_ci struct cx231xx *dev, struct device *device) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci int result; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci mutex_init(&dvb->lock); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* register adapter */ 4648c2ecf20Sopenharmony_ci result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, 4658c2ecf20Sopenharmony_ci adapter_nr); 4668c2ecf20Sopenharmony_ci if (result < 0) { 4678c2ecf20Sopenharmony_ci dev_warn(dev->dev, 4688c2ecf20Sopenharmony_ci "%s: dvb_register_adapter failed (errno = %d)\n", 4698c2ecf20Sopenharmony_ci dev->name, result); 4708c2ecf20Sopenharmony_ci goto fail_adapter; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci dvb_register_media_controller(&dvb->adapter, dev->media_dev); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* Ensure all frontends negotiate bus access */ 4758c2ecf20Sopenharmony_ci dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; 4768c2ecf20Sopenharmony_ci if (dvb->frontend[1]) 4778c2ecf20Sopenharmony_ci dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci dvb->adapter.priv = dev; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* register frontend */ 4828c2ecf20Sopenharmony_ci result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]); 4838c2ecf20Sopenharmony_ci if (result < 0) { 4848c2ecf20Sopenharmony_ci dev_warn(dev->dev, 4858c2ecf20Sopenharmony_ci "%s: dvb_register_frontend failed (errno = %d)\n", 4868c2ecf20Sopenharmony_ci dev->name, result); 4878c2ecf20Sopenharmony_ci goto fail_frontend0; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (dvb->frontend[1]) { 4918c2ecf20Sopenharmony_ci result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]); 4928c2ecf20Sopenharmony_ci if (result < 0) { 4938c2ecf20Sopenharmony_ci dev_warn(dev->dev, 4948c2ecf20Sopenharmony_ci "%s: 2nd dvb_register_frontend failed (errno = %d)\n", 4958c2ecf20Sopenharmony_ci dev->name, result); 4968c2ecf20Sopenharmony_ci goto fail_frontend1; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* MFE lock */ 5008c2ecf20Sopenharmony_ci dvb->adapter.mfe_shared = 1; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* register demux stuff */ 5048c2ecf20Sopenharmony_ci dvb->demux.dmx.capabilities = 5058c2ecf20Sopenharmony_ci DMX_TS_FILTERING | DMX_SECTION_FILTERING | 5068c2ecf20Sopenharmony_ci DMX_MEMORY_BASED_FILTERING; 5078c2ecf20Sopenharmony_ci dvb->demux.priv = dvb; 5088c2ecf20Sopenharmony_ci dvb->demux.filternum = 256; 5098c2ecf20Sopenharmony_ci dvb->demux.feednum = 256; 5108c2ecf20Sopenharmony_ci dvb->demux.start_feed = start_feed; 5118c2ecf20Sopenharmony_ci dvb->demux.stop_feed = stop_feed; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci result = dvb_dmx_init(&dvb->demux); 5148c2ecf20Sopenharmony_ci if (result < 0) { 5158c2ecf20Sopenharmony_ci dev_warn(dev->dev, 5168c2ecf20Sopenharmony_ci "%s: dvb_dmx_init failed (errno = %d)\n", 5178c2ecf20Sopenharmony_ci dev->name, result); 5188c2ecf20Sopenharmony_ci goto fail_dmx; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci dvb->dmxdev.filternum = 256; 5228c2ecf20Sopenharmony_ci dvb->dmxdev.demux = &dvb->demux.dmx; 5238c2ecf20Sopenharmony_ci dvb->dmxdev.capabilities = 0; 5248c2ecf20Sopenharmony_ci result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); 5258c2ecf20Sopenharmony_ci if (result < 0) { 5268c2ecf20Sopenharmony_ci dev_warn(dev->dev, 5278c2ecf20Sopenharmony_ci "%s: dvb_dmxdev_init failed (errno = %d)\n", 5288c2ecf20Sopenharmony_ci dev->name, result); 5298c2ecf20Sopenharmony_ci goto fail_dmxdev; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci dvb->fe_hw.source = DMX_FRONTEND_0; 5338c2ecf20Sopenharmony_ci result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); 5348c2ecf20Sopenharmony_ci if (result < 0) { 5358c2ecf20Sopenharmony_ci dev_warn(dev->dev, 5368c2ecf20Sopenharmony_ci "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", 5378c2ecf20Sopenharmony_ci dev->name, result); 5388c2ecf20Sopenharmony_ci goto fail_fe_hw; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci dvb->fe_mem.source = DMX_MEMORY_FE; 5428c2ecf20Sopenharmony_ci result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); 5438c2ecf20Sopenharmony_ci if (result < 0) { 5448c2ecf20Sopenharmony_ci dev_warn(dev->dev, 5458c2ecf20Sopenharmony_ci "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", 5468c2ecf20Sopenharmony_ci dev->name, result); 5478c2ecf20Sopenharmony_ci goto fail_fe_mem; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); 5518c2ecf20Sopenharmony_ci if (result < 0) { 5528c2ecf20Sopenharmony_ci dev_warn(dev->dev, 5538c2ecf20Sopenharmony_ci "%s: connect_frontend failed (errno = %d)\n", 5548c2ecf20Sopenharmony_ci dev->name, result); 5558c2ecf20Sopenharmony_ci goto fail_fe_conn; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* register network adapter */ 5598c2ecf20Sopenharmony_ci dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); 5608c2ecf20Sopenharmony_ci result = dvb_create_media_graph(&dvb->adapter, 5618c2ecf20Sopenharmony_ci dev->tuner_type == TUNER_ABSENT); 5628c2ecf20Sopenharmony_ci if (result < 0) 5638c2ecf20Sopenharmony_ci goto fail_create_graph; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cifail_create_graph: 5688c2ecf20Sopenharmony_ci dvb_net_release(&dvb->net); 5698c2ecf20Sopenharmony_cifail_fe_conn: 5708c2ecf20Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); 5718c2ecf20Sopenharmony_cifail_fe_mem: 5728c2ecf20Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); 5738c2ecf20Sopenharmony_cifail_fe_hw: 5748c2ecf20Sopenharmony_ci dvb_dmxdev_release(&dvb->dmxdev); 5758c2ecf20Sopenharmony_cifail_dmxdev: 5768c2ecf20Sopenharmony_ci dvb_dmx_release(&dvb->demux); 5778c2ecf20Sopenharmony_cifail_dmx: 5788c2ecf20Sopenharmony_ci if (dvb->frontend[1]) 5798c2ecf20Sopenharmony_ci dvb_unregister_frontend(dvb->frontend[1]); 5808c2ecf20Sopenharmony_ci dvb_unregister_frontend(dvb->frontend[0]); 5818c2ecf20Sopenharmony_cifail_frontend1: 5828c2ecf20Sopenharmony_ci if (dvb->frontend[1]) 5838c2ecf20Sopenharmony_ci dvb_frontend_detach(dvb->frontend[1]); 5848c2ecf20Sopenharmony_cifail_frontend0: 5858c2ecf20Sopenharmony_ci dvb_frontend_detach(dvb->frontend[0]); 5868c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dvb->adapter); 5878c2ecf20Sopenharmony_cifail_adapter: 5888c2ecf20Sopenharmony_ci return result; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic void unregister_dvb(struct cx231xx_dvb *dvb) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci dvb_net_release(&dvb->net); 5948c2ecf20Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); 5958c2ecf20Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); 5968c2ecf20Sopenharmony_ci dvb_dmxdev_release(&dvb->dmxdev); 5978c2ecf20Sopenharmony_ci dvb_dmx_release(&dvb->demux); 5988c2ecf20Sopenharmony_ci if (dvb->frontend[1]) 5998c2ecf20Sopenharmony_ci dvb_unregister_frontend(dvb->frontend[1]); 6008c2ecf20Sopenharmony_ci dvb_unregister_frontend(dvb->frontend[0]); 6018c2ecf20Sopenharmony_ci if (dvb->frontend[1]) 6028c2ecf20Sopenharmony_ci dvb_frontend_detach(dvb->frontend[1]); 6038c2ecf20Sopenharmony_ci dvb_frontend_detach(dvb->frontend[0]); 6048c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dvb->adapter); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* remove I2C tuner */ 6078c2ecf20Sopenharmony_ci dvb_module_release(dvb->i2c_client_tuner); 6088c2ecf20Sopenharmony_ci dvb->i2c_client_tuner = NULL; 6098c2ecf20Sopenharmony_ci /* remove I2C demod(s) */ 6108c2ecf20Sopenharmony_ci dvb_module_release(dvb->i2c_client_demod[1]); 6118c2ecf20Sopenharmony_ci dvb->i2c_client_demod[1] = NULL; 6128c2ecf20Sopenharmony_ci dvb_module_release(dvb->i2c_client_demod[0]); 6138c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = NULL; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic int dvb_init(struct cx231xx *dev) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci int result; 6198c2ecf20Sopenharmony_ci struct cx231xx_dvb *dvb; 6208c2ecf20Sopenharmony_ci struct i2c_adapter *tuner_i2c; 6218c2ecf20Sopenharmony_ci struct i2c_adapter *demod_i2c; 6228c2ecf20Sopenharmony_ci struct i2c_client *client; 6238c2ecf20Sopenharmony_ci struct i2c_adapter *adapter; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!dev->board.has_dvb) { 6268c2ecf20Sopenharmony_ci /* This device does not support the extension */ 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (dvb == NULL) { 6338c2ecf20Sopenharmony_ci dev_info(dev->dev, 6348c2ecf20Sopenharmony_ci "cx231xx_dvb: memory allocation failed\n"); 6358c2ecf20Sopenharmony_ci return -ENOMEM; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci dev->dvb = dvb; 6388c2ecf20Sopenharmony_ci dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq; 6398c2ecf20Sopenharmony_ci dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci tuner_i2c = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master); 6428c2ecf20Sopenharmony_ci demod_i2c = cx231xx_get_i2c_adap(dev, dev->board.demod_i2c_master); 6438c2ecf20Sopenharmony_ci mutex_lock(&dev->lock); 6448c2ecf20Sopenharmony_ci cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); 6458c2ecf20Sopenharmony_ci cx231xx_demod_reset(dev); 6468c2ecf20Sopenharmony_ci /* init frontend */ 6478c2ecf20Sopenharmony_ci switch (dev->model) { 6488c2ecf20Sopenharmony_ci case CX231XX_BOARD_CNXT_CARRAERA: 6498c2ecf20Sopenharmony_ci case CX231XX_BOARD_CNXT_RDE_250: 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci dev->dvb->frontend[0] = dvb_attach(s5h1432_attach, 6528c2ecf20Sopenharmony_ci &dvico_s5h1432_config, 6538c2ecf20Sopenharmony_ci demod_i2c); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (!dev->dvb->frontend[0]) { 6568c2ecf20Sopenharmony_ci dev_err(dev->dev, 6578c2ecf20Sopenharmony_ci "Failed to attach s5h1432 front end\n"); 6588c2ecf20Sopenharmony_ci result = -EINVAL; 6598c2ecf20Sopenharmony_ci goto out_free; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 6638c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0], 6668c2ecf20Sopenharmony_ci tuner_i2c, 6678c2ecf20Sopenharmony_ci &cnxt_rde250_tunerconfig)) { 6688c2ecf20Sopenharmony_ci result = -EINVAL; 6698c2ecf20Sopenharmony_ci goto out_free; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci case CX231XX_BOARD_CNXT_SHELBY: 6748c2ecf20Sopenharmony_ci case CX231XX_BOARD_CNXT_RDU_250: 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci dev->dvb->frontend[0] = dvb_attach(s5h1411_attach, 6778c2ecf20Sopenharmony_ci &xc5000_s5h1411_config, 6788c2ecf20Sopenharmony_ci demod_i2c); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (!dev->dvb->frontend[0]) { 6818c2ecf20Sopenharmony_ci dev_err(dev->dev, 6828c2ecf20Sopenharmony_ci "Failed to attach s5h1411 front end\n"); 6838c2ecf20Sopenharmony_ci result = -EINVAL; 6848c2ecf20Sopenharmony_ci goto out_free; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 6888c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0], 6918c2ecf20Sopenharmony_ci tuner_i2c, 6928c2ecf20Sopenharmony_ci &cnxt_rdu250_tunerconfig)) { 6938c2ecf20Sopenharmony_ci result = -EINVAL; 6948c2ecf20Sopenharmony_ci goto out_free; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci case CX231XX_BOARD_CNXT_RDE_253S: 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci dev->dvb->frontend[0] = dvb_attach(s5h1432_attach, 7008c2ecf20Sopenharmony_ci &dvico_s5h1432_config, 7018c2ecf20Sopenharmony_ci demod_i2c); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (!dev->dvb->frontend[0]) { 7048c2ecf20Sopenharmony_ci dev_err(dev->dev, 7058c2ecf20Sopenharmony_ci "Failed to attach s5h1432 front end\n"); 7068c2ecf20Sopenharmony_ci result = -EINVAL; 7078c2ecf20Sopenharmony_ci goto out_free; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 7118c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0], 7148c2ecf20Sopenharmony_ci dev->board.tuner_addr, tuner_i2c, 7158c2ecf20Sopenharmony_ci &cnxt_rde253s_tunerconfig)) { 7168c2ecf20Sopenharmony_ci result = -EINVAL; 7178c2ecf20Sopenharmony_ci goto out_free; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci break; 7208c2ecf20Sopenharmony_ci case CX231XX_BOARD_CNXT_RDU_253S: 7218c2ecf20Sopenharmony_ci case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID: 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci dev->dvb->frontend[0] = dvb_attach(s5h1411_attach, 7248c2ecf20Sopenharmony_ci &tda18271_s5h1411_config, 7258c2ecf20Sopenharmony_ci demod_i2c); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (!dev->dvb->frontend[0]) { 7288c2ecf20Sopenharmony_ci dev_err(dev->dev, 7298c2ecf20Sopenharmony_ci "Failed to attach s5h1411 front end\n"); 7308c2ecf20Sopenharmony_ci result = -EINVAL; 7318c2ecf20Sopenharmony_ci goto out_free; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 7358c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0], 7388c2ecf20Sopenharmony_ci dev->board.tuner_addr, tuner_i2c, 7398c2ecf20Sopenharmony_ci &cnxt_rde253s_tunerconfig)) { 7408c2ecf20Sopenharmony_ci result = -EINVAL; 7418c2ecf20Sopenharmony_ci goto out_free; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci break; 7448c2ecf20Sopenharmony_ci case CX231XX_BOARD_HAUPPAUGE_EXETER: 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci dev_info(dev->dev, 7478c2ecf20Sopenharmony_ci "%s: looking for tuner / demod on i2c bus: %d\n", 7488c2ecf20Sopenharmony_ci __func__, i2c_adapter_id(tuner_i2c)); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach, 7518c2ecf20Sopenharmony_ci &hcw_lgdt3305_config, 7528c2ecf20Sopenharmony_ci demod_i2c); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (!dev->dvb->frontend[0]) { 7558c2ecf20Sopenharmony_ci dev_err(dev->dev, 7568c2ecf20Sopenharmony_ci "Failed to attach LG3305 front end\n"); 7578c2ecf20Sopenharmony_ci result = -EINVAL; 7588c2ecf20Sopenharmony_ci goto out_free; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 7628c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci dvb_attach(tda18271_attach, dev->dvb->frontend[0], 7658c2ecf20Sopenharmony_ci dev->board.tuner_addr, tuner_i2c, 7668c2ecf20Sopenharmony_ci &hcw_tda18271_config); 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx: 7708c2ecf20Sopenharmony_ci { 7718c2ecf20Sopenharmony_ci struct si2165_platform_data si2165_pdata = {}; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* attach demod */ 7748c2ecf20Sopenharmony_ci si2165_pdata.fe = &dev->dvb->frontend[0]; 7758c2ecf20Sopenharmony_ci si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL; 7768c2ecf20Sopenharmony_ci si2165_pdata.ref_freq_hz = 16000000; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 7798c2ecf20Sopenharmony_ci client = dvb_module_probe("si2165", NULL, demod_i2c, 7808c2ecf20Sopenharmony_ci dev->board.demod_addr, 7818c2ecf20Sopenharmony_ci &si2165_pdata); 7828c2ecf20Sopenharmony_ci if (!client) { 7838c2ecf20Sopenharmony_ci result = -ENODEV; 7848c2ecf20Sopenharmony_ci goto out_free; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = client; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 7918c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci dvb_attach(tda18271_attach, dev->dvb->frontend[0], 7948c2ecf20Sopenharmony_ci dev->board.tuner_addr, tuner_i2c, 7958c2ecf20Sopenharmony_ci &hcw_tda18271_config); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci dev->cx231xx_reset_analog_tuner = NULL; 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: 8018c2ecf20Sopenharmony_ci { 8028c2ecf20Sopenharmony_ci struct si2165_platform_data si2165_pdata = {}; 8038c2ecf20Sopenharmony_ci struct si2157_config si2157_config = {}; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* attach demod */ 8068c2ecf20Sopenharmony_ci si2165_pdata.fe = &dev->dvb->frontend[0]; 8078c2ecf20Sopenharmony_ci si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT; 8088c2ecf20Sopenharmony_ci si2165_pdata.ref_freq_hz = 24000000; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 8118c2ecf20Sopenharmony_ci client = dvb_module_probe("si2165", NULL, demod_i2c, 8128c2ecf20Sopenharmony_ci dev->board.demod_addr, 8138c2ecf20Sopenharmony_ci &si2165_pdata); 8148c2ecf20Sopenharmony_ci if (!client) { 8158c2ecf20Sopenharmony_ci result = -ENODEV; 8168c2ecf20Sopenharmony_ci goto out_free; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = client; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 8238c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* attach tuner */ 8268c2ecf20Sopenharmony_ci si2157_config.fe = dev->dvb->frontend[0]; 8278c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB 8288c2ecf20Sopenharmony_ci si2157_config.mdev = dev->media_dev; 8298c2ecf20Sopenharmony_ci#endif 8308c2ecf20Sopenharmony_ci si2157_config.if_port = 1; 8318c2ecf20Sopenharmony_ci si2157_config.inversion = true; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 8348c2ecf20Sopenharmony_ci client = dvb_module_probe("si2157", NULL, tuner_i2c, 8358c2ecf20Sopenharmony_ci dev->board.tuner_addr, 8368c2ecf20Sopenharmony_ci &si2157_config); 8378c2ecf20Sopenharmony_ci if (!client) { 8388c2ecf20Sopenharmony_ci result = -ENODEV; 8398c2ecf20Sopenharmony_ci goto out_free; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci dev->cx231xx_reset_analog_tuner = NULL; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci dev->dvb->i2c_client_tuner = client; 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci case CX231XX_BOARD_HAUPPAUGE_955Q: 8478c2ecf20Sopenharmony_ci { 8488c2ecf20Sopenharmony_ci struct si2157_config si2157_config = {}; 8498c2ecf20Sopenharmony_ci struct lgdt3306a_config lgdt3306a_config = {}; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci lgdt3306a_config = hauppauge_955q_lgdt3306a_config; 8528c2ecf20Sopenharmony_ci lgdt3306a_config.fe = &dev->dvb->frontend[0]; 8538c2ecf20Sopenharmony_ci lgdt3306a_config.i2c_adapter = &adapter; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 8568c2ecf20Sopenharmony_ci client = dvb_module_probe("lgdt3306a", NULL, demod_i2c, 8578c2ecf20Sopenharmony_ci dev->board.demod_addr, 8588c2ecf20Sopenharmony_ci &lgdt3306a_config); 8598c2ecf20Sopenharmony_ci if (!client) { 8608c2ecf20Sopenharmony_ci result = -ENODEV; 8618c2ecf20Sopenharmony_ci goto out_free; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = client; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 8688c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* attach tuner */ 8718c2ecf20Sopenharmony_ci si2157_config.fe = dev->dvb->frontend[0]; 8728c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB 8738c2ecf20Sopenharmony_ci si2157_config.mdev = dev->media_dev; 8748c2ecf20Sopenharmony_ci#endif 8758c2ecf20Sopenharmony_ci si2157_config.if_port = 1; 8768c2ecf20Sopenharmony_ci si2157_config.inversion = true; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 8798c2ecf20Sopenharmony_ci client = dvb_module_probe("si2157", NULL, tuner_i2c, 8808c2ecf20Sopenharmony_ci dev->board.tuner_addr, 8818c2ecf20Sopenharmony_ci &si2157_config); 8828c2ecf20Sopenharmony_ci if (!client) { 8838c2ecf20Sopenharmony_ci result = -ENODEV; 8848c2ecf20Sopenharmony_ci goto out_free; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci dev->cx231xx_reset_analog_tuner = NULL; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci dev->dvb->i2c_client_tuner = client; 8898c2ecf20Sopenharmony_ci break; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: 8928c2ecf20Sopenharmony_ci case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID: 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci dev_info(dev->dev, 8958c2ecf20Sopenharmony_ci "%s: looking for demod on i2c bus: %d\n", 8968c2ecf20Sopenharmony_ci __func__, i2c_adapter_id(tuner_i2c)); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach, 8998c2ecf20Sopenharmony_ci &pv_mb86a20s_config, 9008c2ecf20Sopenharmony_ci demod_i2c); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (!dev->dvb->frontend[0]) { 9038c2ecf20Sopenharmony_ci dev_err(dev->dev, 9048c2ecf20Sopenharmony_ci "Failed to attach mb86a20s demod\n"); 9058c2ecf20Sopenharmony_ci result = -EINVAL; 9068c2ecf20Sopenharmony_ci goto out_free; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 9108c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci dvb_attach(tda18271_attach, dev->dvb->frontend[0], 9138c2ecf20Sopenharmony_ci dev->board.tuner_addr, tuner_i2c, 9148c2ecf20Sopenharmony_ci &pv_tda18271_config); 9158c2ecf20Sopenharmony_ci break; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD: 9188c2ecf20Sopenharmony_ci { 9198c2ecf20Sopenharmony_ci struct si2157_config si2157_config = {}; 9208c2ecf20Sopenharmony_ci struct si2168_config si2168_config = {}; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* attach demodulator chip */ 9238c2ecf20Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */ 9248c2ecf20Sopenharmony_ci si2168_config.fe = &dev->dvb->frontend[0]; 9258c2ecf20Sopenharmony_ci si2168_config.i2c_adapter = &adapter; 9268c2ecf20Sopenharmony_ci si2168_config.ts_clock_inv = true; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 9298c2ecf20Sopenharmony_ci client = dvb_module_probe("si2168", NULL, demod_i2c, 9308c2ecf20Sopenharmony_ci dev->board.demod_addr, 9318c2ecf20Sopenharmony_ci &si2168_config); 9328c2ecf20Sopenharmony_ci if (!client) { 9338c2ecf20Sopenharmony_ci result = -ENODEV; 9348c2ecf20Sopenharmony_ci goto out_free; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = client; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* attach tuner chip */ 9398c2ecf20Sopenharmony_ci si2157_config.fe = dev->dvb->frontend[0]; 9408c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB 9418c2ecf20Sopenharmony_ci si2157_config.mdev = dev->media_dev; 9428c2ecf20Sopenharmony_ci#endif 9438c2ecf20Sopenharmony_ci si2157_config.if_port = 1; 9448c2ecf20Sopenharmony_ci si2157_config.inversion = false; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 9478c2ecf20Sopenharmony_ci client = dvb_module_probe("si2157", NULL, tuner_i2c, 9488c2ecf20Sopenharmony_ci dev->board.tuner_addr, 9498c2ecf20Sopenharmony_ci &si2157_config); 9508c2ecf20Sopenharmony_ci if (!client) { 9518c2ecf20Sopenharmony_ci result = -ENODEV; 9528c2ecf20Sopenharmony_ci goto out_free; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci dev->cx231xx_reset_analog_tuner = NULL; 9558c2ecf20Sopenharmony_ci dev->dvb->i2c_client_tuner = client; 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci case CX231XX_BOARD_ASTROMETA_T2HYBRID: 9598c2ecf20Sopenharmony_ci { 9608c2ecf20Sopenharmony_ci struct mn88473_config mn88473_config = {}; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* attach demodulator chip */ 9638c2ecf20Sopenharmony_ci mn88473_config.i2c_wr_max = 16; 9648c2ecf20Sopenharmony_ci mn88473_config.xtal = 25000000; 9658c2ecf20Sopenharmony_ci mn88473_config.fe = &dev->dvb->frontend[0]; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 9688c2ecf20Sopenharmony_ci client = dvb_module_probe("mn88473", NULL, demod_i2c, 9698c2ecf20Sopenharmony_ci dev->board.demod_addr, 9708c2ecf20Sopenharmony_ci &mn88473_config); 9718c2ecf20Sopenharmony_ci if (!client) { 9728c2ecf20Sopenharmony_ci result = -ENODEV; 9738c2ecf20Sopenharmony_ci goto out_free; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = client; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 9788c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* attach tuner chip */ 9818c2ecf20Sopenharmony_ci dvb_attach(r820t_attach, dev->dvb->frontend[0], 9828c2ecf20Sopenharmony_ci tuner_i2c, 9838c2ecf20Sopenharmony_ci &astrometa_t2hybrid_r820t_config); 9848c2ecf20Sopenharmony_ci break; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci case CX231XX_BOARD_HAUPPAUGE_935C: 9878c2ecf20Sopenharmony_ci { 9888c2ecf20Sopenharmony_ci struct si2157_config si2157_config = {}; 9898c2ecf20Sopenharmony_ci struct si2168_config si2168_config = {}; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* attach demodulator chip */ 9928c2ecf20Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_SERIAL; 9938c2ecf20Sopenharmony_ci si2168_config.fe = &dev->dvb->frontend[0]; 9948c2ecf20Sopenharmony_ci si2168_config.i2c_adapter = &adapter; 9958c2ecf20Sopenharmony_ci si2168_config.ts_clock_inv = true; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 9988c2ecf20Sopenharmony_ci client = dvb_module_probe("si2168", NULL, demod_i2c, 9998c2ecf20Sopenharmony_ci dev->board.demod_addr, 10008c2ecf20Sopenharmony_ci &si2168_config); 10018c2ecf20Sopenharmony_ci if (!client) { 10028c2ecf20Sopenharmony_ci result = -ENODEV; 10038c2ecf20Sopenharmony_ci goto out_free; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = client; 10068c2ecf20Sopenharmony_ci dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 10098c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* attach tuner */ 10128c2ecf20Sopenharmony_ci si2157_config.fe = dev->dvb->frontend[0]; 10138c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB 10148c2ecf20Sopenharmony_ci si2157_config.mdev = dev->media_dev; 10158c2ecf20Sopenharmony_ci#endif 10168c2ecf20Sopenharmony_ci si2157_config.if_port = 1; 10178c2ecf20Sopenharmony_ci si2157_config.inversion = true; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 10208c2ecf20Sopenharmony_ci client = dvb_module_probe("si2157", NULL, tuner_i2c, 10218c2ecf20Sopenharmony_ci dev->board.tuner_addr, 10228c2ecf20Sopenharmony_ci &si2157_config); 10238c2ecf20Sopenharmony_ci if (!client) { 10248c2ecf20Sopenharmony_ci result = -ENODEV; 10258c2ecf20Sopenharmony_ci goto out_free; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci dev->cx231xx_reset_analog_tuner = NULL; 10288c2ecf20Sopenharmony_ci dev->dvb->i2c_client_tuner = client; 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci case CX231XX_BOARD_HAUPPAUGE_975: 10328c2ecf20Sopenharmony_ci { 10338c2ecf20Sopenharmony_ci struct i2c_adapter *adapter2; 10348c2ecf20Sopenharmony_ci struct si2157_config si2157_config = {}; 10358c2ecf20Sopenharmony_ci struct lgdt3306a_config lgdt3306a_config = {}; 10368c2ecf20Sopenharmony_ci struct si2168_config si2168_config = {}; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* attach first demodulator chip */ 10398c2ecf20Sopenharmony_ci lgdt3306a_config = hauppauge_955q_lgdt3306a_config; 10408c2ecf20Sopenharmony_ci lgdt3306a_config.fe = &dev->dvb->frontend[0]; 10418c2ecf20Sopenharmony_ci lgdt3306a_config.i2c_adapter = &adapter; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 10448c2ecf20Sopenharmony_ci client = dvb_module_probe("lgdt3306a", NULL, demod_i2c, 10458c2ecf20Sopenharmony_ci dev->board.demod_addr, 10468c2ecf20Sopenharmony_ci &lgdt3306a_config); 10478c2ecf20Sopenharmony_ci if (!client) { 10488c2ecf20Sopenharmony_ci result = -ENODEV; 10498c2ecf20Sopenharmony_ci goto out_free; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = client; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* attach second demodulator chip */ 10548c2ecf20Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_SERIAL; 10558c2ecf20Sopenharmony_ci si2168_config.fe = &dev->dvb->frontend[1]; 10568c2ecf20Sopenharmony_ci si2168_config.i2c_adapter = &adapter2; 10578c2ecf20Sopenharmony_ci si2168_config.ts_clock_inv = true; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 10608c2ecf20Sopenharmony_ci client = dvb_module_probe("si2168", NULL, adapter, 10618c2ecf20Sopenharmony_ci dev->board.demod_addr2, 10628c2ecf20Sopenharmony_ci &si2168_config); 10638c2ecf20Sopenharmony_ci if (!client) { 10648c2ecf20Sopenharmony_ci result = -ENODEV; 10658c2ecf20Sopenharmony_ci goto out_free; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci dvb->i2c_client_demod[1] = client; 10688c2ecf20Sopenharmony_ci dvb->frontend[1]->id = 1; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci /* define general-purpose callback pointer */ 10718c2ecf20Sopenharmony_ci dvb->frontend[0]->callback = cx231xx_tuner_callback; 10728c2ecf20Sopenharmony_ci dvb->frontend[1]->callback = cx231xx_tuner_callback; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* attach tuner */ 10758c2ecf20Sopenharmony_ci si2157_config.fe = dev->dvb->frontend[0]; 10768c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB 10778c2ecf20Sopenharmony_ci si2157_config.mdev = dev->media_dev; 10788c2ecf20Sopenharmony_ci#endif 10798c2ecf20Sopenharmony_ci si2157_config.if_port = 1; 10808c2ecf20Sopenharmony_ci si2157_config.inversion = true; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* perform probe/init/attach */ 10838c2ecf20Sopenharmony_ci client = dvb_module_probe("si2157", NULL, adapter, 10848c2ecf20Sopenharmony_ci dev->board.tuner_addr, 10858c2ecf20Sopenharmony_ci &si2157_config); 10868c2ecf20Sopenharmony_ci if (!client) { 10878c2ecf20Sopenharmony_ci result = -ENODEV; 10888c2ecf20Sopenharmony_ci goto out_free; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci dev->cx231xx_reset_analog_tuner = NULL; 10918c2ecf20Sopenharmony_ci dvb->i2c_client_tuner = client; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci dvb->frontend[1]->tuner_priv = dvb->frontend[0]->tuner_priv; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci memcpy(&dvb->frontend[1]->ops.tuner_ops, 10968c2ecf20Sopenharmony_ci &dvb->frontend[0]->ops.tuner_ops, 10978c2ecf20Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 10988c2ecf20Sopenharmony_ci break; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci default: 11018c2ecf20Sopenharmony_ci dev_err(dev->dev, 11028c2ecf20Sopenharmony_ci "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", 11038c2ecf20Sopenharmony_ci dev->name); 11048c2ecf20Sopenharmony_ci break; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci if (!dvb->frontend[0]) { 11078c2ecf20Sopenharmony_ci dev_err(dev->dev, 11088c2ecf20Sopenharmony_ci "%s/2: frontend initialization failed\n", dev->name); 11098c2ecf20Sopenharmony_ci result = -EINVAL; 11108c2ecf20Sopenharmony_ci goto out_free; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* register everything */ 11148c2ecf20Sopenharmony_ci result = register_dvb(dvb, THIS_MODULE, dev, dev->dev); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (result < 0) 11178c2ecf20Sopenharmony_ci goto out_free; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci dev_info(dev->dev, "Successfully loaded cx231xx-dvb\n"); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ciret: 11238c2ecf20Sopenharmony_ci cx231xx_set_mode(dev, CX231XX_SUSPEND); 11248c2ecf20Sopenharmony_ci mutex_unlock(&dev->lock); 11258c2ecf20Sopenharmony_ci return result; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ciout_free: 11288c2ecf20Sopenharmony_ci /* remove I2C tuner */ 11298c2ecf20Sopenharmony_ci dvb_module_release(dvb->i2c_client_tuner); 11308c2ecf20Sopenharmony_ci dvb->i2c_client_tuner = NULL; 11318c2ecf20Sopenharmony_ci /* remove I2C demod(s) */ 11328c2ecf20Sopenharmony_ci dvb_module_release(dvb->i2c_client_demod[1]); 11338c2ecf20Sopenharmony_ci dvb->i2c_client_demod[1] = NULL; 11348c2ecf20Sopenharmony_ci dvb_module_release(dvb->i2c_client_demod[0]); 11358c2ecf20Sopenharmony_ci dvb->i2c_client_demod[0] = NULL; 11368c2ecf20Sopenharmony_ci kfree(dvb); 11378c2ecf20Sopenharmony_ci dev->dvb = NULL; 11388c2ecf20Sopenharmony_ci goto ret; 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic int dvb_fini(struct cx231xx *dev) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci if (!dev->board.has_dvb) { 11448c2ecf20Sopenharmony_ci /* This device does not support the extension */ 11458c2ecf20Sopenharmony_ci return 0; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (dev->dvb) { 11498c2ecf20Sopenharmony_ci unregister_dvb(dev->dvb); 11508c2ecf20Sopenharmony_ci kfree(dev->dvb); 11518c2ecf20Sopenharmony_ci dev->dvb = NULL; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return 0; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic struct cx231xx_ops dvb_ops = { 11588c2ecf20Sopenharmony_ci .id = CX231XX_DVB, 11598c2ecf20Sopenharmony_ci .name = "Cx231xx dvb Extension", 11608c2ecf20Sopenharmony_ci .init = dvb_init, 11618c2ecf20Sopenharmony_ci .fini = dvb_fini, 11628c2ecf20Sopenharmony_ci}; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic int __init cx231xx_dvb_register(void) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci return cx231xx_register_extension(&dvb_ops); 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_cistatic void __exit cx231xx_dvb_unregister(void) 11708c2ecf20Sopenharmony_ci{ 11718c2ecf20Sopenharmony_ci cx231xx_unregister_extension(&dvb_ops); 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_cimodule_init(cx231xx_dvb_register); 11758c2ecf20Sopenharmony_cimodule_exit(cx231xx_dvb_unregister); 1176