162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2007 Xceive Corporation 662306a36Sopenharmony_ci * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> 762306a36Sopenharmony_ci * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> 862306a36Sopenharmony_ci * Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it> 962306a36Sopenharmony_ci * Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/moduleparam.h> 1462306a36Sopenharmony_ci#include <linux/videodev2.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/dvb/frontend.h> 1762306a36Sopenharmony_ci#include <linux/i2c.h> 1862306a36Sopenharmony_ci#include <linux/mutex.h> 1962306a36Sopenharmony_ci#include <asm/unaligned.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <media/dvb_frontend.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "xc4000.h" 2462306a36Sopenharmony_ci#include "tuner-i2c.h" 2562306a36Sopenharmony_ci#include "xc2028-types.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int debug; 2862306a36Sopenharmony_cimodule_param(debug, int, 0644); 2962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int no_poweroff; 3262306a36Sopenharmony_cimodule_param(no_poweroff, int, 0644); 3362306a36Sopenharmony_ciMODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, 0 (default): use device-specific default mode)."); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int audio_std; 3662306a36Sopenharmony_cimodule_param(audio_std, int, 0644); 3762306a36Sopenharmony_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" 3862306a36Sopenharmony_ci " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" 3962306a36Sopenharmony_ci " 2: use A2 instead of NICAM or BTSC\n" 4062306a36Sopenharmony_ci " 4: use SECAM/K3 instead of K1\n" 4162306a36Sopenharmony_ci " 8: use PAL-D/K audio for SECAM-D/K\n" 4262306a36Sopenharmony_ci "16: use FM radio input 1 instead of input 2\n" 4362306a36Sopenharmony_ci "32: use mono audio (the lower three bits are ignored)"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic char firmware_name[30]; 4662306a36Sopenharmony_cimodule_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); 4762306a36Sopenharmony_ciMODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the default firmware name."); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic DEFINE_MUTEX(xc4000_list_mutex); 5062306a36Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define dprintk(level, fmt, arg...) if (debug >= level) \ 5362306a36Sopenharmony_ci printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* struct for storing firmware table */ 5662306a36Sopenharmony_cistruct firmware_description { 5762306a36Sopenharmony_ci unsigned int type; 5862306a36Sopenharmony_ci v4l2_std_id id; 5962306a36Sopenharmony_ci __u16 int_freq; 6062306a36Sopenharmony_ci unsigned char *ptr; 6162306a36Sopenharmony_ci unsigned int size; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct firmware_properties { 6562306a36Sopenharmony_ci unsigned int type; 6662306a36Sopenharmony_ci v4l2_std_id id; 6762306a36Sopenharmony_ci v4l2_std_id std_req; 6862306a36Sopenharmony_ci __u16 int_freq; 6962306a36Sopenharmony_ci unsigned int scode_table; 7062306a36Sopenharmony_ci int scode_nr; 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct xc4000_priv { 7462306a36Sopenharmony_ci struct tuner_i2c_props i2c_props; 7562306a36Sopenharmony_ci struct list_head hybrid_tuner_instance_list; 7662306a36Sopenharmony_ci struct firmware_description *firm; 7762306a36Sopenharmony_ci int firm_size; 7862306a36Sopenharmony_ci u32 if_khz; 7962306a36Sopenharmony_ci u32 freq_hz, freq_offset; 8062306a36Sopenharmony_ci u32 bandwidth; 8162306a36Sopenharmony_ci u8 video_standard; 8262306a36Sopenharmony_ci u8 rf_mode; 8362306a36Sopenharmony_ci u8 default_pm; 8462306a36Sopenharmony_ci u8 dvb_amplitude; 8562306a36Sopenharmony_ci u8 set_smoothedcvbs; 8662306a36Sopenharmony_ci u8 ignore_i2c_write_errors; 8762306a36Sopenharmony_ci __u16 firm_version; 8862306a36Sopenharmony_ci struct firmware_properties cur_fw; 8962306a36Sopenharmony_ci __u16 hwmodel; 9062306a36Sopenharmony_ci __u16 hwvers; 9162306a36Sopenharmony_ci struct mutex lock; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define XC4000_AUDIO_STD_B 1 9562306a36Sopenharmony_ci#define XC4000_AUDIO_STD_A2 2 9662306a36Sopenharmony_ci#define XC4000_AUDIO_STD_K3 4 9762306a36Sopenharmony_ci#define XC4000_AUDIO_STD_L 8 9862306a36Sopenharmony_ci#define XC4000_AUDIO_STD_INPUT1 16 9962306a36Sopenharmony_ci#define XC4000_AUDIO_STD_MONO 32 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw" 10262306a36Sopenharmony_ci#define XC4000_DEFAULT_FIRMWARE_NEW "dvb-fe-xc4000-1.4.1.fw" 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Misc Defines */ 10562306a36Sopenharmony_ci#define MAX_TV_STANDARD 24 10662306a36Sopenharmony_ci#define XC_MAX_I2C_WRITE_LENGTH 64 10762306a36Sopenharmony_ci#define XC_POWERED_DOWN 0x80000000U 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* Signal Types */ 11062306a36Sopenharmony_ci#define XC_RF_MODE_AIR 0 11162306a36Sopenharmony_ci#define XC_RF_MODE_CABLE 1 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* Product id */ 11462306a36Sopenharmony_ci#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 11562306a36Sopenharmony_ci#define XC_PRODUCT_ID_XC4000 0x0FA0 11662306a36Sopenharmony_ci#define XC_PRODUCT_ID_XC4100 0x1004 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* Registers (Write-only) */ 11962306a36Sopenharmony_ci#define XREG_INIT 0x00 12062306a36Sopenharmony_ci#define XREG_VIDEO_MODE 0x01 12162306a36Sopenharmony_ci#define XREG_AUDIO_MODE 0x02 12262306a36Sopenharmony_ci#define XREG_RF_FREQ 0x03 12362306a36Sopenharmony_ci#define XREG_D_CODE 0x04 12462306a36Sopenharmony_ci#define XREG_DIRECTSITTING_MODE 0x05 12562306a36Sopenharmony_ci#define XREG_SEEK_MODE 0x06 12662306a36Sopenharmony_ci#define XREG_POWER_DOWN 0x08 12762306a36Sopenharmony_ci#define XREG_SIGNALSOURCE 0x0A 12862306a36Sopenharmony_ci#define XREG_SMOOTHEDCVBS 0x0E 12962306a36Sopenharmony_ci#define XREG_AMPLITUDE 0x10 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* Registers (Read-only) */ 13262306a36Sopenharmony_ci#define XREG_ADC_ENV 0x00 13362306a36Sopenharmony_ci#define XREG_QUALITY 0x01 13462306a36Sopenharmony_ci#define XREG_FRAME_LINES 0x02 13562306a36Sopenharmony_ci#define XREG_HSYNC_FREQ 0x03 13662306a36Sopenharmony_ci#define XREG_LOCK 0x04 13762306a36Sopenharmony_ci#define XREG_FREQ_ERROR 0x05 13862306a36Sopenharmony_ci#define XREG_SNR 0x06 13962306a36Sopenharmony_ci#define XREG_VERSION 0x07 14062306a36Sopenharmony_ci#define XREG_PRODUCT_ID 0x08 14162306a36Sopenharmony_ci#define XREG_SIGNAL_LEVEL 0x0A 14262306a36Sopenharmony_ci#define XREG_NOISE_LEVEL 0x0B 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci Basic firmware description. This will remain with 14662306a36Sopenharmony_ci the driver for documentation purposes. 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci This represents an I2C firmware file encoded as a 14962306a36Sopenharmony_ci string of unsigned char. Format is as follows: 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB 15262306a36Sopenharmony_ci char[1 ]=len0_LSB -> length of first write transaction 15362306a36Sopenharmony_ci char[2 ]=data0 -> first byte to be sent 15462306a36Sopenharmony_ci char[3 ]=data1 15562306a36Sopenharmony_ci char[4 ]=data2 15662306a36Sopenharmony_ci char[ ]=... 15762306a36Sopenharmony_ci char[M ]=dataN -> last byte to be sent 15862306a36Sopenharmony_ci char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB 15962306a36Sopenharmony_ci char[M+2]=len1_LSB -> length of second write transaction 16062306a36Sopenharmony_ci char[M+3]=data0 16162306a36Sopenharmony_ci char[M+4]=data1 16262306a36Sopenharmony_ci ... 16362306a36Sopenharmony_ci etc. 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci The [len] value should be interpreted as follows: 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci len= len_MSB _ len_LSB 16862306a36Sopenharmony_ci len=1111_1111_1111_1111 : End of I2C_SEQUENCE 16962306a36Sopenharmony_ci len=0000_0000_0000_0000 : Reset command: Do hardware reset 17062306a36Sopenharmony_ci len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) 17162306a36Sopenharmony_ci len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci For the RESET and WAIT commands, the two following bytes will contain 17462306a36Sopenharmony_ci immediately the length of the following transaction. 17562306a36Sopenharmony_ci*/ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistruct XC_TV_STANDARD { 17862306a36Sopenharmony_ci const char *Name; 17962306a36Sopenharmony_ci u16 audio_mode; 18062306a36Sopenharmony_ci u16 video_mode; 18162306a36Sopenharmony_ci u16 int_freq; 18262306a36Sopenharmony_ci}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* Tuner standards */ 18562306a36Sopenharmony_ci#define XC4000_MN_NTSC_PAL_BTSC 0 18662306a36Sopenharmony_ci#define XC4000_MN_NTSC_PAL_A2 1 18762306a36Sopenharmony_ci#define XC4000_MN_NTSC_PAL_EIAJ 2 18862306a36Sopenharmony_ci#define XC4000_MN_NTSC_PAL_Mono 3 18962306a36Sopenharmony_ci#define XC4000_BG_PAL_A2 4 19062306a36Sopenharmony_ci#define XC4000_BG_PAL_NICAM 5 19162306a36Sopenharmony_ci#define XC4000_BG_PAL_MONO 6 19262306a36Sopenharmony_ci#define XC4000_I_PAL_NICAM 7 19362306a36Sopenharmony_ci#define XC4000_I_PAL_NICAM_MONO 8 19462306a36Sopenharmony_ci#define XC4000_DK_PAL_A2 9 19562306a36Sopenharmony_ci#define XC4000_DK_PAL_NICAM 10 19662306a36Sopenharmony_ci#define XC4000_DK_PAL_MONO 11 19762306a36Sopenharmony_ci#define XC4000_DK_SECAM_A2DK1 12 19862306a36Sopenharmony_ci#define XC4000_DK_SECAM_A2LDK3 13 19962306a36Sopenharmony_ci#define XC4000_DK_SECAM_A2MONO 14 20062306a36Sopenharmony_ci#define XC4000_DK_SECAM_NICAM 15 20162306a36Sopenharmony_ci#define XC4000_L_SECAM_NICAM 16 20262306a36Sopenharmony_ci#define XC4000_LC_SECAM_NICAM 17 20362306a36Sopenharmony_ci#define XC4000_DTV6 18 20462306a36Sopenharmony_ci#define XC4000_DTV8 19 20562306a36Sopenharmony_ci#define XC4000_DTV7_8 20 20662306a36Sopenharmony_ci#define XC4000_DTV7 21 20762306a36Sopenharmony_ci#define XC4000_FM_Radio_INPUT2 22 20862306a36Sopenharmony_ci#define XC4000_FM_Radio_INPUT1 23 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = { 21162306a36Sopenharmony_ci {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500}, 21262306a36Sopenharmony_ci {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600}, 21362306a36Sopenharmony_ci {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500}, 21462306a36Sopenharmony_ci {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500}, 21562306a36Sopenharmony_ci {"B/G-PAL-A2", 0x0000, 0x8159, 5640}, 21662306a36Sopenharmony_ci {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740}, 21762306a36Sopenharmony_ci {"B/G-PAL-MONO", 0x0078, 0x8159, 5500}, 21862306a36Sopenharmony_ci {"I-PAL-NICAM", 0x0080, 0x8049, 6240}, 21962306a36Sopenharmony_ci {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000}, 22062306a36Sopenharmony_ci {"D/K-PAL-A2", 0x0000, 0x8049, 6380}, 22162306a36Sopenharmony_ci {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200}, 22262306a36Sopenharmony_ci {"D/K-PAL-MONO", 0x0078, 0x8049, 6500}, 22362306a36Sopenharmony_ci {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340}, 22462306a36Sopenharmony_ci {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000}, 22562306a36Sopenharmony_ci {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500}, 22662306a36Sopenharmony_ci {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200}, 22762306a36Sopenharmony_ci {"L-SECAM-NICAM", 0x8080, 0x0009, 6200}, 22862306a36Sopenharmony_ci {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200}, 22962306a36Sopenharmony_ci {"DTV6", 0x00C0, 0x8002, 0}, 23062306a36Sopenharmony_ci {"DTV8", 0x00C0, 0x800B, 0}, 23162306a36Sopenharmony_ci {"DTV7/8", 0x00C0, 0x801B, 0}, 23262306a36Sopenharmony_ci {"DTV7", 0x00C0, 0x8007, 0}, 23362306a36Sopenharmony_ci {"FM Radio-INPUT2", 0x0008, 0x9800, 10700}, 23462306a36Sopenharmony_ci {"FM Radio-INPUT1", 0x0008, 0x9000, 10700} 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val); 23862306a36Sopenharmony_cistatic int xc4000_tuner_reset(struct dvb_frontend *fe); 23962306a36Sopenharmony_cistatic void xc_debug_dump(struct xc4000_priv *priv); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_props.addr, 24462306a36Sopenharmony_ci .flags = 0, .buf = buf, .len = len }; 24562306a36Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { 24662306a36Sopenharmony_ci if (priv->ignore_i2c_write_errors == 0) { 24762306a36Sopenharmony_ci printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", 24862306a36Sopenharmony_ci len); 24962306a36Sopenharmony_ci if (len == 4) { 25062306a36Sopenharmony_ci printk(KERN_ERR "bytes %*ph\n", 4, buf); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci return -EREMOTEIO; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int xc4000_tuner_reset(struct dvb_frontend *fe) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 26162306a36Sopenharmony_ci int ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (fe->callback) { 26662306a36Sopenharmony_ci ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? 26762306a36Sopenharmony_ci fe->dvb->priv : 26862306a36Sopenharmony_ci priv->i2c_props.adap->algo_data, 26962306a36Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 27062306a36Sopenharmony_ci XC4000_TUNER_RESET, 0); 27162306a36Sopenharmony_ci if (ret) { 27262306a36Sopenharmony_ci printk(KERN_ERR "xc4000: reset failed\n"); 27362306a36Sopenharmony_ci return -EREMOTEIO; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci } else { 27662306a36Sopenharmony_ci printk(KERN_ERR "xc4000: no tuner reset callback function, fatal\n"); 27762306a36Sopenharmony_ci return -EINVAL; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci u8 buf[4]; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci buf[0] = (regAddr >> 8) & 0xFF; 28762306a36Sopenharmony_ci buf[1] = regAddr & 0xFF; 28862306a36Sopenharmony_ci buf[2] = (i2cData >> 8) & 0xFF; 28962306a36Sopenharmony_ci buf[3] = i2cData & 0xFF; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return xc_send_i2c_data(priv, buf, 4); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci int i, nbytes_to_send, result; 29962306a36Sopenharmony_ci unsigned int len, pos, index; 30062306a36Sopenharmony_ci u8 buf[XC_MAX_I2C_WRITE_LENGTH]; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci index = 0; 30362306a36Sopenharmony_ci while ((i2c_sequence[index] != 0xFF) || 30462306a36Sopenharmony_ci (i2c_sequence[index + 1] != 0xFF)) { 30562306a36Sopenharmony_ci len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; 30662306a36Sopenharmony_ci if (len == 0x0000) { 30762306a36Sopenharmony_ci /* RESET command */ 30862306a36Sopenharmony_ci /* NOTE: this is ignored, as the reset callback was */ 30962306a36Sopenharmony_ci /* already called by check_firmware() */ 31062306a36Sopenharmony_ci index += 2; 31162306a36Sopenharmony_ci } else if (len & 0x8000) { 31262306a36Sopenharmony_ci /* WAIT command */ 31362306a36Sopenharmony_ci msleep(len & 0x7FFF); 31462306a36Sopenharmony_ci index += 2; 31562306a36Sopenharmony_ci } else { 31662306a36Sopenharmony_ci /* Send i2c data whilst ensuring individual transactions 31762306a36Sopenharmony_ci * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci index += 2; 32062306a36Sopenharmony_ci buf[0] = i2c_sequence[index]; 32162306a36Sopenharmony_ci buf[1] = i2c_sequence[index + 1]; 32262306a36Sopenharmony_ci pos = 2; 32362306a36Sopenharmony_ci while (pos < len) { 32462306a36Sopenharmony_ci if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) 32562306a36Sopenharmony_ci nbytes_to_send = 32662306a36Sopenharmony_ci XC_MAX_I2C_WRITE_LENGTH; 32762306a36Sopenharmony_ci else 32862306a36Sopenharmony_ci nbytes_to_send = (len - pos + 2); 32962306a36Sopenharmony_ci for (i = 2; i < nbytes_to_send; i++) { 33062306a36Sopenharmony_ci buf[i] = i2c_sequence[index + pos + 33162306a36Sopenharmony_ci i - 2]; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci result = xc_send_i2c_data(priv, buf, 33462306a36Sopenharmony_ci nbytes_to_send); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (result != 0) 33762306a36Sopenharmony_ci return result; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci pos += nbytes_to_send - 2; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci index += len; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int xc_set_tv_standard(struct xc4000_priv *priv, 34862306a36Sopenharmony_ci u16 video_mode, u16 audio_mode) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int ret; 35162306a36Sopenharmony_ci dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); 35262306a36Sopenharmony_ci dprintk(1, "%s() Standard = %s\n", 35362306a36Sopenharmony_ci __func__, 35462306a36Sopenharmony_ci xc4000_standard[priv->video_standard].Name); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Don't complain when the request fails because of i2c stretching */ 35762306a36Sopenharmony_ci priv->ignore_i2c_write_errors = 1; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); 36062306a36Sopenharmony_ci if (ret == 0) 36162306a36Sopenharmony_ci ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci priv->ignore_i2c_write_errors = 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return ret; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, 37162306a36Sopenharmony_ci rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { 37462306a36Sopenharmony_ci rf_mode = XC_RF_MODE_CABLE; 37562306a36Sopenharmony_ci printk(KERN_ERR 37662306a36Sopenharmony_ci "%s(), Invalid mode, defaulting to CABLE", 37762306a36Sopenharmony_ci __func__); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic const struct dvb_tuner_ops xc4000_tuner_ops; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci u16 freq_code; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci dprintk(1, "%s(%u)\n", __func__, freq_hz); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if ((freq_hz > xc4000_tuner_ops.info.frequency_max_hz) || 39162306a36Sopenharmony_ci (freq_hz < xc4000_tuner_ops.info.frequency_min_hz)) 39262306a36Sopenharmony_ci return -EINVAL; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci freq_code = (u16)(freq_hz / 15625); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the 39762306a36Sopenharmony_ci FINERFREQ for all normal tuning (the doc indicates reg 0x03 should 39862306a36Sopenharmony_ci only be used for fast scanning for channel lock) */ 39962306a36Sopenharmony_ci /* WAS: XREG_FINERFREQ */ 40062306a36Sopenharmony_ci return xc_write_reg(priv, XREG_RF_FREQ, freq_code); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci int result; 41162306a36Sopenharmony_ci u16 regData; 41262306a36Sopenharmony_ci u32 tmp; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci result = xc4000_readreg(priv, XREG_FREQ_ERROR, ®Data); 41562306a36Sopenharmony_ci if (result != 0) 41662306a36Sopenharmony_ci return result; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci tmp = (u32)regData & 0xFFFFU; 41962306a36Sopenharmony_ci tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp); 42062306a36Sopenharmony_ci (*freq_error_hz) = tmp * 15625; 42162306a36Sopenharmony_ci return result; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci return xc4000_readreg(priv, XREG_LOCK, lock_status); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic int xc_get_version(struct xc4000_priv *priv, 43062306a36Sopenharmony_ci u8 *hw_majorversion, u8 *hw_minorversion, 43162306a36Sopenharmony_ci u8 *fw_majorversion, u8 *fw_minorversion) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci u16 data; 43462306a36Sopenharmony_ci int result; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci result = xc4000_readreg(priv, XREG_VERSION, &data); 43762306a36Sopenharmony_ci if (result != 0) 43862306a36Sopenharmony_ci return result; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci (*hw_majorversion) = (data >> 12) & 0x0F; 44162306a36Sopenharmony_ci (*hw_minorversion) = (data >> 8) & 0x0F; 44262306a36Sopenharmony_ci (*fw_majorversion) = (data >> 4) & 0x0F; 44362306a36Sopenharmony_ci (*fw_minorversion) = data & 0x0F; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci u16 regData; 45162306a36Sopenharmony_ci int result; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci result = xc4000_readreg(priv, XREG_HSYNC_FREQ, ®Data); 45462306a36Sopenharmony_ci if (result != 0) 45562306a36Sopenharmony_ci return result; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; 45862306a36Sopenharmony_ci return result; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int xc_get_quality(struct xc4000_priv *priv, u16 *quality) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci return xc4000_readreg(priv, XREG_QUALITY, quality); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic u16 xc_wait_for_lock(struct xc4000_priv *priv) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci u16 lock_state = 0; 48462306a36Sopenharmony_ci int watchdog_count = 40; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci while ((lock_state == 0) && (watchdog_count > 0)) { 48762306a36Sopenharmony_ci xc_get_lock_status(priv, &lock_state); 48862306a36Sopenharmony_ci if (lock_state != 1) { 48962306a36Sopenharmony_ci msleep(5); 49062306a36Sopenharmony_ci watchdog_count--; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci return lock_state; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci int found = 1; 49962306a36Sopenharmony_ci int result; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci dprintk(1, "%s(%u)\n", __func__, freq_hz); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Don't complain when the request fails because of i2c stretching */ 50462306a36Sopenharmony_ci priv->ignore_i2c_write_errors = 1; 50562306a36Sopenharmony_ci result = xc_set_rf_frequency(priv, freq_hz); 50662306a36Sopenharmony_ci priv->ignore_i2c_write_errors = 0; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (result != 0) 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* wait for lock only in analog TV mode */ 51262306a36Sopenharmony_ci if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) { 51362306a36Sopenharmony_ci if (xc_wait_for_lock(priv) != 1) 51462306a36Sopenharmony_ci found = 0; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* Wait for stats to stabilize. 51862306a36Sopenharmony_ci * Frame Lines needs two frame times after initial lock 51962306a36Sopenharmony_ci * before it is valid. 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_ci msleep(debug ? 100 : 10); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (debug) 52462306a36Sopenharmony_ci xc_debug_dump(priv); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return found; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci u8 buf[2] = { reg >> 8, reg & 0xff }; 53262306a36Sopenharmony_ci u8 bval[2] = { 0, 0 }; 53362306a36Sopenharmony_ci struct i2c_msg msg[2] = { 53462306a36Sopenharmony_ci { .addr = priv->i2c_props.addr, 53562306a36Sopenharmony_ci .flags = 0, .buf = &buf[0], .len = 2 }, 53662306a36Sopenharmony_ci { .addr = priv->i2c_props.addr, 53762306a36Sopenharmony_ci .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, 53862306a36Sopenharmony_ci }; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { 54162306a36Sopenharmony_ci printk(KERN_ERR "xc4000: I2C read failed\n"); 54262306a36Sopenharmony_ci return -EREMOTEIO; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci *val = (bval[0] << 8) | bval[1]; 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) 55062306a36Sopenharmony_cistatic void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci if (type & BASE) 55362306a36Sopenharmony_ci printk(KERN_CONT "BASE "); 55462306a36Sopenharmony_ci if (type & INIT1) 55562306a36Sopenharmony_ci printk(KERN_CONT "INIT1 "); 55662306a36Sopenharmony_ci if (type & F8MHZ) 55762306a36Sopenharmony_ci printk(KERN_CONT "F8MHZ "); 55862306a36Sopenharmony_ci if (type & MTS) 55962306a36Sopenharmony_ci printk(KERN_CONT "MTS "); 56062306a36Sopenharmony_ci if (type & D2620) 56162306a36Sopenharmony_ci printk(KERN_CONT "D2620 "); 56262306a36Sopenharmony_ci if (type & D2633) 56362306a36Sopenharmony_ci printk(KERN_CONT "D2633 "); 56462306a36Sopenharmony_ci if (type & DTV6) 56562306a36Sopenharmony_ci printk(KERN_CONT "DTV6 "); 56662306a36Sopenharmony_ci if (type & QAM) 56762306a36Sopenharmony_ci printk(KERN_CONT "QAM "); 56862306a36Sopenharmony_ci if (type & DTV7) 56962306a36Sopenharmony_ci printk(KERN_CONT "DTV7 "); 57062306a36Sopenharmony_ci if (type & DTV78) 57162306a36Sopenharmony_ci printk(KERN_CONT "DTV78 "); 57262306a36Sopenharmony_ci if (type & DTV8) 57362306a36Sopenharmony_ci printk(KERN_CONT "DTV8 "); 57462306a36Sopenharmony_ci if (type & FM) 57562306a36Sopenharmony_ci printk(KERN_CONT "FM "); 57662306a36Sopenharmony_ci if (type & INPUT1) 57762306a36Sopenharmony_ci printk(KERN_CONT "INPUT1 "); 57862306a36Sopenharmony_ci if (type & LCD) 57962306a36Sopenharmony_ci printk(KERN_CONT "LCD "); 58062306a36Sopenharmony_ci if (type & NOGD) 58162306a36Sopenharmony_ci printk(KERN_CONT "NOGD "); 58262306a36Sopenharmony_ci if (type & MONO) 58362306a36Sopenharmony_ci printk(KERN_CONT "MONO "); 58462306a36Sopenharmony_ci if (type & ATSC) 58562306a36Sopenharmony_ci printk(KERN_CONT "ATSC "); 58662306a36Sopenharmony_ci if (type & IF) 58762306a36Sopenharmony_ci printk(KERN_CONT "IF "); 58862306a36Sopenharmony_ci if (type & LG60) 58962306a36Sopenharmony_ci printk(KERN_CONT "LG60 "); 59062306a36Sopenharmony_ci if (type & ATI638) 59162306a36Sopenharmony_ci printk(KERN_CONT "ATI638 "); 59262306a36Sopenharmony_ci if (type & OREN538) 59362306a36Sopenharmony_ci printk(KERN_CONT "OREN538 "); 59462306a36Sopenharmony_ci if (type & OREN36) 59562306a36Sopenharmony_ci printk(KERN_CONT "OREN36 "); 59662306a36Sopenharmony_ci if (type & TOYOTA388) 59762306a36Sopenharmony_ci printk(KERN_CONT "TOYOTA388 "); 59862306a36Sopenharmony_ci if (type & TOYOTA794) 59962306a36Sopenharmony_ci printk(KERN_CONT "TOYOTA794 "); 60062306a36Sopenharmony_ci if (type & DIBCOM52) 60162306a36Sopenharmony_ci printk(KERN_CONT "DIBCOM52 "); 60262306a36Sopenharmony_ci if (type & ZARLINK456) 60362306a36Sopenharmony_ci printk(KERN_CONT "ZARLINK456 "); 60462306a36Sopenharmony_ci if (type & CHINA) 60562306a36Sopenharmony_ci printk(KERN_CONT "CHINA "); 60662306a36Sopenharmony_ci if (type & F6MHZ) 60762306a36Sopenharmony_ci printk(KERN_CONT "F6MHZ "); 60862306a36Sopenharmony_ci if (type & INPUT2) 60962306a36Sopenharmony_ci printk(KERN_CONT "INPUT2 "); 61062306a36Sopenharmony_ci if (type & SCODE) 61162306a36Sopenharmony_ci printk(KERN_CONT "SCODE "); 61262306a36Sopenharmony_ci if (type & HAS_IF) 61362306a36Sopenharmony_ci printk(KERN_CONT "HAS_IF_%d ", int_freq); 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic int seek_firmware(struct dvb_frontend *fe, unsigned int type, 61762306a36Sopenharmony_ci v4l2_std_id *id) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 62062306a36Sopenharmony_ci int i, best_i = -1; 62162306a36Sopenharmony_ci unsigned int best_nr_diffs = 255U; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (!priv->firm) { 62462306a36Sopenharmony_ci printk(KERN_ERR "Error! firmware not loaded\n"); 62562306a36Sopenharmony_ci return -EINVAL; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (((type & ~SCODE) == 0) && (*id == 0)) 62962306a36Sopenharmony_ci *id = V4L2_STD_PAL; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* Seek for generic video standard match */ 63262306a36Sopenharmony_ci for (i = 0; i < priv->firm_size; i++) { 63362306a36Sopenharmony_ci v4l2_std_id id_diff_mask = 63462306a36Sopenharmony_ci (priv->firm[i].id ^ (*id)) & (*id); 63562306a36Sopenharmony_ci unsigned int type_diff_mask = 63662306a36Sopenharmony_ci (priv->firm[i].type ^ type) 63762306a36Sopenharmony_ci & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE); 63862306a36Sopenharmony_ci unsigned int nr_diffs; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (type_diff_mask 64162306a36Sopenharmony_ci & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE)) 64262306a36Sopenharmony_ci continue; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask); 64562306a36Sopenharmony_ci if (!nr_diffs) /* Supports all the requested standards */ 64662306a36Sopenharmony_ci goto found; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (nr_diffs < best_nr_diffs) { 64962306a36Sopenharmony_ci best_nr_diffs = nr_diffs; 65062306a36Sopenharmony_ci best_i = i; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* FIXME: Would make sense to seek for type "hint" match ? */ 65562306a36Sopenharmony_ci if (best_i < 0) { 65662306a36Sopenharmony_ci i = -ENOENT; 65762306a36Sopenharmony_ci goto ret; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (best_nr_diffs > 0U) { 66162306a36Sopenharmony_ci printk(KERN_WARNING 66262306a36Sopenharmony_ci "Selecting best matching firmware (%u bits differ) for type=(%x), id %016llx:\n", 66362306a36Sopenharmony_ci best_nr_diffs, type, (unsigned long long)*id); 66462306a36Sopenharmony_ci i = best_i; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cifound: 66862306a36Sopenharmony_ci *id = priv->firm[i].id; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ciret: 67162306a36Sopenharmony_ci if (debug) { 67262306a36Sopenharmony_ci printk(KERN_DEBUG "%s firmware for type=", 67362306a36Sopenharmony_ci (i < 0) ? "Can't find" : "Found"); 67462306a36Sopenharmony_ci dump_firm_type(type); 67562306a36Sopenharmony_ci printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci return i; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic int load_firmware(struct dvb_frontend *fe, unsigned int type, 68162306a36Sopenharmony_ci v4l2_std_id *id) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 68462306a36Sopenharmony_ci int pos, rc; 68562306a36Sopenharmony_ci unsigned char *p; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci pos = seek_firmware(fe, type, id); 68862306a36Sopenharmony_ci if (pos < 0) 68962306a36Sopenharmony_ci return pos; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci p = priv->firm[pos].ptr; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* Don't complain when the request fails because of i2c stretching */ 69462306a36Sopenharmony_ci priv->ignore_i2c_write_errors = 1; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci rc = xc_load_i2c_sequence(fe, p); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci priv->ignore_i2c_write_errors = 0; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci return rc; 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic int xc4000_fwupload(struct dvb_frontend *fe) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 70662306a36Sopenharmony_ci const struct firmware *fw = NULL; 70762306a36Sopenharmony_ci const unsigned char *p, *endp; 70862306a36Sopenharmony_ci int rc = 0; 70962306a36Sopenharmony_ci int n, n_array; 71062306a36Sopenharmony_ci char name[33]; 71162306a36Sopenharmony_ci const char *fname; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (firmware_name[0] != '\0') { 71462306a36Sopenharmony_ci fname = firmware_name; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci dprintk(1, "Reading custom firmware %s\n", fname); 71762306a36Sopenharmony_ci rc = request_firmware(&fw, fname, 71862306a36Sopenharmony_ci priv->i2c_props.adap->dev.parent); 71962306a36Sopenharmony_ci } else { 72062306a36Sopenharmony_ci fname = XC4000_DEFAULT_FIRMWARE_NEW; 72162306a36Sopenharmony_ci dprintk(1, "Trying to read firmware %s\n", fname); 72262306a36Sopenharmony_ci rc = request_firmware(&fw, fname, 72362306a36Sopenharmony_ci priv->i2c_props.adap->dev.parent); 72462306a36Sopenharmony_ci if (rc == -ENOENT) { 72562306a36Sopenharmony_ci fname = XC4000_DEFAULT_FIRMWARE; 72662306a36Sopenharmony_ci dprintk(1, "Trying to read firmware %s\n", fname); 72762306a36Sopenharmony_ci rc = request_firmware(&fw, fname, 72862306a36Sopenharmony_ci priv->i2c_props.adap->dev.parent); 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (rc < 0) { 73362306a36Sopenharmony_ci if (rc == -ENOENT) 73462306a36Sopenharmony_ci printk(KERN_ERR "Error: firmware %s not found.\n", fname); 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci printk(KERN_ERR "Error %d while requesting firmware %s\n", 73762306a36Sopenharmony_ci rc, fname); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci return rc; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci dprintk(1, "Loading Firmware: %s\n", fname); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci p = fw->data; 74462306a36Sopenharmony_ci endp = p + fw->size; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (fw->size < sizeof(name) - 1 + 2 + 2) { 74762306a36Sopenharmony_ci printk(KERN_ERR "Error: firmware file %s has invalid size!\n", 74862306a36Sopenharmony_ci fname); 74962306a36Sopenharmony_ci goto corrupt; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci memcpy(name, p, sizeof(name) - 1); 75362306a36Sopenharmony_ci name[sizeof(name) - 1] = '\0'; 75462306a36Sopenharmony_ci p += sizeof(name) - 1; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci priv->firm_version = get_unaligned_le16(p); 75762306a36Sopenharmony_ci p += 2; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci n_array = get_unaligned_le16(p); 76062306a36Sopenharmony_ci p += 2; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n", 76362306a36Sopenharmony_ci n_array, fname, name, 76462306a36Sopenharmony_ci priv->firm_version >> 8, priv->firm_version & 0xff); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); 76762306a36Sopenharmony_ci if (priv->firm == NULL) { 76862306a36Sopenharmony_ci printk(KERN_ERR "Not enough memory to load firmware file.\n"); 76962306a36Sopenharmony_ci rc = -ENOMEM; 77062306a36Sopenharmony_ci goto done; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci priv->firm_size = n_array; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci n = -1; 77562306a36Sopenharmony_ci while (p < endp) { 77662306a36Sopenharmony_ci __u32 type, size; 77762306a36Sopenharmony_ci v4l2_std_id id; 77862306a36Sopenharmony_ci __u16 int_freq = 0; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci n++; 78162306a36Sopenharmony_ci if (n >= n_array) { 78262306a36Sopenharmony_ci printk(KERN_ERR "More firmware images in file than were expected!\n"); 78362306a36Sopenharmony_ci goto corrupt; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* Checks if there's enough bytes to read */ 78762306a36Sopenharmony_ci if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) 78862306a36Sopenharmony_ci goto header; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci type = get_unaligned_le32(p); 79162306a36Sopenharmony_ci p += sizeof(type); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci id = get_unaligned_le64(p); 79462306a36Sopenharmony_ci p += sizeof(id); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (type & HAS_IF) { 79762306a36Sopenharmony_ci int_freq = get_unaligned_le16(p); 79862306a36Sopenharmony_ci p += sizeof(int_freq); 79962306a36Sopenharmony_ci if (endp - p < sizeof(size)) 80062306a36Sopenharmony_ci goto header; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci size = get_unaligned_le32(p); 80462306a36Sopenharmony_ci p += sizeof(size); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (!size || size > endp - p) { 80762306a36Sopenharmony_ci printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%zd, expected %d)\n", 80862306a36Sopenharmony_ci type, (unsigned long long)id, 80962306a36Sopenharmony_ci endp - p, size); 81062306a36Sopenharmony_ci goto corrupt; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci priv->firm[n].ptr = kmemdup(p, size, GFP_KERNEL); 81462306a36Sopenharmony_ci if (priv->firm[n].ptr == NULL) { 81562306a36Sopenharmony_ci printk(KERN_ERR "Not enough memory to load firmware file.\n"); 81662306a36Sopenharmony_ci rc = -ENOMEM; 81762306a36Sopenharmony_ci goto done; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (debug) { 82162306a36Sopenharmony_ci printk(KERN_DEBUG "Reading firmware type "); 82262306a36Sopenharmony_ci dump_firm_type_and_int_freq(type, int_freq); 82362306a36Sopenharmony_ci printk(KERN_DEBUG "(%x), id %llx, size=%d.\n", 82462306a36Sopenharmony_ci type, (unsigned long long)id, size); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci priv->firm[n].type = type; 82862306a36Sopenharmony_ci priv->firm[n].id = id; 82962306a36Sopenharmony_ci priv->firm[n].size = size; 83062306a36Sopenharmony_ci priv->firm[n].int_freq = int_freq; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci p += size; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (n + 1 != priv->firm_size) { 83662306a36Sopenharmony_ci printk(KERN_ERR "Firmware file is incomplete!\n"); 83762306a36Sopenharmony_ci goto corrupt; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci goto done; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ciheader: 84362306a36Sopenharmony_ci printk(KERN_ERR "Firmware header is incomplete!\n"); 84462306a36Sopenharmony_cicorrupt: 84562306a36Sopenharmony_ci rc = -EINVAL; 84662306a36Sopenharmony_ci printk(KERN_ERR "Error: firmware file is corrupted!\n"); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cidone: 84962306a36Sopenharmony_ci release_firmware(fw); 85062306a36Sopenharmony_ci if (rc == 0) 85162306a36Sopenharmony_ci dprintk(1, "Firmware files loaded.\n"); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci return rc; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_cistatic int load_scode(struct dvb_frontend *fe, unsigned int type, 85762306a36Sopenharmony_ci v4l2_std_id *id, __u16 int_freq, int scode) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 86062306a36Sopenharmony_ci int pos, rc; 86162306a36Sopenharmony_ci unsigned char *p; 86262306a36Sopenharmony_ci u8 scode_buf[13]; 86362306a36Sopenharmony_ci u8 indirect_mode[5]; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci dprintk(1, "%s called int_freq=%d\n", __func__, int_freq); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (!int_freq) { 86862306a36Sopenharmony_ci pos = seek_firmware(fe, type, id); 86962306a36Sopenharmony_ci if (pos < 0) 87062306a36Sopenharmony_ci return pos; 87162306a36Sopenharmony_ci } else { 87262306a36Sopenharmony_ci for (pos = 0; pos < priv->firm_size; pos++) { 87362306a36Sopenharmony_ci if ((priv->firm[pos].int_freq == int_freq) && 87462306a36Sopenharmony_ci (priv->firm[pos].type & HAS_IF)) 87562306a36Sopenharmony_ci break; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci if (pos == priv->firm_size) 87862306a36Sopenharmony_ci return -ENOENT; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci p = priv->firm[pos].ptr; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (priv->firm[pos].size != 12 * 16 || scode >= 16) 88462306a36Sopenharmony_ci return -EINVAL; 88562306a36Sopenharmony_ci p += 12 * scode; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (debug) { 88862306a36Sopenharmony_ci tuner_info("Loading SCODE for type="); 88962306a36Sopenharmony_ci dump_firm_type_and_int_freq(priv->firm[pos].type, 89062306a36Sopenharmony_ci priv->firm[pos].int_freq); 89162306a36Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, 89262306a36Sopenharmony_ci (unsigned long long)*id); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci scode_buf[0] = 0x00; 89662306a36Sopenharmony_ci memcpy(&scode_buf[1], p, 12); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci /* Enter direct-mode */ 89962306a36Sopenharmony_ci rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0); 90062306a36Sopenharmony_ci if (rc < 0) { 90162306a36Sopenharmony_ci printk(KERN_ERR "failed to put device into direct mode!\n"); 90262306a36Sopenharmony_ci return -EIO; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci rc = xc_send_i2c_data(priv, scode_buf, 13); 90662306a36Sopenharmony_ci if (rc != 0) { 90762306a36Sopenharmony_ci /* Even if the send failed, make sure we set back to indirect 90862306a36Sopenharmony_ci mode */ 90962306a36Sopenharmony_ci printk(KERN_ERR "Failed to set scode %d\n", rc); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* Switch back to indirect-mode */ 91362306a36Sopenharmony_ci memset(indirect_mode, 0, sizeof(indirect_mode)); 91462306a36Sopenharmony_ci indirect_mode[4] = 0x88; 91562306a36Sopenharmony_ci xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode)); 91662306a36Sopenharmony_ci msleep(10); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci return 0; 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistatic int check_firmware(struct dvb_frontend *fe, unsigned int type, 92262306a36Sopenharmony_ci v4l2_std_id std, __u16 int_freq) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 92562306a36Sopenharmony_ci struct firmware_properties new_fw; 92662306a36Sopenharmony_ci int rc = 0, is_retry = 0; 92762306a36Sopenharmony_ci u16 hwmodel; 92862306a36Sopenharmony_ci v4l2_std_id std0; 92962306a36Sopenharmony_ci u8 hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci dprintk(1, "%s called\n", __func__); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (!priv->firm) { 93462306a36Sopenharmony_ci rc = xc4000_fwupload(fe); 93562306a36Sopenharmony_ci if (rc < 0) 93662306a36Sopenharmony_ci return rc; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ciretry: 94062306a36Sopenharmony_ci new_fw.type = type; 94162306a36Sopenharmony_ci new_fw.id = std; 94262306a36Sopenharmony_ci new_fw.std_req = std; 94362306a36Sopenharmony_ci new_fw.scode_table = SCODE; 94462306a36Sopenharmony_ci new_fw.scode_nr = 0; 94562306a36Sopenharmony_ci new_fw.int_freq = int_freq; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci dprintk(1, "checking firmware, user requested type="); 94862306a36Sopenharmony_ci if (debug) { 94962306a36Sopenharmony_ci dump_firm_type(new_fw.type); 95062306a36Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, 95162306a36Sopenharmony_ci (unsigned long long)new_fw.std_req); 95262306a36Sopenharmony_ci if (!int_freq) 95362306a36Sopenharmony_ci printk(KERN_CONT "scode_tbl "); 95462306a36Sopenharmony_ci else 95562306a36Sopenharmony_ci printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); 95662306a36Sopenharmony_ci printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* No need to reload base firmware if it matches */ 96062306a36Sopenharmony_ci if (priv->cur_fw.type & BASE) { 96162306a36Sopenharmony_ci dprintk(1, "BASE firmware not changed.\n"); 96262306a36Sopenharmony_ci goto skip_base; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* Updating BASE - forget about all currently loaded firmware */ 96662306a36Sopenharmony_ci memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* Reset is needed before loading firmware */ 96962306a36Sopenharmony_ci rc = xc4000_tuner_reset(fe); 97062306a36Sopenharmony_ci if (rc < 0) 97162306a36Sopenharmony_ci goto fail; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* BASE firmwares are all std0 */ 97462306a36Sopenharmony_ci std0 = 0; 97562306a36Sopenharmony_ci rc = load_firmware(fe, BASE, &std0); 97662306a36Sopenharmony_ci if (rc < 0) { 97762306a36Sopenharmony_ci printk(KERN_ERR "Error %d while loading base firmware\n", rc); 97862306a36Sopenharmony_ci goto fail; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* Load INIT1, if needed */ 98262306a36Sopenharmony_ci dprintk(1, "Load init1 firmware, if exists\n"); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci rc = load_firmware(fe, BASE | INIT1, &std0); 98562306a36Sopenharmony_ci if (rc == -ENOENT) 98662306a36Sopenharmony_ci rc = load_firmware(fe, BASE | INIT1, &std0); 98762306a36Sopenharmony_ci if (rc < 0 && rc != -ENOENT) { 98862306a36Sopenharmony_ci tuner_err("Error %d while loading init1 firmware\n", 98962306a36Sopenharmony_ci rc); 99062306a36Sopenharmony_ci goto fail; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ciskip_base: 99462306a36Sopenharmony_ci /* 99562306a36Sopenharmony_ci * No need to reload standard specific firmware if base firmware 99662306a36Sopenharmony_ci * was not reloaded and requested video standards have not changed. 99762306a36Sopenharmony_ci */ 99862306a36Sopenharmony_ci if (priv->cur_fw.type == (BASE | new_fw.type) && 99962306a36Sopenharmony_ci priv->cur_fw.std_req == std) { 100062306a36Sopenharmony_ci dprintk(1, "Std-specific firmware already loaded.\n"); 100162306a36Sopenharmony_ci goto skip_std_specific; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* Reloading std-specific firmware forces a SCODE update */ 100562306a36Sopenharmony_ci priv->cur_fw.scode_table = 0; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci /* Load the standard firmware */ 100862306a36Sopenharmony_ci rc = load_firmware(fe, new_fw.type, &new_fw.id); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (rc < 0) 101162306a36Sopenharmony_ci goto fail; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ciskip_std_specific: 101462306a36Sopenharmony_ci if (priv->cur_fw.scode_table == new_fw.scode_table && 101562306a36Sopenharmony_ci priv->cur_fw.scode_nr == new_fw.scode_nr) { 101662306a36Sopenharmony_ci dprintk(1, "SCODE firmware already loaded.\n"); 101762306a36Sopenharmony_ci goto check_device; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* Load SCODE firmware, if exists */ 102162306a36Sopenharmony_ci rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, 102262306a36Sopenharmony_ci new_fw.int_freq, new_fw.scode_nr); 102362306a36Sopenharmony_ci if (rc != 0) 102462306a36Sopenharmony_ci dprintk(1, "load scode failed %d\n", rc); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cicheck_device: 102762306a36Sopenharmony_ci if (xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel) < 0) { 102862306a36Sopenharmony_ci printk(KERN_ERR "Unable to read tuner registers.\n"); 102962306a36Sopenharmony_ci goto fail; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, 103362306a36Sopenharmony_ci &fw_minor) != 0) { 103462306a36Sopenharmony_ci printk(KERN_ERR "Unable to read tuner registers.\n"); 103562306a36Sopenharmony_ci goto fail; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci dprintk(1, "Device is Xceive %d version %d.%d, firmware version %d.%d\n", 103962306a36Sopenharmony_ci hwmodel, hw_major, hw_minor, fw_major, fw_minor); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* Check firmware version against what we downloaded. */ 104262306a36Sopenharmony_ci if (priv->firm_version != ((fw_major << 8) | fw_minor)) { 104362306a36Sopenharmony_ci printk(KERN_WARNING 104462306a36Sopenharmony_ci "Incorrect readback of firmware version %d.%d.\n", 104562306a36Sopenharmony_ci fw_major, fw_minor); 104662306a36Sopenharmony_ci goto fail; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* Check that the tuner hardware model remains consistent over time. */ 105062306a36Sopenharmony_ci if (priv->hwmodel == 0 && 105162306a36Sopenharmony_ci (hwmodel == XC_PRODUCT_ID_XC4000 || 105262306a36Sopenharmony_ci hwmodel == XC_PRODUCT_ID_XC4100)) { 105362306a36Sopenharmony_ci priv->hwmodel = hwmodel; 105462306a36Sopenharmony_ci priv->hwvers = (hw_major << 8) | hw_minor; 105562306a36Sopenharmony_ci } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || 105662306a36Sopenharmony_ci priv->hwvers != ((hw_major << 8) | hw_minor)) { 105762306a36Sopenharmony_ci printk(KERN_WARNING 105862306a36Sopenharmony_ci "Read invalid device hardware information - tuner hung?\n"); 105962306a36Sopenharmony_ci goto fail; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci priv->cur_fw = new_fw; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci /* 106562306a36Sopenharmony_ci * By setting BASE in cur_fw.type only after successfully loading all 106662306a36Sopenharmony_ci * firmwares, we can: 106762306a36Sopenharmony_ci * 1. Identify that BASE firmware with type=0 has been loaded; 106862306a36Sopenharmony_ci * 2. Tell whether BASE firmware was just changed the next time through. 106962306a36Sopenharmony_ci */ 107062306a36Sopenharmony_ci priv->cur_fw.type |= BASE; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci return 0; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cifail: 107562306a36Sopenharmony_ci memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); 107662306a36Sopenharmony_ci if (!is_retry) { 107762306a36Sopenharmony_ci msleep(50); 107862306a36Sopenharmony_ci is_retry = 1; 107962306a36Sopenharmony_ci dprintk(1, "Retrying firmware load\n"); 108062306a36Sopenharmony_ci goto retry; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (rc == -ENOENT) 108462306a36Sopenharmony_ci rc = -EINVAL; 108562306a36Sopenharmony_ci return rc; 108662306a36Sopenharmony_ci} 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_cistatic void xc_debug_dump(struct xc4000_priv *priv) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci u16 adc_envelope; 109162306a36Sopenharmony_ci u32 freq_error_hz = 0; 109262306a36Sopenharmony_ci u16 lock_status; 109362306a36Sopenharmony_ci u32 hsync_freq_hz = 0; 109462306a36Sopenharmony_ci u16 frame_lines; 109562306a36Sopenharmony_ci u16 quality; 109662306a36Sopenharmony_ci u16 signal = 0; 109762306a36Sopenharmony_ci u16 noise = 0; 109862306a36Sopenharmony_ci u8 hw_majorversion = 0, hw_minorversion = 0; 109962306a36Sopenharmony_ci u8 fw_majorversion = 0, fw_minorversion = 0; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci xc_get_adc_envelope(priv, &adc_envelope); 110262306a36Sopenharmony_ci dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci xc_get_frequency_error(priv, &freq_error_hz); 110562306a36Sopenharmony_ci dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci xc_get_lock_status(priv, &lock_status); 110862306a36Sopenharmony_ci dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", 110962306a36Sopenharmony_ci lock_status); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci xc_get_version(priv, &hw_majorversion, &hw_minorversion, 111262306a36Sopenharmony_ci &fw_majorversion, &fw_minorversion); 111362306a36Sopenharmony_ci dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", 111462306a36Sopenharmony_ci hw_majorversion, hw_minorversion, 111562306a36Sopenharmony_ci fw_majorversion, fw_minorversion); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (priv->video_standard < XC4000_DTV6) { 111862306a36Sopenharmony_ci xc_get_hsync_freq(priv, &hsync_freq_hz); 111962306a36Sopenharmony_ci dprintk(1, "*** Horizontal sync frequency = %d Hz\n", 112062306a36Sopenharmony_ci hsync_freq_hz); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci xc_get_frame_lines(priv, &frame_lines); 112362306a36Sopenharmony_ci dprintk(1, "*** Frame lines = %d\n", frame_lines); 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci xc_get_quality(priv, &quality); 112762306a36Sopenharmony_ci dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci xc_get_signal_level(priv, &signal); 113062306a36Sopenharmony_ci dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci xc_get_noise_level(priv, &noise); 113362306a36Sopenharmony_ci dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cistatic int xc4000_set_params(struct dvb_frontend *fe) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 113962306a36Sopenharmony_ci u32 delsys = c->delivery_system; 114062306a36Sopenharmony_ci u32 bw = c->bandwidth_hz; 114162306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 114262306a36Sopenharmony_ci unsigned int type; 114362306a36Sopenharmony_ci int ret = -EREMOTEIO; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci mutex_lock(&priv->lock); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci switch (delsys) { 115062306a36Sopenharmony_ci case SYS_ATSC: 115162306a36Sopenharmony_ci dprintk(1, "%s() VSB modulation\n", __func__); 115262306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 115362306a36Sopenharmony_ci priv->freq_offset = 1750000; 115462306a36Sopenharmony_ci priv->video_standard = XC4000_DTV6; 115562306a36Sopenharmony_ci type = DTV6; 115662306a36Sopenharmony_ci break; 115762306a36Sopenharmony_ci case SYS_DVBC_ANNEX_B: 115862306a36Sopenharmony_ci dprintk(1, "%s() QAM modulation\n", __func__); 115962306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 116062306a36Sopenharmony_ci priv->freq_offset = 1750000; 116162306a36Sopenharmony_ci priv->video_standard = XC4000_DTV6; 116262306a36Sopenharmony_ci type = DTV6; 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci case SYS_DVBT: 116562306a36Sopenharmony_ci case SYS_DVBT2: 116662306a36Sopenharmony_ci dprintk(1, "%s() OFDM\n", __func__); 116762306a36Sopenharmony_ci if (bw == 0) { 116862306a36Sopenharmony_ci if (c->frequency < 400000000) { 116962306a36Sopenharmony_ci priv->freq_offset = 2250000; 117062306a36Sopenharmony_ci } else { 117162306a36Sopenharmony_ci priv->freq_offset = 2750000; 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci priv->video_standard = XC4000_DTV7_8; 117462306a36Sopenharmony_ci type = DTV78; 117562306a36Sopenharmony_ci } else if (bw <= 6000000) { 117662306a36Sopenharmony_ci priv->video_standard = XC4000_DTV6; 117762306a36Sopenharmony_ci priv->freq_offset = 1750000; 117862306a36Sopenharmony_ci type = DTV6; 117962306a36Sopenharmony_ci } else if (bw <= 7000000) { 118062306a36Sopenharmony_ci priv->video_standard = XC4000_DTV7; 118162306a36Sopenharmony_ci priv->freq_offset = 2250000; 118262306a36Sopenharmony_ci type = DTV7; 118362306a36Sopenharmony_ci } else { 118462306a36Sopenharmony_ci priv->video_standard = XC4000_DTV8; 118562306a36Sopenharmony_ci priv->freq_offset = 2750000; 118662306a36Sopenharmony_ci type = DTV8; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 118962306a36Sopenharmony_ci break; 119062306a36Sopenharmony_ci default: 119162306a36Sopenharmony_ci printk(KERN_ERR "xc4000 delivery system not supported!\n"); 119262306a36Sopenharmony_ci ret = -EINVAL; 119362306a36Sopenharmony_ci goto fail; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci priv->freq_hz = c->frequency - priv->freq_offset; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci dprintk(1, "%s() frequency=%d (compensated)\n", 119962306a36Sopenharmony_ci __func__, priv->freq_hz); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci /* Make sure the correct firmware type is loaded */ 120262306a36Sopenharmony_ci if (check_firmware(fe, type, 0, priv->if_khz) != 0) 120362306a36Sopenharmony_ci goto fail; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci priv->bandwidth = c->bandwidth_hz; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 120862306a36Sopenharmony_ci if (ret != 0) { 120962306a36Sopenharmony_ci printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", 121062306a36Sopenharmony_ci priv->rf_mode); 121162306a36Sopenharmony_ci goto fail; 121262306a36Sopenharmony_ci } else { 121362306a36Sopenharmony_ci u16 video_mode, audio_mode; 121462306a36Sopenharmony_ci video_mode = xc4000_standard[priv->video_standard].video_mode; 121562306a36Sopenharmony_ci audio_mode = xc4000_standard[priv->video_standard].audio_mode; 121662306a36Sopenharmony_ci if (type == DTV6 && priv->firm_version != 0x0102) 121762306a36Sopenharmony_ci video_mode |= 0x0001; 121862306a36Sopenharmony_ci ret = xc_set_tv_standard(priv, video_mode, audio_mode); 121962306a36Sopenharmony_ci if (ret != 0) { 122062306a36Sopenharmony_ci printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); 122162306a36Sopenharmony_ci /* DJH - do not return when it fails... */ 122262306a36Sopenharmony_ci /* goto fail; */ 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) 122762306a36Sopenharmony_ci ret = 0; 122862306a36Sopenharmony_ci if (priv->dvb_amplitude != 0) { 122962306a36Sopenharmony_ci if (xc_write_reg(priv, XREG_AMPLITUDE, 123062306a36Sopenharmony_ci (priv->firm_version != 0x0102 || 123162306a36Sopenharmony_ci priv->dvb_amplitude != 134 ? 123262306a36Sopenharmony_ci priv->dvb_amplitude : 132)) != 0) 123362306a36Sopenharmony_ci ret = -EREMOTEIO; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci if (priv->set_smoothedcvbs != 0) { 123662306a36Sopenharmony_ci if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) 123762306a36Sopenharmony_ci ret = -EREMOTEIO; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci if (ret != 0) { 124062306a36Sopenharmony_ci printk(KERN_ERR "xc4000: setting registers failed\n"); 124162306a36Sopenharmony_ci /* goto fail; */ 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci ret = 0; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cifail: 124962306a36Sopenharmony_ci mutex_unlock(&priv->lock); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci return ret; 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_cistatic int xc4000_set_analog_params(struct dvb_frontend *fe, 125562306a36Sopenharmony_ci struct analog_parameters *params) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 125862306a36Sopenharmony_ci unsigned int type = 0; 125962306a36Sopenharmony_ci int ret = -EREMOTEIO; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (params->mode == V4L2_TUNER_RADIO) { 126262306a36Sopenharmony_ci dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n", 126362306a36Sopenharmony_ci __func__, params->frequency); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci mutex_lock(&priv->lock); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci params->std = 0; 126862306a36Sopenharmony_ci priv->freq_hz = params->frequency * 125L / 2; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_INPUT1) { 127162306a36Sopenharmony_ci priv->video_standard = XC4000_FM_Radio_INPUT1; 127262306a36Sopenharmony_ci type = FM | INPUT1; 127362306a36Sopenharmony_ci } else { 127462306a36Sopenharmony_ci priv->video_standard = XC4000_FM_Radio_INPUT2; 127562306a36Sopenharmony_ci type = FM | INPUT2; 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci goto tune_channel; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", 128262306a36Sopenharmony_ci __func__, params->frequency); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci mutex_lock(&priv->lock); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* params->frequency is in units of 62.5khz */ 128762306a36Sopenharmony_ci priv->freq_hz = params->frequency * 62500; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci params->std &= V4L2_STD_ALL; 129062306a36Sopenharmony_ci /* if std is not defined, choose one */ 129162306a36Sopenharmony_ci if (!params->std) 129262306a36Sopenharmony_ci params->std = V4L2_STD_PAL_BG; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) 129562306a36Sopenharmony_ci type = MONO; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (params->std & V4L2_STD_MN) { 129862306a36Sopenharmony_ci params->std = V4L2_STD_MN; 129962306a36Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) { 130062306a36Sopenharmony_ci priv->video_standard = XC4000_MN_NTSC_PAL_Mono; 130162306a36Sopenharmony_ci } else if (audio_std & XC4000_AUDIO_STD_A2) { 130262306a36Sopenharmony_ci params->std |= V4L2_STD_A2; 130362306a36Sopenharmony_ci priv->video_standard = XC4000_MN_NTSC_PAL_A2; 130462306a36Sopenharmony_ci } else { 130562306a36Sopenharmony_ci params->std |= V4L2_STD_BTSC; 130662306a36Sopenharmony_ci priv->video_standard = XC4000_MN_NTSC_PAL_BTSC; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci goto tune_channel; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (params->std & V4L2_STD_PAL_BG) { 131262306a36Sopenharmony_ci params->std = V4L2_STD_PAL_BG; 131362306a36Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) { 131462306a36Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_MONO; 131562306a36Sopenharmony_ci } else if (!(audio_std & XC4000_AUDIO_STD_A2)) { 131662306a36Sopenharmony_ci if (!(audio_std & XC4000_AUDIO_STD_B)) { 131762306a36Sopenharmony_ci params->std |= V4L2_STD_NICAM_A; 131862306a36Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_NICAM; 131962306a36Sopenharmony_ci } else { 132062306a36Sopenharmony_ci params->std |= V4L2_STD_NICAM_B; 132162306a36Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_NICAM; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci } else { 132462306a36Sopenharmony_ci if (!(audio_std & XC4000_AUDIO_STD_B)) { 132562306a36Sopenharmony_ci params->std |= V4L2_STD_A2_A; 132662306a36Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_A2; 132762306a36Sopenharmony_ci } else { 132862306a36Sopenharmony_ci params->std |= V4L2_STD_A2_B; 132962306a36Sopenharmony_ci priv->video_standard = XC4000_BG_PAL_A2; 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci goto tune_channel; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (params->std & V4L2_STD_PAL_I) { 133662306a36Sopenharmony_ci /* default to NICAM audio standard */ 133762306a36Sopenharmony_ci params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM; 133862306a36Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) 133962306a36Sopenharmony_ci priv->video_standard = XC4000_I_PAL_NICAM_MONO; 134062306a36Sopenharmony_ci else 134162306a36Sopenharmony_ci priv->video_standard = XC4000_I_PAL_NICAM; 134262306a36Sopenharmony_ci goto tune_channel; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (params->std & V4L2_STD_PAL_DK) { 134662306a36Sopenharmony_ci params->std = V4L2_STD_PAL_DK; 134762306a36Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_MONO) { 134862306a36Sopenharmony_ci priv->video_standard = XC4000_DK_PAL_MONO; 134962306a36Sopenharmony_ci } else if (audio_std & XC4000_AUDIO_STD_A2) { 135062306a36Sopenharmony_ci params->std |= V4L2_STD_A2; 135162306a36Sopenharmony_ci priv->video_standard = XC4000_DK_PAL_A2; 135262306a36Sopenharmony_ci } else { 135362306a36Sopenharmony_ci params->std |= V4L2_STD_NICAM; 135462306a36Sopenharmony_ci priv->video_standard = XC4000_DK_PAL_NICAM; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci goto tune_channel; 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci if (params->std & V4L2_STD_SECAM_DK) { 136062306a36Sopenharmony_ci /* default to A2 audio standard */ 136162306a36Sopenharmony_ci params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2; 136262306a36Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_L) { 136362306a36Sopenharmony_ci type = 0; 136462306a36Sopenharmony_ci priv->video_standard = XC4000_DK_SECAM_NICAM; 136562306a36Sopenharmony_ci } else if (audio_std & XC4000_AUDIO_STD_MONO) { 136662306a36Sopenharmony_ci priv->video_standard = XC4000_DK_SECAM_A2MONO; 136762306a36Sopenharmony_ci } else if (audio_std & XC4000_AUDIO_STD_K3) { 136862306a36Sopenharmony_ci params->std |= V4L2_STD_SECAM_K3; 136962306a36Sopenharmony_ci priv->video_standard = XC4000_DK_SECAM_A2LDK3; 137062306a36Sopenharmony_ci } else { 137162306a36Sopenharmony_ci priv->video_standard = XC4000_DK_SECAM_A2DK1; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci goto tune_channel; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (params->std & V4L2_STD_SECAM_L) { 137762306a36Sopenharmony_ci /* default to NICAM audio standard */ 137862306a36Sopenharmony_ci type = 0; 137962306a36Sopenharmony_ci params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM; 138062306a36Sopenharmony_ci priv->video_standard = XC4000_L_SECAM_NICAM; 138162306a36Sopenharmony_ci goto tune_channel; 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci if (params->std & V4L2_STD_SECAM_LC) { 138562306a36Sopenharmony_ci /* default to NICAM audio standard */ 138662306a36Sopenharmony_ci type = 0; 138762306a36Sopenharmony_ci params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM; 138862306a36Sopenharmony_ci priv->video_standard = XC4000_LC_SECAM_NICAM; 138962306a36Sopenharmony_ci goto tune_channel; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_citune_channel: 139362306a36Sopenharmony_ci /* FIXME: it could be air. */ 139462306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (check_firmware(fe, type, params->std, 139762306a36Sopenharmony_ci xc4000_standard[priv->video_standard].int_freq) != 0) 139862306a36Sopenharmony_ci goto fail; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 140162306a36Sopenharmony_ci if (ret != 0) { 140262306a36Sopenharmony_ci printk(KERN_ERR 140362306a36Sopenharmony_ci "xc4000: xc_set_signal_source(%d) failed\n", 140462306a36Sopenharmony_ci priv->rf_mode); 140562306a36Sopenharmony_ci goto fail; 140662306a36Sopenharmony_ci } else { 140762306a36Sopenharmony_ci u16 video_mode, audio_mode; 140862306a36Sopenharmony_ci video_mode = xc4000_standard[priv->video_standard].video_mode; 140962306a36Sopenharmony_ci audio_mode = xc4000_standard[priv->video_standard].audio_mode; 141062306a36Sopenharmony_ci if (priv->video_standard < XC4000_BG_PAL_A2) { 141162306a36Sopenharmony_ci if (type & NOGD) 141262306a36Sopenharmony_ci video_mode &= 0xFF7F; 141362306a36Sopenharmony_ci } else if (priv->video_standard < XC4000_I_PAL_NICAM) { 141462306a36Sopenharmony_ci if (priv->firm_version == 0x0102) 141562306a36Sopenharmony_ci video_mode &= 0xFEFF; 141662306a36Sopenharmony_ci if (audio_std & XC4000_AUDIO_STD_B) 141762306a36Sopenharmony_ci video_mode |= 0x0080; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci ret = xc_set_tv_standard(priv, video_mode, audio_mode); 142062306a36Sopenharmony_ci if (ret != 0) { 142162306a36Sopenharmony_ci printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); 142262306a36Sopenharmony_ci goto fail; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) 142762306a36Sopenharmony_ci ret = 0; 142862306a36Sopenharmony_ci if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0) 142962306a36Sopenharmony_ci ret = -EREMOTEIO; 143062306a36Sopenharmony_ci if (priv->set_smoothedcvbs != 0) { 143162306a36Sopenharmony_ci if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) 143262306a36Sopenharmony_ci ret = -EREMOTEIO; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci if (ret != 0) { 143562306a36Sopenharmony_ci printk(KERN_ERR "xc4000: setting registers failed\n"); 143662306a36Sopenharmony_ci goto fail; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci ret = 0; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_cifail: 144462306a36Sopenharmony_ci mutex_unlock(&priv->lock); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci return ret; 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_cistatic int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength) 145062306a36Sopenharmony_ci{ 145162306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 145262306a36Sopenharmony_ci u16 value = 0; 145362306a36Sopenharmony_ci int rc; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci mutex_lock(&priv->lock); 145662306a36Sopenharmony_ci rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value); 145762306a36Sopenharmony_ci mutex_unlock(&priv->lock); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci if (rc < 0) 146062306a36Sopenharmony_ci goto ret; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* Information from real testing of DVB-T and radio part, 146362306a36Sopenharmony_ci coefficient for one dB is 0xff. 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_ci tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* all known digital modes */ 146862306a36Sopenharmony_ci if ((priv->video_standard == XC4000_DTV6) || 146962306a36Sopenharmony_ci (priv->video_standard == XC4000_DTV7) || 147062306a36Sopenharmony_ci (priv->video_standard == XC4000_DTV7_8) || 147162306a36Sopenharmony_ci (priv->video_standard == XC4000_DTV8)) 147262306a36Sopenharmony_ci goto digital; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci /* Analog mode has NOISE LEVEL important, signal 147562306a36Sopenharmony_ci depends only on gain of antenna and amplifiers, 147662306a36Sopenharmony_ci but it doesn't tell anything about real quality 147762306a36Sopenharmony_ci of reception. 147862306a36Sopenharmony_ci */ 147962306a36Sopenharmony_ci mutex_lock(&priv->lock); 148062306a36Sopenharmony_ci rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value); 148162306a36Sopenharmony_ci mutex_unlock(&priv->lock); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci /* highest noise level: 32dB */ 148662306a36Sopenharmony_ci if (value >= 0x2000) { 148762306a36Sopenharmony_ci value = 0; 148862306a36Sopenharmony_ci } else { 148962306a36Sopenharmony_ci value = (~value << 3) & 0xffff; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci goto ret; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci /* Digital mode has SIGNAL LEVEL important and real 149562306a36Sopenharmony_ci noise level is stored in demodulator registers. 149662306a36Sopenharmony_ci */ 149762306a36Sopenharmony_cidigital: 149862306a36Sopenharmony_ci /* best signal: -50dB */ 149962306a36Sopenharmony_ci if (value <= 0x3200) { 150062306a36Sopenharmony_ci value = 0xffff; 150162306a36Sopenharmony_ci /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */ 150262306a36Sopenharmony_ci } else if (value >= 0x713A) { 150362306a36Sopenharmony_ci value = 0; 150462306a36Sopenharmony_ci } else { 150562306a36Sopenharmony_ci value = ~(value - 0x3200) << 2; 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ciret: 150962306a36Sopenharmony_ci *strength = value; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci return rc; 151262306a36Sopenharmony_ci} 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_cistatic int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci mutex_lock(&priv->lock); 151962306a36Sopenharmony_ci *freq = priv->freq_hz + priv->freq_offset; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if (debug) { 152262306a36Sopenharmony_ci if ((priv->cur_fw.type 152362306a36Sopenharmony_ci & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) { 152462306a36Sopenharmony_ci u16 snr = 0; 152562306a36Sopenharmony_ci if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) { 152662306a36Sopenharmony_ci mutex_unlock(&priv->lock); 152762306a36Sopenharmony_ci dprintk(1, "%s() freq = %u, SNR = %d\n", 152862306a36Sopenharmony_ci __func__, *freq, snr); 152962306a36Sopenharmony_ci return 0; 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci mutex_unlock(&priv->lock); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci return 0; 153862306a36Sopenharmony_ci} 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cistatic int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) 154162306a36Sopenharmony_ci{ 154262306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 154362306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci *bw = priv->bandwidth; 154662306a36Sopenharmony_ci return 0; 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_cistatic int xc4000_get_status(struct dvb_frontend *fe, u32 *status) 155062306a36Sopenharmony_ci{ 155162306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 155262306a36Sopenharmony_ci u16 lock_status = 0; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci mutex_lock(&priv->lock); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (priv->cur_fw.type & BASE) 155762306a36Sopenharmony_ci xc_get_lock_status(priv, &lock_status); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci *status = (lock_status == 1 ? 156062306a36Sopenharmony_ci TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0); 156162306a36Sopenharmony_ci if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8)) 156262306a36Sopenharmony_ci *status &= (~TUNER_STATUS_STEREO); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci mutex_unlock(&priv->lock); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci dprintk(2, "%s() lock_status = %d\n", __func__, lock_status); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci return 0; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic int xc4000_sleep(struct dvb_frontend *fe) 157262306a36Sopenharmony_ci{ 157362306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 157462306a36Sopenharmony_ci int ret = 0; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci mutex_lock(&priv->lock); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* Avoid firmware reload on slow devices */ 158162306a36Sopenharmony_ci if ((no_poweroff == 2 || 158262306a36Sopenharmony_ci (no_poweroff == 0 && priv->default_pm != 0)) && 158362306a36Sopenharmony_ci (priv->cur_fw.type & BASE) != 0) { 158462306a36Sopenharmony_ci /* force reset and firmware reload */ 158562306a36Sopenharmony_ci priv->cur_fw.type = XC_POWERED_DOWN; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) { 158862306a36Sopenharmony_ci printk(KERN_ERR 158962306a36Sopenharmony_ci "xc4000: %s() unable to shutdown tuner\n", 159062306a36Sopenharmony_ci __func__); 159162306a36Sopenharmony_ci ret = -EREMOTEIO; 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci msleep(20); 159462306a36Sopenharmony_ci } 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci mutex_unlock(&priv->lock); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci return ret; 159962306a36Sopenharmony_ci} 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic int xc4000_init(struct dvb_frontend *fe) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci return 0; 160662306a36Sopenharmony_ci} 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistatic void xc4000_release(struct dvb_frontend *fe) 160962306a36Sopenharmony_ci{ 161062306a36Sopenharmony_ci struct xc4000_priv *priv = fe->tuner_priv; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci mutex_lock(&xc4000_list_mutex); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci if (priv) 161762306a36Sopenharmony_ci hybrid_tuner_release_state(priv); 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci mutex_unlock(&xc4000_list_mutex); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci fe->tuner_priv = NULL; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_cistatic const struct dvb_tuner_ops xc4000_tuner_ops = { 162562306a36Sopenharmony_ci .info = { 162662306a36Sopenharmony_ci .name = "Xceive XC4000", 162762306a36Sopenharmony_ci .frequency_min_hz = 1 * MHz, 162862306a36Sopenharmony_ci .frequency_max_hz = 1023 * MHz, 162962306a36Sopenharmony_ci .frequency_step_hz = 50 * kHz, 163062306a36Sopenharmony_ci }, 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci .release = xc4000_release, 163362306a36Sopenharmony_ci .init = xc4000_init, 163462306a36Sopenharmony_ci .sleep = xc4000_sleep, 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci .set_params = xc4000_set_params, 163762306a36Sopenharmony_ci .set_analog_params = xc4000_set_analog_params, 163862306a36Sopenharmony_ci .get_frequency = xc4000_get_frequency, 163962306a36Sopenharmony_ci .get_rf_strength = xc4000_get_signal, 164062306a36Sopenharmony_ci .get_bandwidth = xc4000_get_bandwidth, 164162306a36Sopenharmony_ci .get_status = xc4000_get_status 164262306a36Sopenharmony_ci}; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_cistruct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, 164562306a36Sopenharmony_ci struct i2c_adapter *i2c, 164662306a36Sopenharmony_ci struct xc4000_config *cfg) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci struct xc4000_priv *priv = NULL; 164962306a36Sopenharmony_ci int instance; 165062306a36Sopenharmony_ci u16 id = 0; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci dprintk(1, "%s(%d-%04x)\n", __func__, 165362306a36Sopenharmony_ci i2c ? i2c_adapter_id(i2c) : -1, 165462306a36Sopenharmony_ci cfg ? cfg->i2c_address : -1); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci mutex_lock(&xc4000_list_mutex); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci instance = hybrid_tuner_request_state(struct xc4000_priv, priv, 165962306a36Sopenharmony_ci hybrid_tuner_instance_list, 166062306a36Sopenharmony_ci i2c, cfg->i2c_address, "xc4000"); 166162306a36Sopenharmony_ci switch (instance) { 166262306a36Sopenharmony_ci case 0: 166362306a36Sopenharmony_ci goto fail; 166462306a36Sopenharmony_ci case 1: 166562306a36Sopenharmony_ci /* new tuner instance */ 166662306a36Sopenharmony_ci priv->bandwidth = 6000000; 166762306a36Sopenharmony_ci /* set default configuration */ 166862306a36Sopenharmony_ci priv->if_khz = 4560; 166962306a36Sopenharmony_ci priv->default_pm = 0; 167062306a36Sopenharmony_ci priv->dvb_amplitude = 134; 167162306a36Sopenharmony_ci priv->set_smoothedcvbs = 1; 167262306a36Sopenharmony_ci mutex_init(&priv->lock); 167362306a36Sopenharmony_ci fe->tuner_priv = priv; 167462306a36Sopenharmony_ci break; 167562306a36Sopenharmony_ci default: 167662306a36Sopenharmony_ci /* existing tuner instance */ 167762306a36Sopenharmony_ci fe->tuner_priv = priv; 167862306a36Sopenharmony_ci break; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci if (cfg->if_khz != 0) { 168262306a36Sopenharmony_ci /* copy configuration if provided by the caller */ 168362306a36Sopenharmony_ci priv->if_khz = cfg->if_khz; 168462306a36Sopenharmony_ci priv->default_pm = cfg->default_pm; 168562306a36Sopenharmony_ci priv->dvb_amplitude = cfg->dvb_amplitude; 168662306a36Sopenharmony_ci priv->set_smoothedcvbs = cfg->set_smoothedcvbs; 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci /* Check if firmware has been loaded. It is possible that another 169062306a36Sopenharmony_ci instance of the driver has loaded the firmware. 169162306a36Sopenharmony_ci */ 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci if (instance == 1) { 169462306a36Sopenharmony_ci if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) 169562306a36Sopenharmony_ci goto fail; 169662306a36Sopenharmony_ci } else { 169762306a36Sopenharmony_ci id = ((priv->cur_fw.type & BASE) != 0 ? 169862306a36Sopenharmony_ci priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED); 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci switch (id) { 170262306a36Sopenharmony_ci case XC_PRODUCT_ID_XC4000: 170362306a36Sopenharmony_ci case XC_PRODUCT_ID_XC4100: 170462306a36Sopenharmony_ci printk(KERN_INFO 170562306a36Sopenharmony_ci "xc4000: Successfully identified at address 0x%02x\n", 170662306a36Sopenharmony_ci cfg->i2c_address); 170762306a36Sopenharmony_ci printk(KERN_INFO 170862306a36Sopenharmony_ci "xc4000: Firmware has been loaded previously\n"); 170962306a36Sopenharmony_ci break; 171062306a36Sopenharmony_ci case XC_PRODUCT_ID_FW_NOT_LOADED: 171162306a36Sopenharmony_ci printk(KERN_INFO 171262306a36Sopenharmony_ci "xc4000: Successfully identified at address 0x%02x\n", 171362306a36Sopenharmony_ci cfg->i2c_address); 171462306a36Sopenharmony_ci printk(KERN_INFO 171562306a36Sopenharmony_ci "xc4000: Firmware has not been loaded previously\n"); 171662306a36Sopenharmony_ci break; 171762306a36Sopenharmony_ci default: 171862306a36Sopenharmony_ci printk(KERN_ERR 171962306a36Sopenharmony_ci "xc4000: Device not found at addr 0x%02x (0x%x)\n", 172062306a36Sopenharmony_ci cfg->i2c_address, id); 172162306a36Sopenharmony_ci goto fail; 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci mutex_unlock(&xc4000_list_mutex); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, 172762306a36Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (instance == 1) { 173062306a36Sopenharmony_ci int ret; 173162306a36Sopenharmony_ci mutex_lock(&priv->lock); 173262306a36Sopenharmony_ci ret = xc4000_fwupload(fe); 173362306a36Sopenharmony_ci mutex_unlock(&priv->lock); 173462306a36Sopenharmony_ci if (ret != 0) 173562306a36Sopenharmony_ci goto fail2; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci return fe; 173962306a36Sopenharmony_cifail: 174062306a36Sopenharmony_ci mutex_unlock(&xc4000_list_mutex); 174162306a36Sopenharmony_cifail2: 174262306a36Sopenharmony_ci xc4000_release(fe); 174362306a36Sopenharmony_ci return NULL; 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xc4000_attach); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ciMODULE_AUTHOR("Steven Toth, Davide Ferri"); 174862306a36Sopenharmony_ciMODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); 174962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 175062306a36Sopenharmony_ciMODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE_NEW); 175162306a36Sopenharmony_ciMODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE); 1752