162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Xceive XC5000 "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 */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/moduleparam.h> 1262306a36Sopenharmony_ci#include <linux/videodev2.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/workqueue.h> 1562306a36Sopenharmony_ci#include <linux/dvb/frontend.h> 1662306a36Sopenharmony_ci#include <linux/i2c.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <media/dvb_frontend.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "xc5000.h" 2162306a36Sopenharmony_ci#include "tuner-i2c.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int debug; 2462306a36Sopenharmony_cimodule_param(debug, int, 0644); 2562306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int no_poweroff; 2862306a36Sopenharmony_cimodule_param(no_poweroff, int, 0644); 2962306a36Sopenharmony_ciMODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" 3062306a36Sopenharmony_ci "\t\t1 keep device energized and with tuner ready all the times.\n" 3162306a36Sopenharmony_ci "\t\tFaster, but consumes more power and keeps the device hotter"); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic DEFINE_MUTEX(xc5000_list_mutex); 3462306a36Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define dprintk(level, fmt, arg...) if (debug >= level) \ 3762306a36Sopenharmony_ci printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct xc5000_priv { 4062306a36Sopenharmony_ci struct tuner_i2c_props i2c_props; 4162306a36Sopenharmony_ci struct list_head hybrid_tuner_instance_list; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci u32 if_khz; 4462306a36Sopenharmony_ci u16 xtal_khz; 4562306a36Sopenharmony_ci u32 freq_hz, freq_offset; 4662306a36Sopenharmony_ci u32 bandwidth; 4762306a36Sopenharmony_ci u8 video_standard; 4862306a36Sopenharmony_ci unsigned int mode; 4962306a36Sopenharmony_ci u8 rf_mode; 5062306a36Sopenharmony_ci u8 radio_input; 5162306a36Sopenharmony_ci u16 output_amp; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci int chip_id; 5462306a36Sopenharmony_ci u16 pll_register_no; 5562306a36Sopenharmony_ci u8 init_status_supported; 5662306a36Sopenharmony_ci u8 fw_checksum_supported; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci struct dvb_frontend *fe; 5962306a36Sopenharmony_ci struct delayed_work timer_sleep; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci const struct firmware *firmware; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Misc Defines */ 6562306a36Sopenharmony_ci#define MAX_TV_STANDARD 24 6662306a36Sopenharmony_ci#define XC_MAX_I2C_WRITE_LENGTH 64 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Time to suspend after the .sleep callback is called */ 6962306a36Sopenharmony_ci#define XC5000_SLEEP_TIME 5000 /* ms */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* Signal Types */ 7262306a36Sopenharmony_ci#define XC_RF_MODE_AIR 0 7362306a36Sopenharmony_ci#define XC_RF_MODE_CABLE 1 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Product id */ 7662306a36Sopenharmony_ci#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 7762306a36Sopenharmony_ci#define XC_PRODUCT_ID_FW_LOADED 0x1388 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* Registers */ 8062306a36Sopenharmony_ci#define XREG_INIT 0x00 8162306a36Sopenharmony_ci#define XREG_VIDEO_MODE 0x01 8262306a36Sopenharmony_ci#define XREG_AUDIO_MODE 0x02 8362306a36Sopenharmony_ci#define XREG_RF_FREQ 0x03 8462306a36Sopenharmony_ci#define XREG_D_CODE 0x04 8562306a36Sopenharmony_ci#define XREG_IF_OUT 0x05 8662306a36Sopenharmony_ci#define XREG_SEEK_MODE 0x07 8762306a36Sopenharmony_ci#define XREG_POWER_DOWN 0x0A /* Obsolete */ 8862306a36Sopenharmony_ci/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ 8962306a36Sopenharmony_ci#define XREG_OUTPUT_AMP 0x0B 9062306a36Sopenharmony_ci#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ 9162306a36Sopenharmony_ci#define XREG_SMOOTHEDCVBS 0x0E 9262306a36Sopenharmony_ci#define XREG_XTALFREQ 0x0F 9362306a36Sopenharmony_ci#define XREG_FINERFREQ 0x10 9462306a36Sopenharmony_ci#define XREG_DDIMODE 0x11 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define XREG_ADC_ENV 0x00 9762306a36Sopenharmony_ci#define XREG_QUALITY 0x01 9862306a36Sopenharmony_ci#define XREG_FRAME_LINES 0x02 9962306a36Sopenharmony_ci#define XREG_HSYNC_FREQ 0x03 10062306a36Sopenharmony_ci#define XREG_LOCK 0x04 10162306a36Sopenharmony_ci#define XREG_FREQ_ERROR 0x05 10262306a36Sopenharmony_ci#define XREG_SNR 0x06 10362306a36Sopenharmony_ci#define XREG_VERSION 0x07 10462306a36Sopenharmony_ci#define XREG_PRODUCT_ID 0x08 10562306a36Sopenharmony_ci#define XREG_BUSY 0x09 10662306a36Sopenharmony_ci#define XREG_BUILD 0x0D 10762306a36Sopenharmony_ci#define XREG_TOTALGAIN 0x0F 10862306a36Sopenharmony_ci#define XREG_FW_CHECKSUM 0x12 10962306a36Sopenharmony_ci#define XREG_INIT_STATUS 0x13 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci Basic firmware description. This will remain with 11362306a36Sopenharmony_ci the driver for documentation purposes. 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci This represents an I2C firmware file encoded as a 11662306a36Sopenharmony_ci string of unsigned char. Format is as follows: 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB 11962306a36Sopenharmony_ci char[1 ]=len0_LSB -> length of first write transaction 12062306a36Sopenharmony_ci char[2 ]=data0 -> first byte to be sent 12162306a36Sopenharmony_ci char[3 ]=data1 12262306a36Sopenharmony_ci char[4 ]=data2 12362306a36Sopenharmony_ci char[ ]=... 12462306a36Sopenharmony_ci char[M ]=dataN -> last byte to be sent 12562306a36Sopenharmony_ci char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB 12662306a36Sopenharmony_ci char[M+2]=len1_LSB -> length of second write transaction 12762306a36Sopenharmony_ci char[M+3]=data0 12862306a36Sopenharmony_ci char[M+4]=data1 12962306a36Sopenharmony_ci ... 13062306a36Sopenharmony_ci etc. 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci The [len] value should be interpreted as follows: 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci len= len_MSB _ len_LSB 13562306a36Sopenharmony_ci len=1111_1111_1111_1111 : End of I2C_SEQUENCE 13662306a36Sopenharmony_ci len=0000_0000_0000_0000 : Reset command: Do hardware reset 13762306a36Sopenharmony_ci len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) 13862306a36Sopenharmony_ci len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci For the RESET and WAIT commands, the two following bytes will contain 14162306a36Sopenharmony_ci immediately the length of the following transaction. 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci*/ 14462306a36Sopenharmony_cistruct XC_TV_STANDARD { 14562306a36Sopenharmony_ci char *name; 14662306a36Sopenharmony_ci u16 audio_mode; 14762306a36Sopenharmony_ci u16 video_mode; 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* Tuner standards */ 15162306a36Sopenharmony_ci#define MN_NTSC_PAL_BTSC 0 15262306a36Sopenharmony_ci#define MN_NTSC_PAL_A2 1 15362306a36Sopenharmony_ci#define MN_NTSC_PAL_EIAJ 2 15462306a36Sopenharmony_ci#define MN_NTSC_PAL_MONO 3 15562306a36Sopenharmony_ci#define BG_PAL_A2 4 15662306a36Sopenharmony_ci#define BG_PAL_NICAM 5 15762306a36Sopenharmony_ci#define BG_PAL_MONO 6 15862306a36Sopenharmony_ci#define I_PAL_NICAM 7 15962306a36Sopenharmony_ci#define I_PAL_NICAM_MONO 8 16062306a36Sopenharmony_ci#define DK_PAL_A2 9 16162306a36Sopenharmony_ci#define DK_PAL_NICAM 10 16262306a36Sopenharmony_ci#define DK_PAL_MONO 11 16362306a36Sopenharmony_ci#define DK_SECAM_A2DK1 12 16462306a36Sopenharmony_ci#define DK_SECAM_A2LDK3 13 16562306a36Sopenharmony_ci#define DK_SECAM_A2MONO 14 16662306a36Sopenharmony_ci#define L_SECAM_NICAM 15 16762306a36Sopenharmony_ci#define LC_SECAM_NICAM 16 16862306a36Sopenharmony_ci#define DTV6 17 16962306a36Sopenharmony_ci#define DTV8 18 17062306a36Sopenharmony_ci#define DTV7_8 19 17162306a36Sopenharmony_ci#define DTV7 20 17262306a36Sopenharmony_ci#define FM_RADIO_INPUT2 21 17362306a36Sopenharmony_ci#define FM_RADIO_INPUT1 22 17462306a36Sopenharmony_ci#define FM_RADIO_INPUT1_MONO 23 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic struct XC_TV_STANDARD xc5000_standard[MAX_TV_STANDARD] = { 17762306a36Sopenharmony_ci {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, 17862306a36Sopenharmony_ci {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, 17962306a36Sopenharmony_ci {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, 18062306a36Sopenharmony_ci {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, 18162306a36Sopenharmony_ci {"B/G-PAL-A2", 0x0A00, 0x8049}, 18262306a36Sopenharmony_ci {"B/G-PAL-NICAM", 0x0C04, 0x8049}, 18362306a36Sopenharmony_ci {"B/G-PAL-MONO", 0x0878, 0x8059}, 18462306a36Sopenharmony_ci {"I-PAL-NICAM", 0x1080, 0x8009}, 18562306a36Sopenharmony_ci {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, 18662306a36Sopenharmony_ci {"D/K-PAL-A2", 0x1600, 0x8009}, 18762306a36Sopenharmony_ci {"D/K-PAL-NICAM", 0x0E80, 0x8009}, 18862306a36Sopenharmony_ci {"D/K-PAL-MONO", 0x1478, 0x8009}, 18962306a36Sopenharmony_ci {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, 19062306a36Sopenharmony_ci {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009}, 19162306a36Sopenharmony_ci {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, 19262306a36Sopenharmony_ci {"L-SECAM-NICAM", 0x8E82, 0x0009}, 19362306a36Sopenharmony_ci {"L'-SECAM-NICAM", 0x8E82, 0x4009}, 19462306a36Sopenharmony_ci {"DTV6", 0x00C0, 0x8002}, 19562306a36Sopenharmony_ci {"DTV8", 0x00C0, 0x800B}, 19662306a36Sopenharmony_ci {"DTV7/8", 0x00C0, 0x801B}, 19762306a36Sopenharmony_ci {"DTV7", 0x00C0, 0x8007}, 19862306a36Sopenharmony_ci {"FM Radio-INPUT2", 0x9802, 0x9002}, 19962306a36Sopenharmony_ci {"FM Radio-INPUT1", 0x0208, 0x9002}, 20062306a36Sopenharmony_ci {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistruct xc5000_fw_cfg { 20562306a36Sopenharmony_ci char *name; 20662306a36Sopenharmony_ci u16 size; 20762306a36Sopenharmony_ci u16 pll_reg; 20862306a36Sopenharmony_ci u8 init_status_supported; 20962306a36Sopenharmony_ci u8 fw_checksum_supported; 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" 21362306a36Sopenharmony_cistatic const struct xc5000_fw_cfg xc5000a_1_6_114 = { 21462306a36Sopenharmony_ci .name = XC5000A_FIRMWARE, 21562306a36Sopenharmony_ci .size = 12401, 21662306a36Sopenharmony_ci .pll_reg = 0x806c, 21762306a36Sopenharmony_ci}; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw" 22062306a36Sopenharmony_cistatic const struct xc5000_fw_cfg xc5000c_41_024_5 = { 22162306a36Sopenharmony_ci .name = XC5000C_FIRMWARE, 22262306a36Sopenharmony_ci .size = 16497, 22362306a36Sopenharmony_ci .pll_reg = 0x13, 22462306a36Sopenharmony_ci .init_status_supported = 1, 22562306a36Sopenharmony_ci .fw_checksum_supported = 1, 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci switch (chip_id) { 23162306a36Sopenharmony_ci default: 23262306a36Sopenharmony_ci case XC5000A: 23362306a36Sopenharmony_ci return &xc5000a_1_6_114; 23462306a36Sopenharmony_ci case XC5000C: 23562306a36Sopenharmony_ci return &xc5000c_41_024_5; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force); 24062306a36Sopenharmony_cistatic int xc5000_is_firmware_loaded(struct dvb_frontend *fe); 24162306a36Sopenharmony_cistatic int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); 24262306a36Sopenharmony_cistatic int xc5000_tuner_reset(struct dvb_frontend *fe); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_props.addr, 24762306a36Sopenharmony_ci .flags = 0, .buf = buf, .len = len }; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { 25062306a36Sopenharmony_ci printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); 25162306a36Sopenharmony_ci return -EREMOTEIO; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci#if 0 25762306a36Sopenharmony_ci/* This routine is never used because the only time we read data from the 25862306a36Sopenharmony_ci i2c bus is when we read registers, and we want that to be an atomic i2c 25962306a36Sopenharmony_ci transaction in case we are on a multi-master bus */ 26062306a36Sopenharmony_cistatic int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_props.addr, 26362306a36Sopenharmony_ci .flags = I2C_M_RD, .buf = buf, .len = len }; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { 26662306a36Sopenharmony_ci printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); 26762306a36Sopenharmony_ci return -EREMOTEIO; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci#endif 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci u8 buf[2] = { reg >> 8, reg & 0xff }; 27662306a36Sopenharmony_ci u8 bval[2] = { 0, 0 }; 27762306a36Sopenharmony_ci struct i2c_msg msg[2] = { 27862306a36Sopenharmony_ci { .addr = priv->i2c_props.addr, 27962306a36Sopenharmony_ci .flags = 0, .buf = &buf[0], .len = 2 }, 28062306a36Sopenharmony_ci { .addr = priv->i2c_props.addr, 28162306a36Sopenharmony_ci .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, 28262306a36Sopenharmony_ci }; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { 28562306a36Sopenharmony_ci printk(KERN_WARNING "xc5000: I2C read failed\n"); 28662306a36Sopenharmony_ci return -EREMOTEIO; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci *val = (bval[0] << 8) | bval[1]; 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int xc5000_tuner_reset(struct dvb_frontend *fe) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 29662306a36Sopenharmony_ci int ret; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (fe->callback) { 30162306a36Sopenharmony_ci ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? 30262306a36Sopenharmony_ci fe->dvb->priv : 30362306a36Sopenharmony_ci priv->i2c_props.adap->algo_data, 30462306a36Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 30562306a36Sopenharmony_ci XC5000_TUNER_RESET, 0); 30662306a36Sopenharmony_ci if (ret) { 30762306a36Sopenharmony_ci printk(KERN_ERR "xc5000: reset failed\n"); 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci } else { 31162306a36Sopenharmony_ci printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); 31262306a36Sopenharmony_ci return -EINVAL; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int xc_write_reg(struct xc5000_priv *priv, u16 reg_addr, u16 i2c_data) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci u8 buf[4]; 32062306a36Sopenharmony_ci int watch_dog_timer = 100; 32162306a36Sopenharmony_ci int result; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci buf[0] = (reg_addr >> 8) & 0xFF; 32462306a36Sopenharmony_ci buf[1] = reg_addr & 0xFF; 32562306a36Sopenharmony_ci buf[2] = (i2c_data >> 8) & 0xFF; 32662306a36Sopenharmony_ci buf[3] = i2c_data & 0xFF; 32762306a36Sopenharmony_ci result = xc_send_i2c_data(priv, buf, 4); 32862306a36Sopenharmony_ci if (result == 0) { 32962306a36Sopenharmony_ci /* wait for busy flag to clear */ 33062306a36Sopenharmony_ci while ((watch_dog_timer > 0) && (result == 0)) { 33162306a36Sopenharmony_ci result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); 33262306a36Sopenharmony_ci if (result == 0) { 33362306a36Sopenharmony_ci if ((buf[0] == 0) && (buf[1] == 0)) { 33462306a36Sopenharmony_ci /* busy flag cleared */ 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci } else { 33762306a36Sopenharmony_ci msleep(5); /* wait 5 ms */ 33862306a36Sopenharmony_ci watch_dog_timer--; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci if (watch_dog_timer <= 0) 34462306a36Sopenharmony_ci result = -EREMOTEIO; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return result; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci int i, nbytes_to_send, result; 35462306a36Sopenharmony_ci unsigned int len, pos, index; 35562306a36Sopenharmony_ci u8 buf[XC_MAX_I2C_WRITE_LENGTH]; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci index = 0; 35862306a36Sopenharmony_ci while ((i2c_sequence[index] != 0xFF) || 35962306a36Sopenharmony_ci (i2c_sequence[index + 1] != 0xFF)) { 36062306a36Sopenharmony_ci len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; 36162306a36Sopenharmony_ci if (len == 0x0000) { 36262306a36Sopenharmony_ci /* RESET command */ 36362306a36Sopenharmony_ci result = xc5000_tuner_reset(fe); 36462306a36Sopenharmony_ci index += 2; 36562306a36Sopenharmony_ci if (result != 0) 36662306a36Sopenharmony_ci return result; 36762306a36Sopenharmony_ci } else if (len & 0x8000) { 36862306a36Sopenharmony_ci /* WAIT command */ 36962306a36Sopenharmony_ci msleep(len & 0x7FFF); 37062306a36Sopenharmony_ci index += 2; 37162306a36Sopenharmony_ci } else { 37262306a36Sopenharmony_ci /* Send i2c data whilst ensuring individual transactions 37362306a36Sopenharmony_ci * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci index += 2; 37662306a36Sopenharmony_ci buf[0] = i2c_sequence[index]; 37762306a36Sopenharmony_ci buf[1] = i2c_sequence[index + 1]; 37862306a36Sopenharmony_ci pos = 2; 37962306a36Sopenharmony_ci while (pos < len) { 38062306a36Sopenharmony_ci if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) 38162306a36Sopenharmony_ci nbytes_to_send = 38262306a36Sopenharmony_ci XC_MAX_I2C_WRITE_LENGTH; 38362306a36Sopenharmony_ci else 38462306a36Sopenharmony_ci nbytes_to_send = (len - pos + 2); 38562306a36Sopenharmony_ci for (i = 2; i < nbytes_to_send; i++) { 38662306a36Sopenharmony_ci buf[i] = i2c_sequence[index + pos + 38762306a36Sopenharmony_ci i - 2]; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci result = xc_send_i2c_data(priv, buf, 39062306a36Sopenharmony_ci nbytes_to_send); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (result != 0) 39362306a36Sopenharmony_ci return result; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci pos += nbytes_to_send - 2; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci index += len; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int xc_initialize(struct xc5000_priv *priv) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 40662306a36Sopenharmony_ci return xc_write_reg(priv, XREG_INIT, 0); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int xc_set_tv_standard(struct xc5000_priv *priv, 41062306a36Sopenharmony_ci u16 video_mode, u16 audio_mode, u8 radio_mode) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci int ret; 41362306a36Sopenharmony_ci dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); 41462306a36Sopenharmony_ci if (radio_mode) { 41562306a36Sopenharmony_ci dprintk(1, "%s() Standard = %s\n", 41662306a36Sopenharmony_ci __func__, 41762306a36Sopenharmony_ci xc5000_standard[radio_mode].name); 41862306a36Sopenharmony_ci } else { 41962306a36Sopenharmony_ci dprintk(1, "%s() Standard = %s\n", 42062306a36Sopenharmony_ci __func__, 42162306a36Sopenharmony_ci xc5000_standard[priv->video_standard].name); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); 42562306a36Sopenharmony_ci if (ret == 0) 42662306a36Sopenharmony_ci ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return ret; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int xc_set_signal_source(struct xc5000_priv *priv, u16 rf_mode) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, 43462306a36Sopenharmony_ci rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { 43762306a36Sopenharmony_ci rf_mode = XC_RF_MODE_CABLE; 43862306a36Sopenharmony_ci printk(KERN_ERR 43962306a36Sopenharmony_ci "%s(), Invalid mode, defaulting to CABLE", 44062306a36Sopenharmony_ci __func__); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic const struct dvb_tuner_ops xc5000_tuner_ops; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int xc_set_rf_frequency(struct xc5000_priv *priv, u32 freq_hz) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci u16 freq_code; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci dprintk(1, "%s(%u)\n", __func__, freq_hz); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if ((freq_hz > xc5000_tuner_ops.info.frequency_max_hz) || 45462306a36Sopenharmony_ci (freq_hz < xc5000_tuner_ops.info.frequency_min_hz)) 45562306a36Sopenharmony_ci return -EINVAL; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci freq_code = (u16)(freq_hz / 15625); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Starting in firmware version 1.1.44, Xceive recommends using the 46062306a36Sopenharmony_ci FINERFREQ for all normal tuning (the doc indicates reg 0x03 should 46162306a36Sopenharmony_ci only be used for fast scanning for channel lock) */ 46262306a36Sopenharmony_ci return xc_write_reg(priv, XREG_FINERFREQ, freq_code); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci u32 freq_code = (freq_khz * 1024)/1000; 46962306a36Sopenharmony_ci dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", 47062306a36Sopenharmony_ci __func__, freq_khz, freq_code); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return xc_write_reg(priv, XREG_IF_OUT, freq_code); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic int xc_get_adc_envelope(struct xc5000_priv *priv, u16 *adc_envelope) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci int result; 48462306a36Sopenharmony_ci u16 reg_data; 48562306a36Sopenharmony_ci u32 tmp; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®_data); 48862306a36Sopenharmony_ci if (result != 0) 48962306a36Sopenharmony_ci return result; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci tmp = (u32)reg_data; 49262306a36Sopenharmony_ci (*freq_error_hz) = (tmp * 15625) / 1000; 49362306a36Sopenharmony_ci return result; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci return xc5000_readreg(priv, XREG_LOCK, lock_status); 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int xc_get_version(struct xc5000_priv *priv, 50262306a36Sopenharmony_ci u8 *hw_majorversion, u8 *hw_minorversion, 50362306a36Sopenharmony_ci u8 *fw_majorversion, u8 *fw_minorversion) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci u16 data; 50662306a36Sopenharmony_ci int result; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci result = xc5000_readreg(priv, XREG_VERSION, &data); 50962306a36Sopenharmony_ci if (result != 0) 51062306a36Sopenharmony_ci return result; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci (*hw_majorversion) = (data >> 12) & 0x0F; 51362306a36Sopenharmony_ci (*hw_minorversion) = (data >> 8) & 0x0F; 51462306a36Sopenharmony_ci (*fw_majorversion) = (data >> 4) & 0x0F; 51562306a36Sopenharmony_ci (*fw_minorversion) = data & 0x0F; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return 0; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci return xc5000_readreg(priv, XREG_BUILD, buildrev); 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci u16 reg_data; 52862306a36Sopenharmony_ci int result; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®_data); 53162306a36Sopenharmony_ci if (result != 0) 53262306a36Sopenharmony_ci return result; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci (*hsync_freq_hz) = ((reg_data & 0x0fff) * 763)/100; 53562306a36Sopenharmony_ci return result; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic int xc_get_quality(struct xc5000_priv *priv, u16 *quality) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci return xc5000_readreg(priv, XREG_QUALITY, quality); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci return xc5000_readreg(priv, XREG_SNR, snr); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci#define XC_TUNE_ANALOG 0 55962306a36Sopenharmony_ci#define XC_TUNE_DIGITAL 1 56062306a36Sopenharmony_cistatic int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci dprintk(1, "%s(%u)\n", __func__, freq_hz); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (xc_set_rf_frequency(priv, freq_hz) != 0) 56562306a36Sopenharmony_ci return -EREMOTEIO; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int xc_set_xtal(struct dvb_frontend *fe) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 57362306a36Sopenharmony_ci int ret = 0; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci switch (priv->chip_id) { 57662306a36Sopenharmony_ci default: 57762306a36Sopenharmony_ci case XC5000A: 57862306a36Sopenharmony_ci /* 32.000 MHz xtal is default */ 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci case XC5000C: 58162306a36Sopenharmony_ci switch (priv->xtal_khz) { 58262306a36Sopenharmony_ci default: 58362306a36Sopenharmony_ci case 32000: 58462306a36Sopenharmony_ci /* 32.000 MHz xtal is default */ 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci case 31875: 58762306a36Sopenharmony_ci /* 31.875 MHz xtal configuration */ 58862306a36Sopenharmony_ci ret = xc_write_reg(priv, 0x000f, 0x8081); 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci return ret; 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_cistatic int xc5000_fwupload(struct dvb_frontend *fe, 59762306a36Sopenharmony_ci const struct xc5000_fw_cfg *desired_fw, 59862306a36Sopenharmony_ci const struct firmware *fw) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 60162306a36Sopenharmony_ci int ret; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* request the firmware, this will block and timeout */ 60462306a36Sopenharmony_ci dprintk(1, "waiting for firmware upload (%s)...\n", 60562306a36Sopenharmony_ci desired_fw->name); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci priv->pll_register_no = desired_fw->pll_reg; 60862306a36Sopenharmony_ci priv->init_status_supported = desired_fw->init_status_supported; 60962306a36Sopenharmony_ci priv->fw_checksum_supported = desired_fw->fw_checksum_supported; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci dprintk(1, "firmware uploading...\n"); 61362306a36Sopenharmony_ci ret = xc_load_i2c_sequence(fe, fw->data); 61462306a36Sopenharmony_ci if (!ret) { 61562306a36Sopenharmony_ci ret = xc_set_xtal(fe); 61662306a36Sopenharmony_ci dprintk(1, "Firmware upload complete...\n"); 61762306a36Sopenharmony_ci } else 61862306a36Sopenharmony_ci printk(KERN_ERR "xc5000: firmware upload failed...\n"); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return ret; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic void xc_debug_dump(struct xc5000_priv *priv) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci u16 adc_envelope; 62662306a36Sopenharmony_ci u32 freq_error_hz = 0; 62762306a36Sopenharmony_ci u16 lock_status; 62862306a36Sopenharmony_ci u32 hsync_freq_hz = 0; 62962306a36Sopenharmony_ci u16 frame_lines; 63062306a36Sopenharmony_ci u16 quality; 63162306a36Sopenharmony_ci u16 snr; 63262306a36Sopenharmony_ci u16 totalgain; 63362306a36Sopenharmony_ci u8 hw_majorversion = 0, hw_minorversion = 0; 63462306a36Sopenharmony_ci u8 fw_majorversion = 0, fw_minorversion = 0; 63562306a36Sopenharmony_ci u16 fw_buildversion = 0; 63662306a36Sopenharmony_ci u16 regval; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Wait for stats to stabilize. 63962306a36Sopenharmony_ci * Frame Lines needs two frame times after initial lock 64062306a36Sopenharmony_ci * before it is valid. 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci msleep(100); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci xc_get_adc_envelope(priv, &adc_envelope); 64562306a36Sopenharmony_ci dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci xc_get_frequency_error(priv, &freq_error_hz); 64862306a36Sopenharmony_ci dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci xc_get_lock_status(priv, &lock_status); 65162306a36Sopenharmony_ci dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", 65262306a36Sopenharmony_ci lock_status); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci xc_get_version(priv, &hw_majorversion, &hw_minorversion, 65562306a36Sopenharmony_ci &fw_majorversion, &fw_minorversion); 65662306a36Sopenharmony_ci xc_get_buildversion(priv, &fw_buildversion); 65762306a36Sopenharmony_ci dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n", 65862306a36Sopenharmony_ci hw_majorversion, hw_minorversion, 65962306a36Sopenharmony_ci fw_majorversion, fw_minorversion, fw_buildversion); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci xc_get_hsync_freq(priv, &hsync_freq_hz); 66262306a36Sopenharmony_ci dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci xc_get_frame_lines(priv, &frame_lines); 66562306a36Sopenharmony_ci dprintk(1, "*** Frame lines = %d\n", frame_lines); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci xc_get_quality(priv, &quality); 66862306a36Sopenharmony_ci dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci xc_get_analogsnr(priv, &snr); 67162306a36Sopenharmony_ci dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci xc_get_totalgain(priv, &totalgain); 67462306a36Sopenharmony_ci dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256, 67562306a36Sopenharmony_ci (totalgain % 256) * 100 / 256); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (priv->pll_register_no) { 67862306a36Sopenharmony_ci if (!xc5000_readreg(priv, priv->pll_register_no, ®val)) 67962306a36Sopenharmony_ci dprintk(1, "*** PLL lock status = 0x%04x\n", regval); 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int xc5000_tune_digital(struct dvb_frontend *fe) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 68662306a36Sopenharmony_ci int ret; 68762306a36Sopenharmony_ci u32 bw = fe->dtv_property_cache.bandwidth_hz; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 69062306a36Sopenharmony_ci if (ret != 0) { 69162306a36Sopenharmony_ci printk(KERN_ERR 69262306a36Sopenharmony_ci "xc5000: xc_set_signal_source(%d) failed\n", 69362306a36Sopenharmony_ci priv->rf_mode); 69462306a36Sopenharmony_ci return -EREMOTEIO; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci ret = xc_set_tv_standard(priv, 69862306a36Sopenharmony_ci xc5000_standard[priv->video_standard].video_mode, 69962306a36Sopenharmony_ci xc5000_standard[priv->video_standard].audio_mode, 0); 70062306a36Sopenharmony_ci if (ret != 0) { 70162306a36Sopenharmony_ci printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); 70262306a36Sopenharmony_ci return -EREMOTEIO; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci ret = xc_set_IF_frequency(priv, priv->if_khz); 70662306a36Sopenharmony_ci if (ret != 0) { 70762306a36Sopenharmony_ci printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", 70862306a36Sopenharmony_ci priv->if_khz); 70962306a36Sopenharmony_ci return -EIO; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci dprintk(1, "%s() setting OUTPUT_AMP to 0x%x\n", 71362306a36Sopenharmony_ci __func__, priv->output_amp); 71462306a36Sopenharmony_ci xc_write_reg(priv, XREG_OUTPUT_AMP, priv->output_amp); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (debug) 71962306a36Sopenharmony_ci xc_debug_dump(priv); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci priv->bandwidth = bw; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic int xc5000_set_digital_params(struct dvb_frontend *fe) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci int b; 72962306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 73062306a36Sopenharmony_ci u32 bw = fe->dtv_property_cache.bandwidth_hz; 73162306a36Sopenharmony_ci u32 freq = fe->dtv_property_cache.frequency; 73262306a36Sopenharmony_ci u32 delsys = fe->dtv_property_cache.delivery_system; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (xc_load_fw_and_init_tuner(fe, 0) != 0) { 73562306a36Sopenharmony_ci dprintk(1, "Unable to load firmware and init tuner\n"); 73662306a36Sopenharmony_ci return -EINVAL; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci switch (delsys) { 74262306a36Sopenharmony_ci case SYS_ATSC: 74362306a36Sopenharmony_ci dprintk(1, "%s() VSB modulation\n", __func__); 74462306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 74562306a36Sopenharmony_ci priv->freq_offset = 1750000; 74662306a36Sopenharmony_ci priv->video_standard = DTV6; 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci case SYS_DVBC_ANNEX_B: 74962306a36Sopenharmony_ci dprintk(1, "%s() QAM modulation\n", __func__); 75062306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 75162306a36Sopenharmony_ci priv->freq_offset = 1750000; 75262306a36Sopenharmony_ci priv->video_standard = DTV6; 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci case SYS_ISDBT: 75562306a36Sopenharmony_ci /* All ISDB-T are currently for 6 MHz bw */ 75662306a36Sopenharmony_ci if (!bw) 75762306a36Sopenharmony_ci bw = 6000000; 75862306a36Sopenharmony_ci /* fall to OFDM handling */ 75962306a36Sopenharmony_ci fallthrough; 76062306a36Sopenharmony_ci case SYS_DMBTH: 76162306a36Sopenharmony_ci case SYS_DVBT: 76262306a36Sopenharmony_ci case SYS_DVBT2: 76362306a36Sopenharmony_ci dprintk(1, "%s() OFDM\n", __func__); 76462306a36Sopenharmony_ci switch (bw) { 76562306a36Sopenharmony_ci case 6000000: 76662306a36Sopenharmony_ci priv->video_standard = DTV6; 76762306a36Sopenharmony_ci priv->freq_offset = 1750000; 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci case 7000000: 77062306a36Sopenharmony_ci priv->video_standard = DTV7; 77162306a36Sopenharmony_ci priv->freq_offset = 2250000; 77262306a36Sopenharmony_ci break; 77362306a36Sopenharmony_ci case 8000000: 77462306a36Sopenharmony_ci priv->video_standard = DTV8; 77562306a36Sopenharmony_ci priv->freq_offset = 2750000; 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci default: 77862306a36Sopenharmony_ci printk(KERN_ERR "xc5000 bandwidth not set!\n"); 77962306a36Sopenharmony_ci return -EINVAL; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci case SYS_DVBC_ANNEX_A: 78462306a36Sopenharmony_ci case SYS_DVBC_ANNEX_C: 78562306a36Sopenharmony_ci dprintk(1, "%s() QAM modulation\n", __func__); 78662306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 78762306a36Sopenharmony_ci if (bw <= 6000000) { 78862306a36Sopenharmony_ci priv->video_standard = DTV6; 78962306a36Sopenharmony_ci priv->freq_offset = 1750000; 79062306a36Sopenharmony_ci b = 6; 79162306a36Sopenharmony_ci } else if (bw <= 7000000) { 79262306a36Sopenharmony_ci priv->video_standard = DTV7; 79362306a36Sopenharmony_ci priv->freq_offset = 2250000; 79462306a36Sopenharmony_ci b = 7; 79562306a36Sopenharmony_ci } else { 79662306a36Sopenharmony_ci priv->video_standard = DTV7_8; 79762306a36Sopenharmony_ci priv->freq_offset = 2750000; 79862306a36Sopenharmony_ci b = 8; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__, 80162306a36Sopenharmony_ci b, bw); 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci default: 80462306a36Sopenharmony_ci printk(KERN_ERR "xc5000: delivery system is not supported!\n"); 80562306a36Sopenharmony_ci return -EINVAL; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci priv->freq_hz = freq - priv->freq_offset; 80962306a36Sopenharmony_ci priv->mode = V4L2_TUNER_DIGITAL_TV; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci dprintk(1, "%s() frequency=%d (compensated to %d)\n", 81262306a36Sopenharmony_ci __func__, freq, priv->freq_hz); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return xc5000_tune_digital(fe); 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic int xc5000_is_firmware_loaded(struct dvb_frontend *fe) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 82062306a36Sopenharmony_ci int ret; 82162306a36Sopenharmony_ci u16 id; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); 82462306a36Sopenharmony_ci if (!ret) { 82562306a36Sopenharmony_ci if (id == XC_PRODUCT_ID_FW_NOT_LOADED) 82662306a36Sopenharmony_ci ret = -ENOENT; 82762306a36Sopenharmony_ci else 82862306a36Sopenharmony_ci ret = 0; 82962306a36Sopenharmony_ci dprintk(1, "%s() returns id = 0x%x\n", __func__, id); 83062306a36Sopenharmony_ci } else { 83162306a36Sopenharmony_ci dprintk(1, "%s() returns error %d\n", __func__, ret); 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci return ret; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic void xc5000_config_tv(struct dvb_frontend *fe, 83862306a36Sopenharmony_ci struct analog_parameters *params) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", 84362306a36Sopenharmony_ci __func__, params->frequency); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* Fix me: it could be air. */ 84662306a36Sopenharmony_ci priv->rf_mode = params->mode; 84762306a36Sopenharmony_ci if (params->mode > XC_RF_MODE_CABLE) 84862306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* params->frequency is in units of 62.5khz */ 85162306a36Sopenharmony_ci priv->freq_hz = params->frequency * 62500; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* FIX ME: Some video standards may have several possible audio 85462306a36Sopenharmony_ci standards. We simply default to one of them here. 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ci if (params->std & V4L2_STD_MN) { 85762306a36Sopenharmony_ci /* default to BTSC audio standard */ 85862306a36Sopenharmony_ci priv->video_standard = MN_NTSC_PAL_BTSC; 85962306a36Sopenharmony_ci return; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (params->std & V4L2_STD_PAL_BG) { 86362306a36Sopenharmony_ci /* default to NICAM audio standard */ 86462306a36Sopenharmony_ci priv->video_standard = BG_PAL_NICAM; 86562306a36Sopenharmony_ci return; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (params->std & V4L2_STD_PAL_I) { 86962306a36Sopenharmony_ci /* default to NICAM audio standard */ 87062306a36Sopenharmony_ci priv->video_standard = I_PAL_NICAM; 87162306a36Sopenharmony_ci return; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (params->std & V4L2_STD_PAL_DK) { 87562306a36Sopenharmony_ci /* default to NICAM audio standard */ 87662306a36Sopenharmony_ci priv->video_standard = DK_PAL_NICAM; 87762306a36Sopenharmony_ci return; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (params->std & V4L2_STD_SECAM_DK) { 88162306a36Sopenharmony_ci /* default to A2 DK1 audio standard */ 88262306a36Sopenharmony_ci priv->video_standard = DK_SECAM_A2DK1; 88362306a36Sopenharmony_ci return; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (params->std & V4L2_STD_SECAM_L) { 88762306a36Sopenharmony_ci priv->video_standard = L_SECAM_NICAM; 88862306a36Sopenharmony_ci return; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (params->std & V4L2_STD_SECAM_LC) { 89262306a36Sopenharmony_ci priv->video_standard = LC_SECAM_NICAM; 89362306a36Sopenharmony_ci return; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int xc5000_set_tv_freq(struct dvb_frontend *fe) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 90062306a36Sopenharmony_ci u16 pll_lock_status; 90162306a36Sopenharmony_ci int ret; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_citune_channel: 90462306a36Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 90562306a36Sopenharmony_ci if (ret != 0) { 90662306a36Sopenharmony_ci printk(KERN_ERR 90762306a36Sopenharmony_ci "xc5000: xc_set_signal_source(%d) failed\n", 90862306a36Sopenharmony_ci priv->rf_mode); 90962306a36Sopenharmony_ci return -EREMOTEIO; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci ret = xc_set_tv_standard(priv, 91362306a36Sopenharmony_ci xc5000_standard[priv->video_standard].video_mode, 91462306a36Sopenharmony_ci xc5000_standard[priv->video_standard].audio_mode, 0); 91562306a36Sopenharmony_ci if (ret != 0) { 91662306a36Sopenharmony_ci printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); 91762306a36Sopenharmony_ci return -EREMOTEIO; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (debug) 92562306a36Sopenharmony_ci xc_debug_dump(priv); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (priv->pll_register_no != 0) { 92862306a36Sopenharmony_ci msleep(20); 92962306a36Sopenharmony_ci ret = xc5000_readreg(priv, priv->pll_register_no, 93062306a36Sopenharmony_ci &pll_lock_status); 93162306a36Sopenharmony_ci if (ret) 93262306a36Sopenharmony_ci return ret; 93362306a36Sopenharmony_ci if (pll_lock_status > 63) { 93462306a36Sopenharmony_ci /* PLL is unlocked, force reload of the firmware */ 93562306a36Sopenharmony_ci dprintk(1, "xc5000: PLL not locked (0x%x). Reloading...\n", 93662306a36Sopenharmony_ci pll_lock_status); 93762306a36Sopenharmony_ci if (xc_load_fw_and_init_tuner(fe, 1) != 0) { 93862306a36Sopenharmony_ci printk(KERN_ERR "xc5000: Unable to reload fw\n"); 93962306a36Sopenharmony_ci return -EREMOTEIO; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci goto tune_channel; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return 0; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic int xc5000_config_radio(struct dvb_frontend *fe, 94962306a36Sopenharmony_ci struct analog_parameters *params) 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci dprintk(1, "%s() frequency=%d (in units of khz)\n", 95562306a36Sopenharmony_ci __func__, params->frequency); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) { 95862306a36Sopenharmony_ci dprintk(1, "%s() radio input not configured\n", __func__); 95962306a36Sopenharmony_ci return -EINVAL; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci priv->freq_hz = params->frequency * 125 / 2; 96362306a36Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci return 0; 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistatic int xc5000_set_radio_freq(struct dvb_frontend *fe) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 97162306a36Sopenharmony_ci int ret; 97262306a36Sopenharmony_ci u8 radio_input; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (priv->radio_input == XC5000_RADIO_FM1) 97562306a36Sopenharmony_ci radio_input = FM_RADIO_INPUT1; 97662306a36Sopenharmony_ci else if (priv->radio_input == XC5000_RADIO_FM2) 97762306a36Sopenharmony_ci radio_input = FM_RADIO_INPUT2; 97862306a36Sopenharmony_ci else if (priv->radio_input == XC5000_RADIO_FM1_MONO) 97962306a36Sopenharmony_ci radio_input = FM_RADIO_INPUT1_MONO; 98062306a36Sopenharmony_ci else { 98162306a36Sopenharmony_ci dprintk(1, "%s() unknown radio input %d\n", __func__, 98262306a36Sopenharmony_ci priv->radio_input); 98362306a36Sopenharmony_ci return -EINVAL; 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode, 98762306a36Sopenharmony_ci xc5000_standard[radio_input].audio_mode, radio_input); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (ret != 0) { 99062306a36Sopenharmony_ci printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); 99162306a36Sopenharmony_ci return -EREMOTEIO; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 99562306a36Sopenharmony_ci if (ret != 0) { 99662306a36Sopenharmony_ci printk(KERN_ERR 99762306a36Sopenharmony_ci "xc5000: xc_set_signal_source(%d) failed\n", 99862306a36Sopenharmony_ci priv->rf_mode); 99962306a36Sopenharmony_ci return -EREMOTEIO; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if ((priv->radio_input == XC5000_RADIO_FM1) || 100362306a36Sopenharmony_ci (priv->radio_input == XC5000_RADIO_FM2)) 100462306a36Sopenharmony_ci xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); 100562306a36Sopenharmony_ci else if (priv->radio_input == XC5000_RADIO_FM1_MONO) 100662306a36Sopenharmony_ci xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return 0; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic int xc5000_set_params(struct dvb_frontend *fe) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (xc_load_fw_and_init_tuner(fe, 0) != 0) { 101862306a36Sopenharmony_ci dprintk(1, "Unable to load firmware and init tuner\n"); 101962306a36Sopenharmony_ci return -EINVAL; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci switch (priv->mode) { 102362306a36Sopenharmony_ci case V4L2_TUNER_RADIO: 102462306a36Sopenharmony_ci return xc5000_set_radio_freq(fe); 102562306a36Sopenharmony_ci case V4L2_TUNER_ANALOG_TV: 102662306a36Sopenharmony_ci return xc5000_set_tv_freq(fe); 102762306a36Sopenharmony_ci case V4L2_TUNER_DIGITAL_TV: 102862306a36Sopenharmony_ci return xc5000_tune_digital(fe); 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci return 0; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic int xc5000_set_analog_params(struct dvb_frontend *fe, 103562306a36Sopenharmony_ci struct analog_parameters *params) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 103862306a36Sopenharmony_ci int ret; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if (priv->i2c_props.adap == NULL) 104162306a36Sopenharmony_ci return -EINVAL; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci switch (params->mode) { 104462306a36Sopenharmony_ci case V4L2_TUNER_RADIO: 104562306a36Sopenharmony_ci ret = xc5000_config_radio(fe, params); 104662306a36Sopenharmony_ci if (ret) 104762306a36Sopenharmony_ci return ret; 104862306a36Sopenharmony_ci break; 104962306a36Sopenharmony_ci case V4L2_TUNER_ANALOG_TV: 105062306a36Sopenharmony_ci xc5000_config_tv(fe, params); 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci default: 105362306a36Sopenharmony_ci break; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci priv->mode = params->mode; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci return xc5000_set_params(fe); 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_cistatic int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 106362306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 106462306a36Sopenharmony_ci *freq = priv->freq_hz + priv->freq_offset; 106562306a36Sopenharmony_ci return 0; 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 107162306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 107262306a36Sopenharmony_ci *freq = priv->if_khz * 1000; 107362306a36Sopenharmony_ci return 0; 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 107962306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci *bw = priv->bandwidth; 108262306a36Sopenharmony_ci return 0; 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic int xc5000_get_status(struct dvb_frontend *fe, u32 *status) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 108862306a36Sopenharmony_ci u16 lock_status = 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci xc_get_lock_status(priv, &lock_status); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci *status = lock_status; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci return 0; 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 110262306a36Sopenharmony_ci const struct xc5000_fw_cfg *desired_fw = xc5000_assign_firmware(priv->chip_id); 110362306a36Sopenharmony_ci const struct firmware *fw; 110462306a36Sopenharmony_ci int ret, i; 110562306a36Sopenharmony_ci u16 pll_lock_status; 110662306a36Sopenharmony_ci u16 fw_ck; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci cancel_delayed_work(&priv->timer_sleep); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (!force && xc5000_is_firmware_loaded(fe) == 0) 111162306a36Sopenharmony_ci return 0; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (!priv->firmware) { 111462306a36Sopenharmony_ci ret = request_firmware(&fw, desired_fw->name, 111562306a36Sopenharmony_ci priv->i2c_props.adap->dev.parent); 111662306a36Sopenharmony_ci if (ret) { 111762306a36Sopenharmony_ci pr_err("xc5000: Upload failed. rc %d\n", ret); 111862306a36Sopenharmony_ci return ret; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci dprintk(1, "firmware read %zu bytes.\n", fw->size); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (fw->size != desired_fw->size) { 112362306a36Sopenharmony_ci pr_err("xc5000: Firmware file with incorrect size\n"); 112462306a36Sopenharmony_ci release_firmware(fw); 112562306a36Sopenharmony_ci return -EINVAL; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci priv->firmware = fw; 112862306a36Sopenharmony_ci } else 112962306a36Sopenharmony_ci fw = priv->firmware; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci /* Try up to 5 times to load firmware */ 113262306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 113362306a36Sopenharmony_ci if (i) 113462306a36Sopenharmony_ci printk(KERN_CONT " - retrying to upload firmware.\n"); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci ret = xc5000_fwupload(fe, desired_fw, fw); 113762306a36Sopenharmony_ci if (ret != 0) 113862306a36Sopenharmony_ci goto err; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci msleep(20); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (priv->fw_checksum_supported) { 114362306a36Sopenharmony_ci if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)) { 114462306a36Sopenharmony_ci printk(KERN_ERR 114562306a36Sopenharmony_ci "xc5000: FW checksum reading failed."); 114662306a36Sopenharmony_ci continue; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (!fw_ck) { 115062306a36Sopenharmony_ci printk(KERN_ERR 115162306a36Sopenharmony_ci "xc5000: FW checksum failed = 0x%04x.", 115262306a36Sopenharmony_ci fw_ck); 115362306a36Sopenharmony_ci continue; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci /* Start the tuner self-calibration process */ 115862306a36Sopenharmony_ci ret = xc_initialize(priv); 115962306a36Sopenharmony_ci if (ret) { 116062306a36Sopenharmony_ci printk(KERN_ERR "xc5000: Can't request self-calibration."); 116162306a36Sopenharmony_ci continue; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* Wait for calibration to complete. 116562306a36Sopenharmony_ci * We could continue but XC5000 will clock stretch subsequent 116662306a36Sopenharmony_ci * I2C transactions until calibration is complete. This way we 116762306a36Sopenharmony_ci * don't have to rely on clock stretching working. 116862306a36Sopenharmony_ci */ 116962306a36Sopenharmony_ci msleep(100); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (priv->init_status_supported) { 117262306a36Sopenharmony_ci if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck)) { 117362306a36Sopenharmony_ci printk(KERN_ERR 117462306a36Sopenharmony_ci "xc5000: FW failed reading init status."); 117562306a36Sopenharmony_ci continue; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (!fw_ck) { 117962306a36Sopenharmony_ci printk(KERN_ERR 118062306a36Sopenharmony_ci "xc5000: FW init status failed = 0x%04x.", 118162306a36Sopenharmony_ci fw_ck); 118262306a36Sopenharmony_ci continue; 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (priv->pll_register_no) { 118762306a36Sopenharmony_ci ret = xc5000_readreg(priv, priv->pll_register_no, 118862306a36Sopenharmony_ci &pll_lock_status); 118962306a36Sopenharmony_ci if (ret) 119062306a36Sopenharmony_ci continue; 119162306a36Sopenharmony_ci if (pll_lock_status > 63) { 119262306a36Sopenharmony_ci /* PLL is unlocked, force reload of the firmware */ 119362306a36Sopenharmony_ci printk(KERN_ERR 119462306a36Sopenharmony_ci "xc5000: PLL not running after fwload."); 119562306a36Sopenharmony_ci continue; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* Default to "CABLE" mode */ 120062306a36Sopenharmony_ci ret = xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); 120162306a36Sopenharmony_ci if (!ret) 120262306a36Sopenharmony_ci break; 120362306a36Sopenharmony_ci printk(KERN_ERR "xc5000: can't set to cable mode."); 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cierr: 120762306a36Sopenharmony_ci if (!ret) 120862306a36Sopenharmony_ci printk(KERN_INFO "xc5000: Firmware %s loaded and running.\n", 120962306a36Sopenharmony_ci desired_fw->name); 121062306a36Sopenharmony_ci else 121162306a36Sopenharmony_ci printk(KERN_CONT " - too many retries. Giving up\n"); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci return ret; 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic void xc5000_do_timer_sleep(struct work_struct *timer_sleep) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct xc5000_priv *priv =container_of(timer_sleep, struct xc5000_priv, 121962306a36Sopenharmony_ci timer_sleep.work); 122062306a36Sopenharmony_ci struct dvb_frontend *fe = priv->fe; 122162306a36Sopenharmony_ci int ret; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci /* According to Xceive technical support, the "powerdown" register 122662306a36Sopenharmony_ci was removed in newer versions of the firmware. The "supported" 122762306a36Sopenharmony_ci way to sleep the tuner is to pull the reset pin low for 10ms */ 122862306a36Sopenharmony_ci ret = xc5000_tuner_reset(fe); 122962306a36Sopenharmony_ci if (ret != 0) 123062306a36Sopenharmony_ci printk(KERN_ERR 123162306a36Sopenharmony_ci "xc5000: %s() unable to shutdown tuner\n", 123262306a36Sopenharmony_ci __func__); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int xc5000_sleep(struct dvb_frontend *fe) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci /* Avoid firmware reload on slow devices */ 124262306a36Sopenharmony_ci if (no_poweroff) 124362306a36Sopenharmony_ci return 0; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci schedule_delayed_work(&priv->timer_sleep, 124662306a36Sopenharmony_ci msecs_to_jiffies(XC5000_SLEEP_TIME)); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci return 0; 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cistatic int xc5000_suspend(struct dvb_frontend *fe) 125262306a36Sopenharmony_ci{ 125362306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 125462306a36Sopenharmony_ci int ret; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci cancel_delayed_work(&priv->timer_sleep); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci ret = xc5000_tuner_reset(fe); 126162306a36Sopenharmony_ci if (ret != 0) 126262306a36Sopenharmony_ci printk(KERN_ERR 126362306a36Sopenharmony_ci "xc5000: %s() unable to shutdown tuner\n", 126462306a36Sopenharmony_ci __func__); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci return 0; 126762306a36Sopenharmony_ci} 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cistatic int xc5000_resume(struct dvb_frontend *fe) 127062306a36Sopenharmony_ci{ 127162306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* suspended before firmware is loaded. 127662306a36Sopenharmony_ci Avoid firmware load in resume path. */ 127762306a36Sopenharmony_ci if (!priv->firmware) 127862306a36Sopenharmony_ci return 0; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci return xc5000_set_params(fe); 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int xc5000_init(struct dvb_frontend *fe) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 128662306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (xc_load_fw_and_init_tuner(fe, 0) != 0) { 128962306a36Sopenharmony_ci printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); 129062306a36Sopenharmony_ci return -EREMOTEIO; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if (debug) 129462306a36Sopenharmony_ci xc_debug_dump(priv); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci return 0; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic void xc5000_release(struct dvb_frontend *fe) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci mutex_lock(&xc5000_list_mutex); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (priv) { 130862306a36Sopenharmony_ci cancel_delayed_work(&priv->timer_sleep); 130962306a36Sopenharmony_ci if (priv->firmware) { 131062306a36Sopenharmony_ci release_firmware(priv->firmware); 131162306a36Sopenharmony_ci priv->firmware = NULL; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci hybrid_tuner_release_state(priv); 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci mutex_unlock(&xc5000_list_mutex); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci fe->tuner_priv = NULL; 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 132462306a36Sopenharmony_ci struct xc5000_config *p = priv_cfg; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci dprintk(1, "%s()\n", __func__); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (p->if_khz) 132962306a36Sopenharmony_ci priv->if_khz = p->if_khz; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (p->radio_input) 133262306a36Sopenharmony_ci priv->radio_input = p->radio_input; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (p->output_amp) 133562306a36Sopenharmony_ci priv->output_amp = p->output_amp; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci return 0; 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic const struct dvb_tuner_ops xc5000_tuner_ops = { 134262306a36Sopenharmony_ci .info = { 134362306a36Sopenharmony_ci .name = "Xceive XC5000", 134462306a36Sopenharmony_ci .frequency_min_hz = 1 * MHz, 134562306a36Sopenharmony_ci .frequency_max_hz = 1023 * MHz, 134662306a36Sopenharmony_ci .frequency_step_hz = 50 * kHz, 134762306a36Sopenharmony_ci }, 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci .release = xc5000_release, 135062306a36Sopenharmony_ci .init = xc5000_init, 135162306a36Sopenharmony_ci .sleep = xc5000_sleep, 135262306a36Sopenharmony_ci .suspend = xc5000_suspend, 135362306a36Sopenharmony_ci .resume = xc5000_resume, 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci .set_config = xc5000_set_config, 135662306a36Sopenharmony_ci .set_params = xc5000_set_digital_params, 135762306a36Sopenharmony_ci .set_analog_params = xc5000_set_analog_params, 135862306a36Sopenharmony_ci .get_frequency = xc5000_get_frequency, 135962306a36Sopenharmony_ci .get_if_frequency = xc5000_get_if_frequency, 136062306a36Sopenharmony_ci .get_bandwidth = xc5000_get_bandwidth, 136162306a36Sopenharmony_ci .get_status = xc5000_get_status 136262306a36Sopenharmony_ci}; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_cistruct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, 136562306a36Sopenharmony_ci struct i2c_adapter *i2c, 136662306a36Sopenharmony_ci const struct xc5000_config *cfg) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci struct xc5000_priv *priv = NULL; 136962306a36Sopenharmony_ci int instance; 137062306a36Sopenharmony_ci u16 id = 0; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci dprintk(1, "%s(%d-%04x)\n", __func__, 137362306a36Sopenharmony_ci i2c ? i2c_adapter_id(i2c) : -1, 137462306a36Sopenharmony_ci cfg ? cfg->i2c_address : -1); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci mutex_lock(&xc5000_list_mutex); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci instance = hybrid_tuner_request_state(struct xc5000_priv, priv, 137962306a36Sopenharmony_ci hybrid_tuner_instance_list, 138062306a36Sopenharmony_ci i2c, cfg->i2c_address, "xc5000"); 138162306a36Sopenharmony_ci switch (instance) { 138262306a36Sopenharmony_ci case 0: 138362306a36Sopenharmony_ci goto fail; 138462306a36Sopenharmony_ci case 1: 138562306a36Sopenharmony_ci /* new tuner instance */ 138662306a36Sopenharmony_ci priv->bandwidth = 6000000; 138762306a36Sopenharmony_ci fe->tuner_priv = priv; 138862306a36Sopenharmony_ci priv->fe = fe; 138962306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->timer_sleep, xc5000_do_timer_sleep); 139062306a36Sopenharmony_ci break; 139162306a36Sopenharmony_ci default: 139262306a36Sopenharmony_ci /* existing tuner instance */ 139362306a36Sopenharmony_ci fe->tuner_priv = priv; 139462306a36Sopenharmony_ci break; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (priv->if_khz == 0) { 139862306a36Sopenharmony_ci /* If the IF hasn't been set yet, use the value provided by 139962306a36Sopenharmony_ci the caller (occurs in hybrid devices where the analog 140062306a36Sopenharmony_ci call to xc5000_attach occurs before the digital side) */ 140162306a36Sopenharmony_ci priv->if_khz = cfg->if_khz; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (priv->xtal_khz == 0) 140562306a36Sopenharmony_ci priv->xtal_khz = cfg->xtal_khz; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (priv->radio_input == 0) 140862306a36Sopenharmony_ci priv->radio_input = cfg->radio_input; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci /* don't override chip id if it's already been set 141162306a36Sopenharmony_ci unless explicitly specified */ 141262306a36Sopenharmony_ci if ((priv->chip_id == 0) || (cfg->chip_id)) 141362306a36Sopenharmony_ci /* use default chip id if none specified, set to 0 so 141462306a36Sopenharmony_ci it can be overridden if this is a hybrid driver */ 141562306a36Sopenharmony_ci priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci /* don't override output_amp if it's already been set 141862306a36Sopenharmony_ci unless explicitly specified */ 141962306a36Sopenharmony_ci if ((priv->output_amp == 0) || (cfg->output_amp)) 142062306a36Sopenharmony_ci /* use default output_amp value if none specified */ 142162306a36Sopenharmony_ci priv->output_amp = (cfg->output_amp) ? cfg->output_amp : 0x8a; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci /* Check if firmware has been loaded. It is possible that another 142462306a36Sopenharmony_ci instance of the driver has loaded the firmware. 142562306a36Sopenharmony_ci */ 142662306a36Sopenharmony_ci if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) 142762306a36Sopenharmony_ci goto fail; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci switch (id) { 143062306a36Sopenharmony_ci case XC_PRODUCT_ID_FW_LOADED: 143162306a36Sopenharmony_ci printk(KERN_INFO 143262306a36Sopenharmony_ci "xc5000: Successfully identified at address 0x%02x\n", 143362306a36Sopenharmony_ci cfg->i2c_address); 143462306a36Sopenharmony_ci printk(KERN_INFO 143562306a36Sopenharmony_ci "xc5000: Firmware has been loaded previously\n"); 143662306a36Sopenharmony_ci break; 143762306a36Sopenharmony_ci case XC_PRODUCT_ID_FW_NOT_LOADED: 143862306a36Sopenharmony_ci printk(KERN_INFO 143962306a36Sopenharmony_ci "xc5000: Successfully identified at address 0x%02x\n", 144062306a36Sopenharmony_ci cfg->i2c_address); 144162306a36Sopenharmony_ci printk(KERN_INFO 144262306a36Sopenharmony_ci "xc5000: Firmware has not been loaded previously\n"); 144362306a36Sopenharmony_ci break; 144462306a36Sopenharmony_ci default: 144562306a36Sopenharmony_ci printk(KERN_ERR 144662306a36Sopenharmony_ci "xc5000: Device not found at addr 0x%02x (0x%x)\n", 144762306a36Sopenharmony_ci cfg->i2c_address, id); 144862306a36Sopenharmony_ci goto fail; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci mutex_unlock(&xc5000_list_mutex); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, 145462306a36Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci return fe; 145762306a36Sopenharmony_cifail: 145862306a36Sopenharmony_ci mutex_unlock(&xc5000_list_mutex); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci xc5000_release(fe); 146162306a36Sopenharmony_ci return NULL; 146262306a36Sopenharmony_ci} 146362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xc5000_attach); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ciMODULE_AUTHOR("Steven Toth"); 146662306a36Sopenharmony_ciMODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); 146762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 146862306a36Sopenharmony_ciMODULE_FIRMWARE(XC5000A_FIRMWARE); 146962306a36Sopenharmony_ciMODULE_FIRMWARE(XC5000C_FIRMWARE); 1470