18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2007 Xceive Corporation 68c2ecf20Sopenharmony_ci * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> 78c2ecf20Sopenharmony_ci * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> 88c2ecf20Sopenharmony_ci * Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it> 98c2ecf20Sopenharmony_ci * Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 148c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h> 178c2ecf20Sopenharmony_ci#include <linux/i2c.h> 188c2ecf20Sopenharmony_ci#include <linux/mutex.h> 198c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "xc4000.h" 248c2ecf20Sopenharmony_ci#include "tuner-i2c.h" 258c2ecf20Sopenharmony_ci#include "tuner-xc2028-types.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int debug; 288c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int no_poweroff; 328c2ecf20Sopenharmony_cimodule_param(no_poweroff, int, 0644); 338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, 0 (default): use device-specific default mode)."); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int audio_std; 368c2ecf20Sopenharmony_cimodule_param(audio_std, int, 0644); 378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly needs to know what audio standard is needed for some video standards with audio A2 or NICAM. The valid settings are a sum of:\n" 388c2ecf20Sopenharmony_ci " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" 398c2ecf20Sopenharmony_ci " 2: use A2 instead of NICAM or BTSC\n" 408c2ecf20Sopenharmony_ci " 4: use SECAM/K3 instead of K1\n" 418c2ecf20Sopenharmony_ci " 8: use PAL-D/K audio for SECAM-D/K\n" 428c2ecf20Sopenharmony_ci "16: use FM radio input 1 instead of input 2\n" 438c2ecf20Sopenharmony_ci "32: use mono audio (the lower three bits are ignored)"); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic char firmware_name[30]; 468c2ecf20Sopenharmony_cimodule_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); 478c2ecf20Sopenharmony_ciMODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the default firmware name."); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(xc4000_list_mutex); 508c2ecf20Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...) if (debug >= level) \ 538c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* struct for storing firmware table */ 568c2ecf20Sopenharmony_cistruct firmware_description { 578c2ecf20Sopenharmony_ci unsigned int type; 588c2ecf20Sopenharmony_ci v4l2_std_id id; 598c2ecf20Sopenharmony_ci __u16 int_freq; 608c2ecf20Sopenharmony_ci unsigned char *ptr; 618c2ecf20Sopenharmony_ci unsigned int size; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct firmware_properties { 658c2ecf20Sopenharmony_ci unsigned int type; 668c2ecf20Sopenharmony_ci v4l2_std_id id; 678c2ecf20Sopenharmony_ci v4l2_std_id std_req; 688c2ecf20Sopenharmony_ci __u16 int_freq; 698c2ecf20Sopenharmony_ci unsigned int scode_table; 708c2ecf20Sopenharmony_ci int scode_nr; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistruct xc4000_priv { 748c2ecf20Sopenharmony_ci struct tuner_i2c_props i2c_props; 758c2ecf20Sopenharmony_ci struct list_head hybrid_tuner_instance_list; 768c2ecf20Sopenharmony_ci struct firmware_description *firm; 778c2ecf20Sopenharmony_ci int firm_size; 788c2ecf20Sopenharmony_ci u32 if_khz; 798c2ecf20Sopenharmony_ci u32 freq_hz, freq_offset; 808c2ecf20Sopenharmony_ci u32 bandwidth; 818c2ecf20Sopenharmony_ci u8 video_standard; 828c2ecf20Sopenharmony_ci u8 rf_mode; 838c2ecf20Sopenharmony_ci u8 default_pm; 848c2ecf20Sopenharmony_ci u8 dvb_amplitude; 858c2ecf20Sopenharmony_ci u8 set_smoothedcvbs; 868c2ecf20Sopenharmony_ci u8 ignore_i2c_write_errors; 878c2ecf20Sopenharmony_ci __u16 firm_version; 888c2ecf20Sopenharmony_ci struct firmware_properties cur_fw; 898c2ecf20Sopenharmony_ci __u16 hwmodel; 908c2ecf20Sopenharmony_ci __u16 hwvers; 918c2ecf20Sopenharmony_ci struct mutex lock; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define XC4000_AUDIO_STD_B 1 958c2ecf20Sopenharmony_ci#define XC4000_AUDIO_STD_A2 2 968c2ecf20Sopenharmony_ci#define XC4000_AUDIO_STD_K3 4 978c2ecf20Sopenharmony_ci#define XC4000_AUDIO_STD_L 8 988c2ecf20Sopenharmony_ci#define XC4000_AUDIO_STD_INPUT1 16 998c2ecf20Sopenharmony_ci#define XC4000_AUDIO_STD_MONO 32 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw" 1028c2ecf20Sopenharmony_ci#define XC4000_DEFAULT_FIRMWARE_NEW "dvb-fe-xc4000-1.4.1.fw" 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Misc Defines */ 1058c2ecf20Sopenharmony_ci#define MAX_TV_STANDARD 24 1068c2ecf20Sopenharmony_ci#define XC_MAX_I2C_WRITE_LENGTH 64 1078c2ecf20Sopenharmony_ci#define XC_POWERED_DOWN 0x80000000U 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* Signal Types */ 1108c2ecf20Sopenharmony_ci#define XC_RF_MODE_AIR 0 1118c2ecf20Sopenharmony_ci#define XC_RF_MODE_CABLE 1 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* Product id */ 1148c2ecf20Sopenharmony_ci#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 1158c2ecf20Sopenharmony_ci#define XC_PRODUCT_ID_XC4000 0x0FA0 1168c2ecf20Sopenharmony_ci#define XC_PRODUCT_ID_XC4100 0x1004 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Registers (Write-only) */ 1198c2ecf20Sopenharmony_ci#define XREG_INIT 0x00 1208c2ecf20Sopenharmony_ci#define XREG_VIDEO_MODE 0x01 1218c2ecf20Sopenharmony_ci#define XREG_AUDIO_MODE 0x02 1228c2ecf20Sopenharmony_ci#define XREG_RF_FREQ 0x03 1238c2ecf20Sopenharmony_ci#define XREG_D_CODE 0x04 1248c2ecf20Sopenharmony_ci#define XREG_DIRECTSITTING_MODE 0x05 1258c2ecf20Sopenharmony_ci#define XREG_SEEK_MODE 0x06 1268c2ecf20Sopenharmony_ci#define XREG_POWER_DOWN 0x08 1278c2ecf20Sopenharmony_ci#define XREG_SIGNALSOURCE 0x0A 1288c2ecf20Sopenharmony_ci#define XREG_SMOOTHEDCVBS 0x0E 1298c2ecf20Sopenharmony_ci#define XREG_AMPLITUDE 0x10 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* Registers (Read-only) */ 1328c2ecf20Sopenharmony_ci#define XREG_ADC_ENV 0x00 1338c2ecf20Sopenharmony_ci#define XREG_QUALITY 0x01 1348c2ecf20Sopenharmony_ci#define XREG_FRAME_LINES 0x02 1358c2ecf20Sopenharmony_ci#define XREG_HSYNC_FREQ 0x03 1368c2ecf20Sopenharmony_ci#define XREG_LOCK 0x04 1378c2ecf20Sopenharmony_ci#define XREG_FREQ_ERROR 0x05 1388c2ecf20Sopenharmony_ci#define XREG_SNR 0x06 1398c2ecf20Sopenharmony_ci#define XREG_VERSION 0x07 1408c2ecf20Sopenharmony_ci#define XREG_PRODUCT_ID 0x08 1418c2ecf20Sopenharmony_ci#define XREG_SIGNAL_LEVEL 0x0A 1428c2ecf20Sopenharmony_ci#define XREG_NOISE_LEVEL 0x0B 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* 1458c2ecf20Sopenharmony_ci Basic firmware description. This will remain with 1468c2ecf20Sopenharmony_ci the driver for documentation purposes. 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci This represents an I2C firmware file encoded as a 1498c2ecf20Sopenharmony_ci string of unsigned char. Format is as follows: 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB 1528c2ecf20Sopenharmony_ci char[1 ]=len0_LSB -> length of first write transaction 1538c2ecf20Sopenharmony_ci char[2 ]=data0 -> first byte to be sent 1548c2ecf20Sopenharmony_ci char[3 ]=data1 1558c2ecf20Sopenharmony_ci char[4 ]=data2 1568c2ecf20Sopenharmony_ci char[ ]=... 1578c2ecf20Sopenharmony_ci char[M ]=dataN -> last byte to be sent 1588c2ecf20Sopenharmony_ci char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB 1598c2ecf20Sopenharmony_ci char[M+2]=len1_LSB -> length of second write transaction 1608c2ecf20Sopenharmony_ci char[M+3]=data0 1618c2ecf20Sopenharmony_ci char[M+4]=data1 1628c2ecf20Sopenharmony_ci ... 1638c2ecf20Sopenharmony_ci etc. 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci The [len] value should be interpreted as follows: 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci len= len_MSB _ len_LSB 1688c2ecf20Sopenharmony_ci len=1111_1111_1111_1111 : End of I2C_SEQUENCE 1698c2ecf20Sopenharmony_ci len=0000_0000_0000_0000 : Reset command: Do hardware reset 1708c2ecf20Sopenharmony_ci len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) 1718c2ecf20Sopenharmony_ci len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci For the RESET and WAIT commands, the two following bytes will contain 1748c2ecf20Sopenharmony_ci immediately the length of the following transaction. 1758c2ecf20Sopenharmony_ci*/ 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistruct XC_TV_STANDARD { 1788c2ecf20Sopenharmony_ci const char *Name; 1798c2ecf20Sopenharmony_ci u16 audio_mode; 1808c2ecf20Sopenharmony_ci u16 video_mode; 1818c2ecf20Sopenharmony_ci u16 int_freq; 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* Tuner standards */ 1858c2ecf20Sopenharmony_ci#define XC4000_MN_NTSC_PAL_BTSC 0 1868c2ecf20Sopenharmony_ci#define XC4000_MN_NTSC_PAL_A2 1 1878c2ecf20Sopenharmony_ci#define XC4000_MN_NTSC_PAL_EIAJ 2 1888c2ecf20Sopenharmony_ci#define XC4000_MN_NTSC_PAL_Mono 3 1898c2ecf20Sopenharmony_ci#define XC4000_BG_PAL_A2 4 1908c2ecf20Sopenharmony_ci#define XC4000_BG_PAL_NICAM 5 1918c2ecf20Sopenharmony_ci#define XC4000_BG_PAL_MONO 6 1928c2ecf20Sopenharmony_ci#define XC4000_I_PAL_NICAM 7 1938c2ecf20Sopenharmony_ci#define XC4000_I_PAL_NICAM_MONO 8 1948c2ecf20Sopenharmony_ci#define XC4000_DK_PAL_A2 9 1958c2ecf20Sopenharmony_ci#define XC4000_DK_PAL_NICAM 10 1968c2ecf20Sopenharmony_ci#define XC4000_DK_PAL_MONO 11 1978c2ecf20Sopenharmony_ci#define XC4000_DK_SECAM_A2DK1 12 1988c2ecf20Sopenharmony_ci#define XC4000_DK_SECAM_A2LDK3 13 1998c2ecf20Sopenharmony_ci#define XC4000_DK_SECAM_A2MONO 14 2008c2ecf20Sopenharmony_ci#define XC4000_DK_SECAM_NICAM 15 2018c2ecf20Sopenharmony_ci#define XC4000_L_SECAM_NICAM 16 2028c2ecf20Sopenharmony_ci#define XC4000_LC_SECAM_NICAM 17 2038c2ecf20Sopenharmony_ci#define XC4000_DTV6 18 2048c2ecf20Sopenharmony_ci#define XC4000_DTV8 19 2058c2ecf20Sopenharmony_ci#define XC4000_DTV7_8 20 2068c2ecf20Sopenharmony_ci#define XC4000_DTV7 21 2078c2ecf20Sopenharmony_ci#define XC4000_FM_Radio_INPUT2 22 2088c2ecf20Sopenharmony_ci#define XC4000_FM_Radio_INPUT1 23 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = { 2118c2ecf20Sopenharmony_ci {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500}, 2128c2ecf20Sopenharmony_ci {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600}, 2138c2ecf20Sopenharmony_ci {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500}, 2148c2ecf20Sopenharmony_ci {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500}, 2158c2ecf20Sopenharmony_ci {"B/G-PAL-A2", 0x0000, 0x8159, 5640}, 2168c2ecf20Sopenharmony_ci {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740}, 2178c2ecf20Sopenharmony_ci {"B/G-PAL-MONO", 0x0078, 0x8159, 5500}, 2188c2ecf20Sopenharmony_ci {"I-PAL-NICAM", 0x0080, 0x8049, 6240}, 2198c2ecf20Sopenharmony_ci {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000}, 2208c2ecf20Sopenharmony_ci {"D/K-PAL-A2", 0x0000, 0x8049, 6380}, 2218c2ecf20Sopenharmony_ci {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200}, 2228c2ecf20Sopenharmony_ci {"D/K-PAL-MONO", 0x0078, 0x8049, 6500}, 2238c2ecf20Sopenharmony_ci {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340}, 2248c2ecf20Sopenharmony_ci {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000}, 2258c2ecf20Sopenharmony_ci {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500}, 2268c2ecf20Sopenharmony_ci {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200}, 2278c2ecf20Sopenharmony_ci {"L-SECAM-NICAM", 0x8080, 0x0009, 6200}, 2288c2ecf20Sopenharmony_ci {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200}, 2298c2ecf20Sopenharmony_ci {"DTV6", 0x00C0, 0x8002, 0}, 2308c2ecf20Sopenharmony_ci {"DTV8", 0x00C0, 0x800B, 0}, 2318c2ecf20Sopenharmony_ci {"DTV7/8", 0x00C0, 0x801B, 0}, 2328c2ecf20Sopenharmony_ci {"DTV7", 0x00C0, 0x8007, 0}, 2338c2ecf20Sopenharmony_ci {"FM Radio-INPUT2", 0x0008, 0x9800, 10700}, 2348c2ecf20Sopenharmony_ci {"FM Radio-INPUT1", 0x0008, 0x9000, 10700} 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val); 2388c2ecf20Sopenharmony_cistatic int xc4000_tuner_reset(struct dvb_frontend *fe); 2398c2ecf20Sopenharmony_cistatic void xc_debug_dump(struct xc4000_priv *priv); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_props.addr, 2448c2ecf20Sopenharmony_ci .flags = 0, .buf = buf, .len = len }; 2458c2ecf20Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { 2468c2ecf20Sopenharmony_ci if (priv->ignore_i2c_write_errors == 0) { 2478c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", 2488c2ecf20Sopenharmony_ci len); 2498c2ecf20Sopenharmony_ci if (len == 4) { 2508c2ecf20Sopenharmony_ci printk(KERN_ERR "bytes %*ph\n", 4, buf); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci return -EREMOTEIO; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int xc4000_tuner_reset(struct dvb_frontend *fe) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (fe->callback) { 2668c2ecf20Sopenharmony_ci ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? 2678c2ecf20Sopenharmony_ci fe->dvb->priv : 2688c2ecf20Sopenharmony_ci priv->i2c_props.adap->algo_data, 2698c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 2708c2ecf20Sopenharmony_ci XC4000_TUNER_RESET, 0); 2718c2ecf20Sopenharmony_ci if (ret) { 2728c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: reset failed\n"); 2738c2ecf20Sopenharmony_ci return -EREMOTEIO; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci } else { 2768c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: no tuner reset callback function, fatal\n"); 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci u8 buf[4]; 2858c2ecf20Sopenharmony_ci int result; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci buf[0] = (regAddr >> 8) & 0xFF; 2888c2ecf20Sopenharmony_ci buf[1] = regAddr & 0xFF; 2898c2ecf20Sopenharmony_ci buf[2] = (i2cData >> 8) & 0xFF; 2908c2ecf20Sopenharmony_ci buf[3] = i2cData & 0xFF; 2918c2ecf20Sopenharmony_ci result = xc_send_i2c_data(priv, buf, 4); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return result; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci int i, nbytes_to_send, result; 3018c2ecf20Sopenharmony_ci unsigned int len, pos, index; 3028c2ecf20Sopenharmony_ci u8 buf[XC_MAX_I2C_WRITE_LENGTH]; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci index = 0; 3058c2ecf20Sopenharmony_ci while ((i2c_sequence[index] != 0xFF) || 3068c2ecf20Sopenharmony_ci (i2c_sequence[index + 1] != 0xFF)) { 3078c2ecf20Sopenharmony_ci len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; 3088c2ecf20Sopenharmony_ci if (len == 0x0000) { 3098c2ecf20Sopenharmony_ci /* RESET command */ 3108c2ecf20Sopenharmony_ci /* NOTE: this is ignored, as the reset callback was */ 3118c2ecf20Sopenharmony_ci /* already called by check_firmware() */ 3128c2ecf20Sopenharmony_ci index += 2; 3138c2ecf20Sopenharmony_ci } else if (len & 0x8000) { 3148c2ecf20Sopenharmony_ci /* WAIT command */ 3158c2ecf20Sopenharmony_ci msleep(len & 0x7FFF); 3168c2ecf20Sopenharmony_ci index += 2; 3178c2ecf20Sopenharmony_ci } else { 3188c2ecf20Sopenharmony_ci /* Send i2c data whilst ensuring individual transactions 3198c2ecf20Sopenharmony_ci * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_ci index += 2; 3228c2ecf20Sopenharmony_ci buf[0] = i2c_sequence[index]; 3238c2ecf20Sopenharmony_ci buf[1] = i2c_sequence[index + 1]; 3248c2ecf20Sopenharmony_ci pos = 2; 3258c2ecf20Sopenharmony_ci while (pos < len) { 3268c2ecf20Sopenharmony_ci if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) 3278c2ecf20Sopenharmony_ci nbytes_to_send = 3288c2ecf20Sopenharmony_ci XC_MAX_I2C_WRITE_LENGTH; 3298c2ecf20Sopenharmony_ci else 3308c2ecf20Sopenharmony_ci nbytes_to_send = (len - pos + 2); 3318c2ecf20Sopenharmony_ci for (i = 2; i < nbytes_to_send; i++) { 3328c2ecf20Sopenharmony_ci buf[i] = i2c_sequence[index + pos + 3338c2ecf20Sopenharmony_ci i - 2]; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci result = xc_send_i2c_data(priv, buf, 3368c2ecf20Sopenharmony_ci nbytes_to_send); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (result != 0) 3398c2ecf20Sopenharmony_ci return result; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci pos += nbytes_to_send - 2; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci index += len; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int xc_set_tv_standard(struct xc4000_priv *priv, 3508c2ecf20Sopenharmony_ci u16 video_mode, u16 audio_mode) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci int ret; 3538c2ecf20Sopenharmony_ci dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); 3548c2ecf20Sopenharmony_ci dprintk(1, "%s() Standard = %s\n", 3558c2ecf20Sopenharmony_ci __func__, 3568c2ecf20Sopenharmony_ci xc4000_standard[priv->video_standard].Name); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Don't complain when the request fails because of i2c stretching */ 3598c2ecf20Sopenharmony_ci priv->ignore_i2c_write_errors = 1; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); 3628c2ecf20Sopenharmony_ci if (ret == 0) 3638c2ecf20Sopenharmony_ci ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci priv->ignore_i2c_write_errors = 0; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, 3738c2ecf20Sopenharmony_ci rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { 3768c2ecf20Sopenharmony_ci rf_mode = XC_RF_MODE_CABLE; 3778c2ecf20Sopenharmony_ci printk(KERN_ERR 3788c2ecf20Sopenharmony_ci "%s(), Invalid mode, defaulting to CABLE", 3798c2ecf20Sopenharmony_ci __func__); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops xc4000_tuner_ops; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci u16 freq_code; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci dprintk(1, "%s(%u)\n", __func__, freq_hz); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if ((freq_hz > xc4000_tuner_ops.info.frequency_max_hz) || 3938c2ecf20Sopenharmony_ci (freq_hz < xc4000_tuner_ops.info.frequency_min_hz)) 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci freq_code = (u16)(freq_hz / 15625); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the 3998c2ecf20Sopenharmony_ci FINERFREQ for all normal tuning (the doc indicates reg 0x03 should 4008c2ecf20Sopenharmony_ci only be used for fast scanning for channel lock) */ 4018c2ecf20Sopenharmony_ci /* WAS: XREG_FINERFREQ */ 4028c2ecf20Sopenharmony_ci return xc_write_reg(priv, XREG_RF_FREQ, freq_code); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci int result; 4138c2ecf20Sopenharmony_ci u16 regData; 4148c2ecf20Sopenharmony_ci u32 tmp; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci result = xc4000_readreg(priv, XREG_FREQ_ERROR, ®Data); 4178c2ecf20Sopenharmony_ci if (result != 0) 4188c2ecf20Sopenharmony_ci return result; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci tmp = (u32)regData & 0xFFFFU; 4218c2ecf20Sopenharmony_ci tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp); 4228c2ecf20Sopenharmony_ci (*freq_error_hz) = tmp * 15625; 4238c2ecf20Sopenharmony_ci return result; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci return xc4000_readreg(priv, XREG_LOCK, lock_status); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int xc_get_version(struct xc4000_priv *priv, 4328c2ecf20Sopenharmony_ci u8 *hw_majorversion, u8 *hw_minorversion, 4338c2ecf20Sopenharmony_ci u8 *fw_majorversion, u8 *fw_minorversion) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci u16 data; 4368c2ecf20Sopenharmony_ci int result; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci result = xc4000_readreg(priv, XREG_VERSION, &data); 4398c2ecf20Sopenharmony_ci if (result != 0) 4408c2ecf20Sopenharmony_ci return result; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci (*hw_majorversion) = (data >> 12) & 0x0F; 4438c2ecf20Sopenharmony_ci (*hw_minorversion) = (data >> 8) & 0x0F; 4448c2ecf20Sopenharmony_ci (*fw_majorversion) = (data >> 4) & 0x0F; 4458c2ecf20Sopenharmony_ci (*fw_minorversion) = data & 0x0F; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci u16 regData; 4538c2ecf20Sopenharmony_ci int result; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci result = xc4000_readreg(priv, XREG_HSYNC_FREQ, ®Data); 4568c2ecf20Sopenharmony_ci if (result != 0) 4578c2ecf20Sopenharmony_ci return result; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; 4608c2ecf20Sopenharmony_ci return result; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int xc_get_quality(struct xc4000_priv *priv, u16 *quality) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci return xc4000_readreg(priv, XREG_QUALITY, quality); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic u16 xc_wait_for_lock(struct xc4000_priv *priv) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci u16 lock_state = 0; 4868c2ecf20Sopenharmony_ci int watchdog_count = 40; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci while ((lock_state == 0) && (watchdog_count > 0)) { 4898c2ecf20Sopenharmony_ci xc_get_lock_status(priv, &lock_state); 4908c2ecf20Sopenharmony_ci if (lock_state != 1) { 4918c2ecf20Sopenharmony_ci msleep(5); 4928c2ecf20Sopenharmony_ci watchdog_count--; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci return lock_state; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci int found = 1; 5018c2ecf20Sopenharmony_ci int result; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci dprintk(1, "%s(%u)\n", __func__, freq_hz); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Don't complain when the request fails because of i2c stretching */ 5068c2ecf20Sopenharmony_ci priv->ignore_i2c_write_errors = 1; 5078c2ecf20Sopenharmony_ci result = xc_set_rf_frequency(priv, freq_hz); 5088c2ecf20Sopenharmony_ci priv->ignore_i2c_write_errors = 0; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (result != 0) 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* wait for lock only in analog TV mode */ 5148c2ecf20Sopenharmony_ci if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) { 5158c2ecf20Sopenharmony_ci if (xc_wait_for_lock(priv) != 1) 5168c2ecf20Sopenharmony_ci found = 0; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* Wait for stats to stabilize. 5208c2ecf20Sopenharmony_ci * Frame Lines needs two frame times after initial lock 5218c2ecf20Sopenharmony_ci * before it is valid. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ci msleep(debug ? 100 : 10); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (debug) 5268c2ecf20Sopenharmony_ci xc_debug_dump(priv); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci return found; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci u8 buf[2] = { reg >> 8, reg & 0xff }; 5348c2ecf20Sopenharmony_ci u8 bval[2] = { 0, 0 }; 5358c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 5368c2ecf20Sopenharmony_ci { .addr = priv->i2c_props.addr, 5378c2ecf20Sopenharmony_ci .flags = 0, .buf = &buf[0], .len = 2 }, 5388c2ecf20Sopenharmony_ci { .addr = priv->i2c_props.addr, 5398c2ecf20Sopenharmony_ci .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, 5408c2ecf20Sopenharmony_ci }; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { 5438c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: I2C read failed\n"); 5448c2ecf20Sopenharmony_ci return -EREMOTEIO; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci *val = (bval[0] << 8) | bval[1]; 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) 5528c2ecf20Sopenharmony_cistatic void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci if (type & BASE) 5558c2ecf20Sopenharmony_ci printk(KERN_CONT "BASE "); 5568c2ecf20Sopenharmony_ci if (type & INIT1) 5578c2ecf20Sopenharmony_ci printk(KERN_CONT "INIT1 "); 5588c2ecf20Sopenharmony_ci if (type & F8MHZ) 5598c2ecf20Sopenharmony_ci printk(KERN_CONT "F8MHZ "); 5608c2ecf20Sopenharmony_ci if (type & MTS) 5618c2ecf20Sopenharmony_ci printk(KERN_CONT "MTS "); 5628c2ecf20Sopenharmony_ci if (type & D2620) 5638c2ecf20Sopenharmony_ci printk(KERN_CONT "D2620 "); 5648c2ecf20Sopenharmony_ci if (type & D2633) 5658c2ecf20Sopenharmony_ci printk(KERN_CONT "D2633 "); 5668c2ecf20Sopenharmony_ci if (type & DTV6) 5678c2ecf20Sopenharmony_ci printk(KERN_CONT "DTV6 "); 5688c2ecf20Sopenharmony_ci if (type & QAM) 5698c2ecf20Sopenharmony_ci printk(KERN_CONT "QAM "); 5708c2ecf20Sopenharmony_ci if (type & DTV7) 5718c2ecf20Sopenharmony_ci printk(KERN_CONT "DTV7 "); 5728c2ecf20Sopenharmony_ci if (type & DTV78) 5738c2ecf20Sopenharmony_ci printk(KERN_CONT "DTV78 "); 5748c2ecf20Sopenharmony_ci if (type & DTV8) 5758c2ecf20Sopenharmony_ci printk(KERN_CONT "DTV8 "); 5768c2ecf20Sopenharmony_ci if (type & FM) 5778c2ecf20Sopenharmony_ci printk(KERN_CONT "FM "); 5788c2ecf20Sopenharmony_ci if (type & INPUT1) 5798c2ecf20Sopenharmony_ci printk(KERN_CONT "INPUT1 "); 5808c2ecf20Sopenharmony_ci if (type & LCD) 5818c2ecf20Sopenharmony_ci printk(KERN_CONT "LCD "); 5828c2ecf20Sopenharmony_ci if (type & NOGD) 5838c2ecf20Sopenharmony_ci printk(KERN_CONT "NOGD "); 5848c2ecf20Sopenharmony_ci if (type & MONO) 5858c2ecf20Sopenharmony_ci printk(KERN_CONT "MONO "); 5868c2ecf20Sopenharmony_ci if (type & ATSC) 5878c2ecf20Sopenharmony_ci printk(KERN_CONT "ATSC "); 5888c2ecf20Sopenharmony_ci if (type & IF) 5898c2ecf20Sopenharmony_ci printk(KERN_CONT "IF "); 5908c2ecf20Sopenharmony_ci if (type & LG60) 5918c2ecf20Sopenharmony_ci printk(KERN_CONT "LG60 "); 5928c2ecf20Sopenharmony_ci if (type & ATI638) 5938c2ecf20Sopenharmony_ci printk(KERN_CONT "ATI638 "); 5948c2ecf20Sopenharmony_ci if (type & OREN538) 5958c2ecf20Sopenharmony_ci printk(KERN_CONT "OREN538 "); 5968c2ecf20Sopenharmony_ci if (type & OREN36) 5978c2ecf20Sopenharmony_ci printk(KERN_CONT "OREN36 "); 5988c2ecf20Sopenharmony_ci if (type & TOYOTA388) 5998c2ecf20Sopenharmony_ci printk(KERN_CONT "TOYOTA388 "); 6008c2ecf20Sopenharmony_ci if (type & TOYOTA794) 6018c2ecf20Sopenharmony_ci printk(KERN_CONT "TOYOTA794 "); 6028c2ecf20Sopenharmony_ci if (type & DIBCOM52) 6038c2ecf20Sopenharmony_ci printk(KERN_CONT "DIBCOM52 "); 6048c2ecf20Sopenharmony_ci if (type & ZARLINK456) 6058c2ecf20Sopenharmony_ci printk(KERN_CONT "ZARLINK456 "); 6068c2ecf20Sopenharmony_ci if (type & CHINA) 6078c2ecf20Sopenharmony_ci printk(KERN_CONT "CHINA "); 6088c2ecf20Sopenharmony_ci if (type & F6MHZ) 6098c2ecf20Sopenharmony_ci printk(KERN_CONT "F6MHZ "); 6108c2ecf20Sopenharmony_ci if (type & INPUT2) 6118c2ecf20Sopenharmony_ci printk(KERN_CONT "INPUT2 "); 6128c2ecf20Sopenharmony_ci if (type & SCODE) 6138c2ecf20Sopenharmony_ci printk(KERN_CONT "SCODE "); 6148c2ecf20Sopenharmony_ci if (type & HAS_IF) 6158c2ecf20Sopenharmony_ci printk(KERN_CONT "HAS_IF_%d ", int_freq); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int seek_firmware(struct dvb_frontend *fe, unsigned int type, 6198c2ecf20Sopenharmony_ci v4l2_std_id *id) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 6228c2ecf20Sopenharmony_ci int i, best_i = -1; 6238c2ecf20Sopenharmony_ci unsigned int best_nr_diffs = 255U; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!priv->firm) { 6268c2ecf20Sopenharmony_ci printk(KERN_ERR "Error! firmware not loaded\n"); 6278c2ecf20Sopenharmony_ci return -EINVAL; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (((type & ~SCODE) == 0) && (*id == 0)) 6318c2ecf20Sopenharmony_ci *id = V4L2_STD_PAL; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* Seek for generic video standard match */ 6348c2ecf20Sopenharmony_ci for (i = 0; i < priv->firm_size; i++) { 6358c2ecf20Sopenharmony_ci v4l2_std_id id_diff_mask = 6368c2ecf20Sopenharmony_ci (priv->firm[i].id ^ (*id)) & (*id); 6378c2ecf20Sopenharmony_ci unsigned int type_diff_mask = 6388c2ecf20Sopenharmony_ci (priv->firm[i].type ^ type) 6398c2ecf20Sopenharmony_ci & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE); 6408c2ecf20Sopenharmony_ci unsigned int nr_diffs; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (type_diff_mask 6438c2ecf20Sopenharmony_ci & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE)) 6448c2ecf20Sopenharmony_ci continue; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask); 6478c2ecf20Sopenharmony_ci if (!nr_diffs) /* Supports all the requested standards */ 6488c2ecf20Sopenharmony_ci goto found; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (nr_diffs < best_nr_diffs) { 6518c2ecf20Sopenharmony_ci best_nr_diffs = nr_diffs; 6528c2ecf20Sopenharmony_ci best_i = i; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* FIXME: Would make sense to seek for type "hint" match ? */ 6578c2ecf20Sopenharmony_ci if (best_i < 0) { 6588c2ecf20Sopenharmony_ci i = -ENOENT; 6598c2ecf20Sopenharmony_ci goto ret; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (best_nr_diffs > 0U) { 6638c2ecf20Sopenharmony_ci printk(KERN_WARNING 6648c2ecf20Sopenharmony_ci "Selecting best matching firmware (%u bits differ) for type=(%x), id %016llx:\n", 6658c2ecf20Sopenharmony_ci best_nr_diffs, type, (unsigned long long)*id); 6668c2ecf20Sopenharmony_ci i = best_i; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cifound: 6708c2ecf20Sopenharmony_ci *id = priv->firm[i].id; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ciret: 6738c2ecf20Sopenharmony_ci if (debug) { 6748c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s firmware for type=", 6758c2ecf20Sopenharmony_ci (i < 0) ? "Can't find" : "Found"); 6768c2ecf20Sopenharmony_ci dump_firm_type(type); 6778c2ecf20Sopenharmony_ci printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id); 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci return i; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int load_firmware(struct dvb_frontend *fe, unsigned int type, 6838c2ecf20Sopenharmony_ci v4l2_std_id *id) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 6868c2ecf20Sopenharmony_ci int pos, rc; 6878c2ecf20Sopenharmony_ci unsigned char *p; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci pos = seek_firmware(fe, type, id); 6908c2ecf20Sopenharmony_ci if (pos < 0) 6918c2ecf20Sopenharmony_ci return pos; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci p = priv->firm[pos].ptr; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* Don't complain when the request fails because of i2c stretching */ 6968c2ecf20Sopenharmony_ci priv->ignore_i2c_write_errors = 1; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci rc = xc_load_i2c_sequence(fe, p); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci priv->ignore_i2c_write_errors = 0; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci return rc; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic int xc4000_fwupload(struct dvb_frontend *fe) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 7088c2ecf20Sopenharmony_ci const struct firmware *fw = NULL; 7098c2ecf20Sopenharmony_ci const unsigned char *p, *endp; 7108c2ecf20Sopenharmony_ci int rc = 0; 7118c2ecf20Sopenharmony_ci int n, n_array; 7128c2ecf20Sopenharmony_ci char name[33]; 7138c2ecf20Sopenharmony_ci const char *fname; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (firmware_name[0] != '\0') { 7168c2ecf20Sopenharmony_ci fname = firmware_name; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci dprintk(1, "Reading custom firmware %s\n", fname); 7198c2ecf20Sopenharmony_ci rc = request_firmware(&fw, fname, 7208c2ecf20Sopenharmony_ci priv->i2c_props.adap->dev.parent); 7218c2ecf20Sopenharmony_ci } else { 7228c2ecf20Sopenharmony_ci fname = XC4000_DEFAULT_FIRMWARE_NEW; 7238c2ecf20Sopenharmony_ci dprintk(1, "Trying to read firmware %s\n", fname); 7248c2ecf20Sopenharmony_ci rc = request_firmware(&fw, fname, 7258c2ecf20Sopenharmony_ci priv->i2c_props.adap->dev.parent); 7268c2ecf20Sopenharmony_ci if (rc == -ENOENT) { 7278c2ecf20Sopenharmony_ci fname = XC4000_DEFAULT_FIRMWARE; 7288c2ecf20Sopenharmony_ci dprintk(1, "Trying to read firmware %s\n", fname); 7298c2ecf20Sopenharmony_ci rc = request_firmware(&fw, fname, 7308c2ecf20Sopenharmony_ci priv->i2c_props.adap->dev.parent); 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (rc < 0) { 7358c2ecf20Sopenharmony_ci if (rc == -ENOENT) 7368c2ecf20Sopenharmony_ci printk(KERN_ERR "Error: firmware %s not found.\n", fname); 7378c2ecf20Sopenharmony_ci else 7388c2ecf20Sopenharmony_ci printk(KERN_ERR "Error %d while requesting firmware %s\n", 7398c2ecf20Sopenharmony_ci rc, fname); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return rc; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci dprintk(1, "Loading Firmware: %s\n", fname); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci p = fw->data; 7468c2ecf20Sopenharmony_ci endp = p + fw->size; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (fw->size < sizeof(name) - 1 + 2 + 2) { 7498c2ecf20Sopenharmony_ci printk(KERN_ERR "Error: firmware file %s has invalid size!\n", 7508c2ecf20Sopenharmony_ci fname); 7518c2ecf20Sopenharmony_ci goto corrupt; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci memcpy(name, p, sizeof(name) - 1); 7558c2ecf20Sopenharmony_ci name[sizeof(name) - 1] = '\0'; 7568c2ecf20Sopenharmony_ci p += sizeof(name) - 1; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci priv->firm_version = get_unaligned_le16(p); 7598c2ecf20Sopenharmony_ci p += 2; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci n_array = get_unaligned_le16(p); 7628c2ecf20Sopenharmony_ci p += 2; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n", 7658c2ecf20Sopenharmony_ci n_array, fname, name, 7668c2ecf20Sopenharmony_ci priv->firm_version >> 8, priv->firm_version & 0xff); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); 7698c2ecf20Sopenharmony_ci if (priv->firm == NULL) { 7708c2ecf20Sopenharmony_ci printk(KERN_ERR "Not enough memory to load firmware file.\n"); 7718c2ecf20Sopenharmony_ci rc = -ENOMEM; 7728c2ecf20Sopenharmony_ci goto done; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci priv->firm_size = n_array; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci n = -1; 7778c2ecf20Sopenharmony_ci while (p < endp) { 7788c2ecf20Sopenharmony_ci __u32 type, size; 7798c2ecf20Sopenharmony_ci v4l2_std_id id; 7808c2ecf20Sopenharmony_ci __u16 int_freq = 0; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci n++; 7838c2ecf20Sopenharmony_ci if (n >= n_array) { 7848c2ecf20Sopenharmony_ci printk(KERN_ERR "More firmware images in file than were expected!\n"); 7858c2ecf20Sopenharmony_ci goto corrupt; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* Checks if there's enough bytes to read */ 7898c2ecf20Sopenharmony_ci if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) 7908c2ecf20Sopenharmony_ci goto header; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci type = get_unaligned_le32(p); 7938c2ecf20Sopenharmony_ci p += sizeof(type); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci id = get_unaligned_le64(p); 7968c2ecf20Sopenharmony_ci p += sizeof(id); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (type & HAS_IF) { 7998c2ecf20Sopenharmony_ci int_freq = get_unaligned_le16(p); 8008c2ecf20Sopenharmony_ci p += sizeof(int_freq); 8018c2ecf20Sopenharmony_ci if (endp - p < sizeof(size)) 8028c2ecf20Sopenharmony_ci goto header; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci size = get_unaligned_le32(p); 8068c2ecf20Sopenharmony_ci p += sizeof(size); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (!size || size > endp - p) { 8098c2ecf20Sopenharmony_ci printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%zd, expected %d)\n", 8108c2ecf20Sopenharmony_ci type, (unsigned long long)id, 8118c2ecf20Sopenharmony_ci endp - p, size); 8128c2ecf20Sopenharmony_ci goto corrupt; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci priv->firm[n].ptr = kmemdup(p, size, GFP_KERNEL); 8168c2ecf20Sopenharmony_ci if (priv->firm[n].ptr == NULL) { 8178c2ecf20Sopenharmony_ci printk(KERN_ERR "Not enough memory to load firmware file.\n"); 8188c2ecf20Sopenharmony_ci rc = -ENOMEM; 8198c2ecf20Sopenharmony_ci goto done; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (debug) { 8238c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Reading firmware type "); 8248c2ecf20Sopenharmony_ci dump_firm_type_and_int_freq(type, int_freq); 8258c2ecf20Sopenharmony_ci printk(KERN_DEBUG "(%x), id %llx, size=%d.\n", 8268c2ecf20Sopenharmony_ci type, (unsigned long long)id, size); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci priv->firm[n].type = type; 8308c2ecf20Sopenharmony_ci priv->firm[n].id = id; 8318c2ecf20Sopenharmony_ci priv->firm[n].size = size; 8328c2ecf20Sopenharmony_ci priv->firm[n].int_freq = int_freq; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci p += size; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (n + 1 != priv->firm_size) { 8388c2ecf20Sopenharmony_ci printk(KERN_ERR "Firmware file is incomplete!\n"); 8398c2ecf20Sopenharmony_ci goto corrupt; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci goto done; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ciheader: 8458c2ecf20Sopenharmony_ci printk(KERN_ERR "Firmware header is incomplete!\n"); 8468c2ecf20Sopenharmony_cicorrupt: 8478c2ecf20Sopenharmony_ci rc = -EINVAL; 8488c2ecf20Sopenharmony_ci printk(KERN_ERR "Error: firmware file is corrupted!\n"); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cidone: 8518c2ecf20Sopenharmony_ci release_firmware(fw); 8528c2ecf20Sopenharmony_ci if (rc == 0) 8538c2ecf20Sopenharmony_ci dprintk(1, "Firmware files loaded.\n"); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci return rc; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic int load_scode(struct dvb_frontend *fe, unsigned int type, 8598c2ecf20Sopenharmony_ci v4l2_std_id *id, __u16 int_freq, int scode) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 8628c2ecf20Sopenharmony_ci int pos, rc; 8638c2ecf20Sopenharmony_ci unsigned char *p; 8648c2ecf20Sopenharmony_ci u8 scode_buf[13]; 8658c2ecf20Sopenharmony_ci u8 indirect_mode[5]; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci dprintk(1, "%s called int_freq=%d\n", __func__, int_freq); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (!int_freq) { 8708c2ecf20Sopenharmony_ci pos = seek_firmware(fe, type, id); 8718c2ecf20Sopenharmony_ci if (pos < 0) 8728c2ecf20Sopenharmony_ci return pos; 8738c2ecf20Sopenharmony_ci } else { 8748c2ecf20Sopenharmony_ci for (pos = 0; pos < priv->firm_size; pos++) { 8758c2ecf20Sopenharmony_ci if ((priv->firm[pos].int_freq == int_freq) && 8768c2ecf20Sopenharmony_ci (priv->firm[pos].type & HAS_IF)) 8778c2ecf20Sopenharmony_ci break; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci if (pos == priv->firm_size) 8808c2ecf20Sopenharmony_ci return -ENOENT; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci p = priv->firm[pos].ptr; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (priv->firm[pos].size != 12 * 16 || scode >= 16) 8868c2ecf20Sopenharmony_ci return -EINVAL; 8878c2ecf20Sopenharmony_ci p += 12 * scode; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (debug) { 8908c2ecf20Sopenharmony_ci tuner_info("Loading SCODE for type="); 8918c2ecf20Sopenharmony_ci dump_firm_type_and_int_freq(priv->firm[pos].type, 8928c2ecf20Sopenharmony_ci priv->firm[pos].int_freq); 8938c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, 8948c2ecf20Sopenharmony_ci (unsigned long long)*id); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci scode_buf[0] = 0x00; 8988c2ecf20Sopenharmony_ci memcpy(&scode_buf[1], p, 12); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* Enter direct-mode */ 9018c2ecf20Sopenharmony_ci rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0); 9028c2ecf20Sopenharmony_ci if (rc < 0) { 9038c2ecf20Sopenharmony_ci printk(KERN_ERR "failed to put device into direct mode!\n"); 9048c2ecf20Sopenharmony_ci return -EIO; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci rc = xc_send_i2c_data(priv, scode_buf, 13); 9088c2ecf20Sopenharmony_ci if (rc != 0) { 9098c2ecf20Sopenharmony_ci /* Even if the send failed, make sure we set back to indirect 9108c2ecf20Sopenharmony_ci mode */ 9118c2ecf20Sopenharmony_ci printk(KERN_ERR "Failed to set scode %d\n", rc); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci /* Switch back to indirect-mode */ 9158c2ecf20Sopenharmony_ci memset(indirect_mode, 0, sizeof(indirect_mode)); 9168c2ecf20Sopenharmony_ci indirect_mode[4] = 0x88; 9178c2ecf20Sopenharmony_ci xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode)); 9188c2ecf20Sopenharmony_ci msleep(10); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return 0; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic int check_firmware(struct dvb_frontend *fe, unsigned int type, 9248c2ecf20Sopenharmony_ci v4l2_std_id std, __u16 int_freq) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 9278c2ecf20Sopenharmony_ci struct firmware_properties new_fw; 9288c2ecf20Sopenharmony_ci int rc = 0, is_retry = 0; 9298c2ecf20Sopenharmony_ci u16 hwmodel; 9308c2ecf20Sopenharmony_ci v4l2_std_id std0; 9318c2ecf20Sopenharmony_ci u8 hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci dprintk(1, "%s called\n", __func__); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (!priv->firm) { 9368c2ecf20Sopenharmony_ci rc = xc4000_fwupload(fe); 9378c2ecf20Sopenharmony_ci if (rc < 0) 9388c2ecf20Sopenharmony_ci return rc; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ciretry: 9428c2ecf20Sopenharmony_ci new_fw.type = type; 9438c2ecf20Sopenharmony_ci new_fw.id = std; 9448c2ecf20Sopenharmony_ci new_fw.std_req = std; 9458c2ecf20Sopenharmony_ci new_fw.scode_table = SCODE; 9468c2ecf20Sopenharmony_ci new_fw.scode_nr = 0; 9478c2ecf20Sopenharmony_ci new_fw.int_freq = int_freq; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci dprintk(1, "checking firmware, user requested type="); 9508c2ecf20Sopenharmony_ci if (debug) { 9518c2ecf20Sopenharmony_ci dump_firm_type(new_fw.type); 9528c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, 9538c2ecf20Sopenharmony_ci (unsigned long long)new_fw.std_req); 9548c2ecf20Sopenharmony_ci if (!int_freq) 9558c2ecf20Sopenharmony_ci printk(KERN_CONT "scode_tbl "); 9568c2ecf20Sopenharmony_ci else 9578c2ecf20Sopenharmony_ci printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); 9588c2ecf20Sopenharmony_ci printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* No need to reload base firmware if it matches */ 9628c2ecf20Sopenharmony_ci if (priv->cur_fw.type & BASE) { 9638c2ecf20Sopenharmony_ci dprintk(1, "BASE firmware not changed.\n"); 9648c2ecf20Sopenharmony_ci goto skip_base; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Updating BASE - forget about all currently loaded firmware */ 9688c2ecf20Sopenharmony_ci memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* Reset is needed before loading firmware */ 9718c2ecf20Sopenharmony_ci rc = xc4000_tuner_reset(fe); 9728c2ecf20Sopenharmony_ci if (rc < 0) 9738c2ecf20Sopenharmony_ci goto fail; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* BASE firmwares are all std0 */ 9768c2ecf20Sopenharmony_ci std0 = 0; 9778c2ecf20Sopenharmony_ci rc = load_firmware(fe, BASE, &std0); 9788c2ecf20Sopenharmony_ci if (rc < 0) { 9798c2ecf20Sopenharmony_ci printk(KERN_ERR "Error %d while loading base firmware\n", rc); 9808c2ecf20Sopenharmony_ci goto fail; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* Load INIT1, if needed */ 9848c2ecf20Sopenharmony_ci dprintk(1, "Load init1 firmware, if exists\n"); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci rc = load_firmware(fe, BASE | INIT1, &std0); 9878c2ecf20Sopenharmony_ci if (rc == -ENOENT) 9888c2ecf20Sopenharmony_ci rc = load_firmware(fe, BASE | INIT1, &std0); 9898c2ecf20Sopenharmony_ci if (rc < 0 && rc != -ENOENT) { 9908c2ecf20Sopenharmony_ci tuner_err("Error %d while loading init1 firmware\n", 9918c2ecf20Sopenharmony_ci rc); 9928c2ecf20Sopenharmony_ci goto fail; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ciskip_base: 9968c2ecf20Sopenharmony_ci /* 9978c2ecf20Sopenharmony_ci * No need to reload standard specific firmware if base firmware 9988c2ecf20Sopenharmony_ci * was not reloaded and requested video standards have not changed. 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_ci if (priv->cur_fw.type == (BASE | new_fw.type) && 10018c2ecf20Sopenharmony_ci priv->cur_fw.std_req == std) { 10028c2ecf20Sopenharmony_ci dprintk(1, "Std-specific firmware already loaded.\n"); 10038c2ecf20Sopenharmony_ci goto skip_std_specific; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci /* Reloading std-specific firmware forces a SCODE update */ 10078c2ecf20Sopenharmony_ci priv->cur_fw.scode_table = 0; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci /* Load the standard firmware */ 10108c2ecf20Sopenharmony_ci rc = load_firmware(fe, new_fw.type, &new_fw.id); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (rc < 0) 10138c2ecf20Sopenharmony_ci goto fail; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ciskip_std_specific: 10168c2ecf20Sopenharmony_ci if (priv->cur_fw.scode_table == new_fw.scode_table && 10178c2ecf20Sopenharmony_ci priv->cur_fw.scode_nr == new_fw.scode_nr) { 10188c2ecf20Sopenharmony_ci dprintk(1, "SCODE firmware already loaded.\n"); 10198c2ecf20Sopenharmony_ci goto check_device; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* Load SCODE firmware, if exists */ 10238c2ecf20Sopenharmony_ci rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, 10248c2ecf20Sopenharmony_ci new_fw.int_freq, new_fw.scode_nr); 10258c2ecf20Sopenharmony_ci if (rc != 0) 10268c2ecf20Sopenharmony_ci dprintk(1, "load scode failed %d\n", rc); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_cicheck_device: 10298c2ecf20Sopenharmony_ci if (xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel) < 0) { 10308c2ecf20Sopenharmony_ci printk(KERN_ERR "Unable to read tuner registers.\n"); 10318c2ecf20Sopenharmony_ci goto fail; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, 10358c2ecf20Sopenharmony_ci &fw_minor) != 0) { 10368c2ecf20Sopenharmony_ci printk(KERN_ERR "Unable to read tuner registers.\n"); 10378c2ecf20Sopenharmony_ci goto fail; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci dprintk(1, "Device is Xceive %d version %d.%d, firmware version %d.%d\n", 10418c2ecf20Sopenharmony_ci hwmodel, hw_major, hw_minor, fw_major, fw_minor); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* Check firmware version against what we downloaded. */ 10448c2ecf20Sopenharmony_ci if (priv->firm_version != ((fw_major << 8) | fw_minor)) { 10458c2ecf20Sopenharmony_ci printk(KERN_WARNING 10468c2ecf20Sopenharmony_ci "Incorrect readback of firmware version %d.%d.\n", 10478c2ecf20Sopenharmony_ci fw_major, fw_minor); 10488c2ecf20Sopenharmony_ci goto fail; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* Check that the tuner hardware model remains consistent over time. */ 10528c2ecf20Sopenharmony_ci if (priv->hwmodel == 0 && 10538c2ecf20Sopenharmony_ci (hwmodel == XC_PRODUCT_ID_XC4000 || 10548c2ecf20Sopenharmony_ci hwmodel == XC_PRODUCT_ID_XC4100)) { 10558c2ecf20Sopenharmony_ci priv->hwmodel = hwmodel; 10568c2ecf20Sopenharmony_ci priv->hwvers = (hw_major << 8) | hw_minor; 10578c2ecf20Sopenharmony_ci } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || 10588c2ecf20Sopenharmony_ci priv->hwvers != ((hw_major << 8) | hw_minor)) { 10598c2ecf20Sopenharmony_ci printk(KERN_WARNING 10608c2ecf20Sopenharmony_ci "Read invalid device hardware information - tuner hung?\n"); 10618c2ecf20Sopenharmony_ci goto fail; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci priv->cur_fw = new_fw; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* 10678c2ecf20Sopenharmony_ci * By setting BASE in cur_fw.type only after successfully loading all 10688c2ecf20Sopenharmony_ci * firmwares, we can: 10698c2ecf20Sopenharmony_ci * 1. Identify that BASE firmware with type=0 has been loaded; 10708c2ecf20Sopenharmony_ci * 2. Tell whether BASE firmware was just changed the next time through. 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci priv->cur_fw.type |= BASE; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci return 0; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cifail: 10778c2ecf20Sopenharmony_ci memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); 10788c2ecf20Sopenharmony_ci if (!is_retry) { 10798c2ecf20Sopenharmony_ci msleep(50); 10808c2ecf20Sopenharmony_ci is_retry = 1; 10818c2ecf20Sopenharmony_ci dprintk(1, "Retrying firmware load\n"); 10828c2ecf20Sopenharmony_ci goto retry; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (rc == -ENOENT) 10868c2ecf20Sopenharmony_ci rc = -EINVAL; 10878c2ecf20Sopenharmony_ci return rc; 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cistatic void xc_debug_dump(struct xc4000_priv *priv) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci u16 adc_envelope; 10938c2ecf20Sopenharmony_ci u32 freq_error_hz = 0; 10948c2ecf20Sopenharmony_ci u16 lock_status; 10958c2ecf20Sopenharmony_ci u32 hsync_freq_hz = 0; 10968c2ecf20Sopenharmony_ci u16 frame_lines; 10978c2ecf20Sopenharmony_ci u16 quality; 10988c2ecf20Sopenharmony_ci u16 signal = 0; 10998c2ecf20Sopenharmony_ci u16 noise = 0; 11008c2ecf20Sopenharmony_ci u8 hw_majorversion = 0, hw_minorversion = 0; 11018c2ecf20Sopenharmony_ci u8 fw_majorversion = 0, fw_minorversion = 0; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci xc_get_adc_envelope(priv, &adc_envelope); 11048c2ecf20Sopenharmony_ci dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci xc_get_frequency_error(priv, &freq_error_hz); 11078c2ecf20Sopenharmony_ci dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci xc_get_lock_status(priv, &lock_status); 11108c2ecf20Sopenharmony_ci dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", 11118c2ecf20Sopenharmony_ci lock_status); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci xc_get_version(priv, &hw_majorversion, &hw_minorversion, 11148c2ecf20Sopenharmony_ci &fw_majorversion, &fw_minorversion); 11158c2ecf20Sopenharmony_ci dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", 11168c2ecf20Sopenharmony_ci hw_majorversion, hw_minorversion, 11178c2ecf20Sopenharmony_ci fw_majorversion, fw_minorversion); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (priv->video_standard < XC4000_DTV6) { 11208c2ecf20Sopenharmony_ci xc_get_hsync_freq(priv, &hsync_freq_hz); 11218c2ecf20Sopenharmony_ci dprintk(1, "*** Horizontal sync frequency = %d Hz\n", 11228c2ecf20Sopenharmony_ci hsync_freq_hz); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci xc_get_frame_lines(priv, &frame_lines); 11258c2ecf20Sopenharmony_ci dprintk(1, "*** Frame lines = %d\n", frame_lines); 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci xc_get_quality(priv, &quality); 11298c2ecf20Sopenharmony_ci dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci xc_get_signal_level(priv, &signal); 11328c2ecf20Sopenharmony_ci dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci xc_get_noise_level(priv, &noise); 11358c2ecf20Sopenharmony_ci dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic int xc4000_set_params(struct dvb_frontend *fe) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 11418c2ecf20Sopenharmony_ci u32 delsys = c->delivery_system; 11428c2ecf20Sopenharmony_ci u32 bw = c->bandwidth_hz; 11438c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 11448c2ecf20Sopenharmony_ci unsigned int type; 11458c2ecf20Sopenharmony_ci int ret = -EREMOTEIO; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci switch (delsys) { 11528c2ecf20Sopenharmony_ci case SYS_ATSC: 11538c2ecf20Sopenharmony_ci dprintk(1, "%s() VSB modulation\n", __func__); 11548c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 11558c2ecf20Sopenharmony_ci priv->freq_offset = 1750000; 11568c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DTV6; 11578c2ecf20Sopenharmony_ci type = DTV6; 11588c2ecf20Sopenharmony_ci break; 11598c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_B: 11608c2ecf20Sopenharmony_ci dprintk(1, "%s() QAM modulation\n", __func__); 11618c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 11628c2ecf20Sopenharmony_ci priv->freq_offset = 1750000; 11638c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DTV6; 11648c2ecf20Sopenharmony_ci type = DTV6; 11658c2ecf20Sopenharmony_ci break; 11668c2ecf20Sopenharmony_ci case SYS_DVBT: 11678c2ecf20Sopenharmony_ci case SYS_DVBT2: 11688c2ecf20Sopenharmony_ci dprintk(1, "%s() OFDM\n", __func__); 11698c2ecf20Sopenharmony_ci if (bw == 0) { 11708c2ecf20Sopenharmony_ci if (c->frequency < 400000000) { 11718c2ecf20Sopenharmony_ci priv->freq_offset = 2250000; 11728c2ecf20Sopenharmony_ci } else { 11738c2ecf20Sopenharmony_ci priv->freq_offset = 2750000; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DTV7_8; 11768c2ecf20Sopenharmony_ci type = DTV78; 11778c2ecf20Sopenharmony_ci } else if (bw <= 6000000) { 11788c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DTV6; 11798c2ecf20Sopenharmony_ci priv->freq_offset = 1750000; 11808c2ecf20Sopenharmony_ci type = DTV6; 11818c2ecf20Sopenharmony_ci } else if (bw <= 7000000) { 11828c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DTV7; 11838c2ecf20Sopenharmony_ci priv->freq_offset = 2250000; 11848c2ecf20Sopenharmony_ci type = DTV7; 11858c2ecf20Sopenharmony_ci } else { 11868c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DTV8; 11878c2ecf20Sopenharmony_ci priv->freq_offset = 2750000; 11888c2ecf20Sopenharmony_ci type = DTV8; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 11918c2ecf20Sopenharmony_ci break; 11928c2ecf20Sopenharmony_ci default: 11938c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000 delivery system not supported!\n"); 11948c2ecf20Sopenharmony_ci ret = -EINVAL; 11958c2ecf20Sopenharmony_ci goto fail; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci priv->freq_hz = c->frequency - priv->freq_offset; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci dprintk(1, "%s() frequency=%d (compensated)\n", 12018c2ecf20Sopenharmony_ci __func__, priv->freq_hz); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci /* Make sure the correct firmware type is loaded */ 12048c2ecf20Sopenharmony_ci if (check_firmware(fe, type, 0, priv->if_khz) != 0) 12058c2ecf20Sopenharmony_ci goto fail; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci priv->bandwidth = c->bandwidth_hz; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 12108c2ecf20Sopenharmony_ci if (ret != 0) { 12118c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", 12128c2ecf20Sopenharmony_ci priv->rf_mode); 12138c2ecf20Sopenharmony_ci goto fail; 12148c2ecf20Sopenharmony_ci } else { 12158c2ecf20Sopenharmony_ci u16 video_mode, audio_mode; 12168c2ecf20Sopenharmony_ci video_mode = xc4000_standard[priv->video_standard].video_mode; 12178c2ecf20Sopenharmony_ci audio_mode = xc4000_standard[priv->video_standard].audio_mode; 12188c2ecf20Sopenharmony_ci if (type == DTV6 && priv->firm_version != 0x0102) 12198c2ecf20Sopenharmony_ci video_mode |= 0x0001; 12208c2ecf20Sopenharmony_ci ret = xc_set_tv_standard(priv, video_mode, audio_mode); 12218c2ecf20Sopenharmony_ci if (ret != 0) { 12228c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); 12238c2ecf20Sopenharmony_ci /* DJH - do not return when it fails... */ 12248c2ecf20Sopenharmony_ci /* goto fail; */ 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) 12298c2ecf20Sopenharmony_ci ret = 0; 12308c2ecf20Sopenharmony_ci if (priv->dvb_amplitude != 0) { 12318c2ecf20Sopenharmony_ci if (xc_write_reg(priv, XREG_AMPLITUDE, 12328c2ecf20Sopenharmony_ci (priv->firm_version != 0x0102 || 12338c2ecf20Sopenharmony_ci priv->dvb_amplitude != 134 ? 12348c2ecf20Sopenharmony_ci priv->dvb_amplitude : 132)) != 0) 12358c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci if (priv->set_smoothedcvbs != 0) { 12388c2ecf20Sopenharmony_ci if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) 12398c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci if (ret != 0) { 12428c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: setting registers failed\n"); 12438c2ecf20Sopenharmony_ci /* goto fail; */ 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci ret = 0; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cifail: 12518c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci return ret; 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic int xc4000_set_analog_params(struct dvb_frontend *fe, 12578c2ecf20Sopenharmony_ci struct analog_parameters *params) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 12608c2ecf20Sopenharmony_ci unsigned int type = 0; 12618c2ecf20Sopenharmony_ci int ret = -EREMOTEIO; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci if (params->mode == V4L2_TUNER_RADIO) { 12648c2ecf20Sopenharmony_ci dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n", 12658c2ecf20Sopenharmony_ci __func__, params->frequency); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci params->std = 0; 12708c2ecf20Sopenharmony_ci priv->freq_hz = params->frequency * 125L / 2; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_INPUT1) { 12738c2ecf20Sopenharmony_ci priv->video_standard = XC4000_FM_Radio_INPUT1; 12748c2ecf20Sopenharmony_ci type = FM | INPUT1; 12758c2ecf20Sopenharmony_ci } else { 12768c2ecf20Sopenharmony_ci priv->video_standard = XC4000_FM_Radio_INPUT2; 12778c2ecf20Sopenharmony_ci type = FM | INPUT2; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci goto tune_channel; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", 12848c2ecf20Sopenharmony_ci __func__, params->frequency); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci /* params->frequency is in units of 62.5khz */ 12898c2ecf20Sopenharmony_ci priv->freq_hz = params->frequency * 62500; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci params->std &= V4L2_STD_ALL; 12928c2ecf20Sopenharmony_ci /* if std is not defined, choose one */ 12938c2ecf20Sopenharmony_ci if (!params->std) 12948c2ecf20Sopenharmony_ci params->std = V4L2_STD_PAL_BG; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) 12978c2ecf20Sopenharmony_ci type = MONO; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_MN) { 13008c2ecf20Sopenharmony_ci params->std = V4L2_STD_MN; 13018c2ecf20Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) { 13028c2ecf20Sopenharmony_ci priv->video_standard = XC4000_MN_NTSC_PAL_Mono; 13038c2ecf20Sopenharmony_ci } else if (audio_std & XC4000_AUDIO_STD_A2) { 13048c2ecf20Sopenharmony_ci params->std |= V4L2_STD_A2; 13058c2ecf20Sopenharmony_ci priv->video_standard = XC4000_MN_NTSC_PAL_A2; 13068c2ecf20Sopenharmony_ci } else { 13078c2ecf20Sopenharmony_ci params->std |= V4L2_STD_BTSC; 13088c2ecf20Sopenharmony_ci priv->video_standard = XC4000_MN_NTSC_PAL_BTSC; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci goto tune_channel; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_PAL_BG) { 13148c2ecf20Sopenharmony_ci params->std = V4L2_STD_PAL_BG; 13158c2ecf20Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) { 13168c2ecf20Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_MONO; 13178c2ecf20Sopenharmony_ci } else if (!(audio_std & XC4000_AUDIO_STD_A2)) { 13188c2ecf20Sopenharmony_ci if (!(audio_std & XC4000_AUDIO_STD_B)) { 13198c2ecf20Sopenharmony_ci params->std |= V4L2_STD_NICAM_A; 13208c2ecf20Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_NICAM; 13218c2ecf20Sopenharmony_ci } else { 13228c2ecf20Sopenharmony_ci params->std |= V4L2_STD_NICAM_B; 13238c2ecf20Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_NICAM; 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci } else { 13268c2ecf20Sopenharmony_ci if (!(audio_std & XC4000_AUDIO_STD_B)) { 13278c2ecf20Sopenharmony_ci params->std |= V4L2_STD_A2_A; 13288c2ecf20Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_A2; 13298c2ecf20Sopenharmony_ci } else { 13308c2ecf20Sopenharmony_ci params->std |= V4L2_STD_A2_B; 13318c2ecf20Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_A2; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci goto tune_channel; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_PAL_I) { 13388c2ecf20Sopenharmony_ci /* default to NICAM audio standard */ 13398c2ecf20Sopenharmony_ci params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM; 13408c2ecf20Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) 13418c2ecf20Sopenharmony_ci priv->video_standard = XC4000_I_PAL_NICAM_MONO; 13428c2ecf20Sopenharmony_ci else 13438c2ecf20Sopenharmony_ci priv->video_standard = XC4000_I_PAL_NICAM; 13448c2ecf20Sopenharmony_ci goto tune_channel; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_PAL_DK) { 13488c2ecf20Sopenharmony_ci params->std = V4L2_STD_PAL_DK; 13498c2ecf20Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) { 13508c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DK_PAL_MONO; 13518c2ecf20Sopenharmony_ci } else if (audio_std & XC4000_AUDIO_STD_A2) { 13528c2ecf20Sopenharmony_ci params->std |= V4L2_STD_A2; 13538c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DK_PAL_A2; 13548c2ecf20Sopenharmony_ci } else { 13558c2ecf20Sopenharmony_ci params->std |= V4L2_STD_NICAM; 13568c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DK_PAL_NICAM; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci goto tune_channel; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_SECAM_DK) { 13628c2ecf20Sopenharmony_ci /* default to A2 audio standard */ 13638c2ecf20Sopenharmony_ci params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2; 13648c2ecf20Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_L) { 13658c2ecf20Sopenharmony_ci type = 0; 13668c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DK_SECAM_NICAM; 13678c2ecf20Sopenharmony_ci } else if (audio_std & XC4000_AUDIO_STD_MONO) { 13688c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DK_SECAM_A2MONO; 13698c2ecf20Sopenharmony_ci } else if (audio_std & XC4000_AUDIO_STD_K3) { 13708c2ecf20Sopenharmony_ci params->std |= V4L2_STD_SECAM_K3; 13718c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DK_SECAM_A2LDK3; 13728c2ecf20Sopenharmony_ci } else { 13738c2ecf20Sopenharmony_ci priv->video_standard = XC4000_DK_SECAM_A2DK1; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci goto tune_channel; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_SECAM_L) { 13798c2ecf20Sopenharmony_ci /* default to NICAM audio standard */ 13808c2ecf20Sopenharmony_ci type = 0; 13818c2ecf20Sopenharmony_ci params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM; 13828c2ecf20Sopenharmony_ci priv->video_standard = XC4000_L_SECAM_NICAM; 13838c2ecf20Sopenharmony_ci goto tune_channel; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_SECAM_LC) { 13878c2ecf20Sopenharmony_ci /* default to NICAM audio standard */ 13888c2ecf20Sopenharmony_ci type = 0; 13898c2ecf20Sopenharmony_ci params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM; 13908c2ecf20Sopenharmony_ci priv->video_standard = XC4000_LC_SECAM_NICAM; 13918c2ecf20Sopenharmony_ci goto tune_channel; 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_citune_channel: 13958c2ecf20Sopenharmony_ci /* FIXME: it could be air. */ 13968c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (check_firmware(fe, type, params->std, 13998c2ecf20Sopenharmony_ci xc4000_standard[priv->video_standard].int_freq) != 0) 14008c2ecf20Sopenharmony_ci goto fail; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 14038c2ecf20Sopenharmony_ci if (ret != 0) { 14048c2ecf20Sopenharmony_ci printk(KERN_ERR 14058c2ecf20Sopenharmony_ci "xc4000: xc_set_signal_source(%d) failed\n", 14068c2ecf20Sopenharmony_ci priv->rf_mode); 14078c2ecf20Sopenharmony_ci goto fail; 14088c2ecf20Sopenharmony_ci } else { 14098c2ecf20Sopenharmony_ci u16 video_mode, audio_mode; 14108c2ecf20Sopenharmony_ci video_mode = xc4000_standard[priv->video_standard].video_mode; 14118c2ecf20Sopenharmony_ci audio_mode = xc4000_standard[priv->video_standard].audio_mode; 14128c2ecf20Sopenharmony_ci if (priv->video_standard < XC4000_BG_PAL_A2) { 14138c2ecf20Sopenharmony_ci if (type & NOGD) 14148c2ecf20Sopenharmony_ci video_mode &= 0xFF7F; 14158c2ecf20Sopenharmony_ci } else if (priv->video_standard < XC4000_I_PAL_NICAM) { 14168c2ecf20Sopenharmony_ci if (priv->firm_version == 0x0102) 14178c2ecf20Sopenharmony_ci video_mode &= 0xFEFF; 14188c2ecf20Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_B) 14198c2ecf20Sopenharmony_ci video_mode |= 0x0080; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci ret = xc_set_tv_standard(priv, video_mode, audio_mode); 14228c2ecf20Sopenharmony_ci if (ret != 0) { 14238c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); 14248c2ecf20Sopenharmony_ci goto fail; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) 14298c2ecf20Sopenharmony_ci ret = 0; 14308c2ecf20Sopenharmony_ci if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0) 14318c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 14328c2ecf20Sopenharmony_ci if (priv->set_smoothedcvbs != 0) { 14338c2ecf20Sopenharmony_ci if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) 14348c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci if (ret != 0) { 14378c2ecf20Sopenharmony_ci printk(KERN_ERR "xc4000: setting registers failed\n"); 14388c2ecf20Sopenharmony_ci goto fail; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci ret = 0; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cifail: 14468c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci return ret; 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_cistatic int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 14548c2ecf20Sopenharmony_ci u16 value = 0; 14558c2ecf20Sopenharmony_ci int rc; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 14588c2ecf20Sopenharmony_ci rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value); 14598c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if (rc < 0) 14628c2ecf20Sopenharmony_ci goto ret; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci /* Information from real testing of DVB-T and radio part, 14658c2ecf20Sopenharmony_ci coefficient for one dB is 0xff. 14668c2ecf20Sopenharmony_ci */ 14678c2ecf20Sopenharmony_ci tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci /* all known digital modes */ 14708c2ecf20Sopenharmony_ci if ((priv->video_standard == XC4000_DTV6) || 14718c2ecf20Sopenharmony_ci (priv->video_standard == XC4000_DTV7) || 14728c2ecf20Sopenharmony_ci (priv->video_standard == XC4000_DTV7_8) || 14738c2ecf20Sopenharmony_ci (priv->video_standard == XC4000_DTV8)) 14748c2ecf20Sopenharmony_ci goto digital; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* Analog mode has NOISE LEVEL important, signal 14778c2ecf20Sopenharmony_ci depends only on gain of antenna and amplifiers, 14788c2ecf20Sopenharmony_ci but it doesn't tell anything about real quality 14798c2ecf20Sopenharmony_ci of reception. 14808c2ecf20Sopenharmony_ci */ 14818c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 14828c2ecf20Sopenharmony_ci rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value); 14838c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci /* highest noise level: 32dB */ 14888c2ecf20Sopenharmony_ci if (value >= 0x2000) { 14898c2ecf20Sopenharmony_ci value = 0; 14908c2ecf20Sopenharmony_ci } else { 14918c2ecf20Sopenharmony_ci value = (~value << 3) & 0xffff; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci goto ret; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci /* Digital mode has SIGNAL LEVEL important and real 14978c2ecf20Sopenharmony_ci noise level is stored in demodulator registers. 14988c2ecf20Sopenharmony_ci */ 14998c2ecf20Sopenharmony_cidigital: 15008c2ecf20Sopenharmony_ci /* best signal: -50dB */ 15018c2ecf20Sopenharmony_ci if (value <= 0x3200) { 15028c2ecf20Sopenharmony_ci value = 0xffff; 15038c2ecf20Sopenharmony_ci /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */ 15048c2ecf20Sopenharmony_ci } else if (value >= 0x713A) { 15058c2ecf20Sopenharmony_ci value = 0; 15068c2ecf20Sopenharmony_ci } else { 15078c2ecf20Sopenharmony_ci value = ~(value - 0x3200) << 2; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ciret: 15118c2ecf20Sopenharmony_ci *strength = value; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci return rc; 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_cistatic int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 15218c2ecf20Sopenharmony_ci *freq = priv->freq_hz + priv->freq_offset; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (debug) { 15248c2ecf20Sopenharmony_ci if ((priv->cur_fw.type 15258c2ecf20Sopenharmony_ci & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) { 15268c2ecf20Sopenharmony_ci u16 snr = 0; 15278c2ecf20Sopenharmony_ci if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) { 15288c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 15298c2ecf20Sopenharmony_ci dprintk(1, "%s() freq = %u, SNR = %d\n", 15308c2ecf20Sopenharmony_ci __func__, *freq, snr); 15318c2ecf20Sopenharmony_ci return 0; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci return 0; 15408c2ecf20Sopenharmony_ci} 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_cistatic int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) 15438c2ecf20Sopenharmony_ci{ 15448c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 15458c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci *bw = priv->bandwidth; 15488c2ecf20Sopenharmony_ci return 0; 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_cistatic int xc4000_get_status(struct dvb_frontend *fe, u32 *status) 15528c2ecf20Sopenharmony_ci{ 15538c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 15548c2ecf20Sopenharmony_ci u16 lock_status = 0; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci if (priv->cur_fw.type & BASE) 15598c2ecf20Sopenharmony_ci xc_get_lock_status(priv, &lock_status); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci *status = (lock_status == 1 ? 15628c2ecf20Sopenharmony_ci TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0); 15638c2ecf20Sopenharmony_ci if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8)) 15648c2ecf20Sopenharmony_ci *status &= (~TUNER_STATUS_STEREO); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci dprintk(2, "%s() lock_status = %d\n", __func__, lock_status); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci return 0; 15718c2ecf20Sopenharmony_ci} 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_cistatic int xc4000_sleep(struct dvb_frontend *fe) 15748c2ecf20Sopenharmony_ci{ 15758c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 15768c2ecf20Sopenharmony_ci int ret = 0; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* Avoid firmware reload on slow devices */ 15838c2ecf20Sopenharmony_ci if ((no_poweroff == 2 || 15848c2ecf20Sopenharmony_ci (no_poweroff == 0 && priv->default_pm != 0)) && 15858c2ecf20Sopenharmony_ci (priv->cur_fw.type & BASE) != 0) { 15868c2ecf20Sopenharmony_ci /* force reset and firmware reload */ 15878c2ecf20Sopenharmony_ci priv->cur_fw.type = XC_POWERED_DOWN; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) { 15908c2ecf20Sopenharmony_ci printk(KERN_ERR 15918c2ecf20Sopenharmony_ci "xc4000: %s() unable to shutdown tuner\n", 15928c2ecf20Sopenharmony_ci __func__); 15938c2ecf20Sopenharmony_ci ret = -EREMOTEIO; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci msleep(20); 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci return ret; 16018c2ecf20Sopenharmony_ci} 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_cistatic int xc4000_init(struct dvb_frontend *fe) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci return 0; 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic void xc4000_release(struct dvb_frontend *fe) 16118c2ecf20Sopenharmony_ci{ 16128c2ecf20Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci mutex_lock(&xc4000_list_mutex); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci if (priv) 16198c2ecf20Sopenharmony_ci hybrid_tuner_release_state(priv); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci mutex_unlock(&xc4000_list_mutex); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops xc4000_tuner_ops = { 16278c2ecf20Sopenharmony_ci .info = { 16288c2ecf20Sopenharmony_ci .name = "Xceive XC4000", 16298c2ecf20Sopenharmony_ci .frequency_min_hz = 1 * MHz, 16308c2ecf20Sopenharmony_ci .frequency_max_hz = 1023 * MHz, 16318c2ecf20Sopenharmony_ci .frequency_step_hz = 50 * kHz, 16328c2ecf20Sopenharmony_ci }, 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci .release = xc4000_release, 16358c2ecf20Sopenharmony_ci .init = xc4000_init, 16368c2ecf20Sopenharmony_ci .sleep = xc4000_sleep, 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci .set_params = xc4000_set_params, 16398c2ecf20Sopenharmony_ci .set_analog_params = xc4000_set_analog_params, 16408c2ecf20Sopenharmony_ci .get_frequency = xc4000_get_frequency, 16418c2ecf20Sopenharmony_ci .get_rf_strength = xc4000_get_signal, 16428c2ecf20Sopenharmony_ci .get_bandwidth = xc4000_get_bandwidth, 16438c2ecf20Sopenharmony_ci .get_status = xc4000_get_status 16448c2ecf20Sopenharmony_ci}; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_cistruct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, 16478c2ecf20Sopenharmony_ci struct i2c_adapter *i2c, 16488c2ecf20Sopenharmony_ci struct xc4000_config *cfg) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci struct xc4000_priv *priv = NULL; 16518c2ecf20Sopenharmony_ci int instance; 16528c2ecf20Sopenharmony_ci u16 id = 0; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci dprintk(1, "%s(%d-%04x)\n", __func__, 16558c2ecf20Sopenharmony_ci i2c ? i2c_adapter_id(i2c) : -1, 16568c2ecf20Sopenharmony_ci cfg ? cfg->i2c_address : -1); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci mutex_lock(&xc4000_list_mutex); 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci instance = hybrid_tuner_request_state(struct xc4000_priv, priv, 16618c2ecf20Sopenharmony_ci hybrid_tuner_instance_list, 16628c2ecf20Sopenharmony_ci i2c, cfg->i2c_address, "xc4000"); 16638c2ecf20Sopenharmony_ci switch (instance) { 16648c2ecf20Sopenharmony_ci case 0: 16658c2ecf20Sopenharmony_ci goto fail; 16668c2ecf20Sopenharmony_ci case 1: 16678c2ecf20Sopenharmony_ci /* new tuner instance */ 16688c2ecf20Sopenharmony_ci priv->bandwidth = 6000000; 16698c2ecf20Sopenharmony_ci /* set default configuration */ 16708c2ecf20Sopenharmony_ci priv->if_khz = 4560; 16718c2ecf20Sopenharmony_ci priv->default_pm = 0; 16728c2ecf20Sopenharmony_ci priv->dvb_amplitude = 134; 16738c2ecf20Sopenharmony_ci priv->set_smoothedcvbs = 1; 16748c2ecf20Sopenharmony_ci mutex_init(&priv->lock); 16758c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 16768c2ecf20Sopenharmony_ci break; 16778c2ecf20Sopenharmony_ci default: 16788c2ecf20Sopenharmony_ci /* existing tuner instance */ 16798c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 16808c2ecf20Sopenharmony_ci break; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci if (cfg->if_khz != 0) { 16848c2ecf20Sopenharmony_ci /* copy configuration if provided by the caller */ 16858c2ecf20Sopenharmony_ci priv->if_khz = cfg->if_khz; 16868c2ecf20Sopenharmony_ci priv->default_pm = cfg->default_pm; 16878c2ecf20Sopenharmony_ci priv->dvb_amplitude = cfg->dvb_amplitude; 16888c2ecf20Sopenharmony_ci priv->set_smoothedcvbs = cfg->set_smoothedcvbs; 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci /* Check if firmware has been loaded. It is possible that another 16928c2ecf20Sopenharmony_ci instance of the driver has loaded the firmware. 16938c2ecf20Sopenharmony_ci */ 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if (instance == 1) { 16968c2ecf20Sopenharmony_ci if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) 16978c2ecf20Sopenharmony_ci goto fail; 16988c2ecf20Sopenharmony_ci } else { 16998c2ecf20Sopenharmony_ci id = ((priv->cur_fw.type & BASE) != 0 ? 17008c2ecf20Sopenharmony_ci priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED); 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci switch (id) { 17048c2ecf20Sopenharmony_ci case XC_PRODUCT_ID_XC4000: 17058c2ecf20Sopenharmony_ci case XC_PRODUCT_ID_XC4100: 17068c2ecf20Sopenharmony_ci printk(KERN_INFO 17078c2ecf20Sopenharmony_ci "xc4000: Successfully identified at address 0x%02x\n", 17088c2ecf20Sopenharmony_ci cfg->i2c_address); 17098c2ecf20Sopenharmony_ci printk(KERN_INFO 17108c2ecf20Sopenharmony_ci "xc4000: Firmware has been loaded previously\n"); 17118c2ecf20Sopenharmony_ci break; 17128c2ecf20Sopenharmony_ci case XC_PRODUCT_ID_FW_NOT_LOADED: 17138c2ecf20Sopenharmony_ci printk(KERN_INFO 17148c2ecf20Sopenharmony_ci "xc4000: Successfully identified at address 0x%02x\n", 17158c2ecf20Sopenharmony_ci cfg->i2c_address); 17168c2ecf20Sopenharmony_ci printk(KERN_INFO 17178c2ecf20Sopenharmony_ci "xc4000: Firmware has not been loaded previously\n"); 17188c2ecf20Sopenharmony_ci break; 17198c2ecf20Sopenharmony_ci default: 17208c2ecf20Sopenharmony_ci printk(KERN_ERR 17218c2ecf20Sopenharmony_ci "xc4000: Device not found at addr 0x%02x (0x%x)\n", 17228c2ecf20Sopenharmony_ci cfg->i2c_address, id); 17238c2ecf20Sopenharmony_ci goto fail; 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci mutex_unlock(&xc4000_list_mutex); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, 17298c2ecf20Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci if (instance == 1) { 17328c2ecf20Sopenharmony_ci int ret; 17338c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 17348c2ecf20Sopenharmony_ci ret = xc4000_fwupload(fe); 17358c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 17368c2ecf20Sopenharmony_ci if (ret != 0) 17378c2ecf20Sopenharmony_ci goto fail2; 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci return fe; 17418c2ecf20Sopenharmony_cifail: 17428c2ecf20Sopenharmony_ci mutex_unlock(&xc4000_list_mutex); 17438c2ecf20Sopenharmony_cifail2: 17448c2ecf20Sopenharmony_ci xc4000_release(fe); 17458c2ecf20Sopenharmony_ci return NULL; 17468c2ecf20Sopenharmony_ci} 17478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xc4000_attach); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steven Toth, Davide Ferri"); 17508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); 17518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 17528c2ecf20Sopenharmony_ciMODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE_NEW); 17538c2ecf20Sopenharmony_ciMODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE); 1754