18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2007 Xceive Corporation 68c2ecf20Sopenharmony_ci * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> 78c2ecf20Sopenharmony_ci * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 128c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 158c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h> 168c2ecf20Sopenharmony_ci#include <linux/i2c.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "xc5000.h" 218c2ecf20Sopenharmony_ci#include "tuner-i2c.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic int debug; 248c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int no_poweroff; 288c2ecf20Sopenharmony_cimodule_param(no_poweroff, int, 0644); 298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" 308c2ecf20Sopenharmony_ci "\t\t1 keep device energized and with tuner ready all the times.\n" 318c2ecf20Sopenharmony_ci "\t\tFaster, but consumes more power and keeps the device hotter"); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(xc5000_list_mutex); 348c2ecf20Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...) if (debug >= level) \ 378c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct xc5000_priv { 408c2ecf20Sopenharmony_ci struct tuner_i2c_props i2c_props; 418c2ecf20Sopenharmony_ci struct list_head hybrid_tuner_instance_list; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci u32 if_khz; 448c2ecf20Sopenharmony_ci u16 xtal_khz; 458c2ecf20Sopenharmony_ci u32 freq_hz, freq_offset; 468c2ecf20Sopenharmony_ci u32 bandwidth; 478c2ecf20Sopenharmony_ci u8 video_standard; 488c2ecf20Sopenharmony_ci unsigned int mode; 498c2ecf20Sopenharmony_ci u8 rf_mode; 508c2ecf20Sopenharmony_ci u8 radio_input; 518c2ecf20Sopenharmony_ci u16 output_amp; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci int chip_id; 548c2ecf20Sopenharmony_ci u16 pll_register_no; 558c2ecf20Sopenharmony_ci u8 init_status_supported; 568c2ecf20Sopenharmony_ci u8 fw_checksum_supported; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci struct dvb_frontend *fe; 598c2ecf20Sopenharmony_ci struct delayed_work timer_sleep; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci const struct firmware *firmware; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Misc Defines */ 658c2ecf20Sopenharmony_ci#define MAX_TV_STANDARD 24 668c2ecf20Sopenharmony_ci#define XC_MAX_I2C_WRITE_LENGTH 64 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Time to suspend after the .sleep callback is called */ 698c2ecf20Sopenharmony_ci#define XC5000_SLEEP_TIME 5000 /* ms */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* Signal Types */ 728c2ecf20Sopenharmony_ci#define XC_RF_MODE_AIR 0 738c2ecf20Sopenharmony_ci#define XC_RF_MODE_CABLE 1 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* Product id */ 768c2ecf20Sopenharmony_ci#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 778c2ecf20Sopenharmony_ci#define XC_PRODUCT_ID_FW_LOADED 0x1388 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* Registers */ 808c2ecf20Sopenharmony_ci#define XREG_INIT 0x00 818c2ecf20Sopenharmony_ci#define XREG_VIDEO_MODE 0x01 828c2ecf20Sopenharmony_ci#define XREG_AUDIO_MODE 0x02 838c2ecf20Sopenharmony_ci#define XREG_RF_FREQ 0x03 848c2ecf20Sopenharmony_ci#define XREG_D_CODE 0x04 858c2ecf20Sopenharmony_ci#define XREG_IF_OUT 0x05 868c2ecf20Sopenharmony_ci#define XREG_SEEK_MODE 0x07 878c2ecf20Sopenharmony_ci#define XREG_POWER_DOWN 0x0A /* Obsolete */ 888c2ecf20Sopenharmony_ci/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ 898c2ecf20Sopenharmony_ci#define XREG_OUTPUT_AMP 0x0B 908c2ecf20Sopenharmony_ci#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ 918c2ecf20Sopenharmony_ci#define XREG_SMOOTHEDCVBS 0x0E 928c2ecf20Sopenharmony_ci#define XREG_XTALFREQ 0x0F 938c2ecf20Sopenharmony_ci#define XREG_FINERFREQ 0x10 948c2ecf20Sopenharmony_ci#define XREG_DDIMODE 0x11 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define XREG_ADC_ENV 0x00 978c2ecf20Sopenharmony_ci#define XREG_QUALITY 0x01 988c2ecf20Sopenharmony_ci#define XREG_FRAME_LINES 0x02 998c2ecf20Sopenharmony_ci#define XREG_HSYNC_FREQ 0x03 1008c2ecf20Sopenharmony_ci#define XREG_LOCK 0x04 1018c2ecf20Sopenharmony_ci#define XREG_FREQ_ERROR 0x05 1028c2ecf20Sopenharmony_ci#define XREG_SNR 0x06 1038c2ecf20Sopenharmony_ci#define XREG_VERSION 0x07 1048c2ecf20Sopenharmony_ci#define XREG_PRODUCT_ID 0x08 1058c2ecf20Sopenharmony_ci#define XREG_BUSY 0x09 1068c2ecf20Sopenharmony_ci#define XREG_BUILD 0x0D 1078c2ecf20Sopenharmony_ci#define XREG_TOTALGAIN 0x0F 1088c2ecf20Sopenharmony_ci#define XREG_FW_CHECKSUM 0x12 1098c2ecf20Sopenharmony_ci#define XREG_INIT_STATUS 0x13 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci Basic firmware description. This will remain with 1138c2ecf20Sopenharmony_ci the driver for documentation purposes. 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci This represents an I2C firmware file encoded as a 1168c2ecf20Sopenharmony_ci string of unsigned char. Format is as follows: 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB 1198c2ecf20Sopenharmony_ci char[1 ]=len0_LSB -> length of first write transaction 1208c2ecf20Sopenharmony_ci char[2 ]=data0 -> first byte to be sent 1218c2ecf20Sopenharmony_ci char[3 ]=data1 1228c2ecf20Sopenharmony_ci char[4 ]=data2 1238c2ecf20Sopenharmony_ci char[ ]=... 1248c2ecf20Sopenharmony_ci char[M ]=dataN -> last byte to be sent 1258c2ecf20Sopenharmony_ci char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB 1268c2ecf20Sopenharmony_ci char[M+2]=len1_LSB -> length of second write transaction 1278c2ecf20Sopenharmony_ci char[M+3]=data0 1288c2ecf20Sopenharmony_ci char[M+4]=data1 1298c2ecf20Sopenharmony_ci ... 1308c2ecf20Sopenharmony_ci etc. 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci The [len] value should be interpreted as follows: 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci len= len_MSB _ len_LSB 1358c2ecf20Sopenharmony_ci len=1111_1111_1111_1111 : End of I2C_SEQUENCE 1368c2ecf20Sopenharmony_ci len=0000_0000_0000_0000 : Reset command: Do hardware reset 1378c2ecf20Sopenharmony_ci len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) 1388c2ecf20Sopenharmony_ci len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci For the RESET and WAIT commands, the two following bytes will contain 1418c2ecf20Sopenharmony_ci immediately the length of the following transaction. 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci*/ 1448c2ecf20Sopenharmony_cistruct XC_TV_STANDARD { 1458c2ecf20Sopenharmony_ci char *name; 1468c2ecf20Sopenharmony_ci u16 audio_mode; 1478c2ecf20Sopenharmony_ci u16 video_mode; 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* Tuner standards */ 1518c2ecf20Sopenharmony_ci#define MN_NTSC_PAL_BTSC 0 1528c2ecf20Sopenharmony_ci#define MN_NTSC_PAL_A2 1 1538c2ecf20Sopenharmony_ci#define MN_NTSC_PAL_EIAJ 2 1548c2ecf20Sopenharmony_ci#define MN_NTSC_PAL_MONO 3 1558c2ecf20Sopenharmony_ci#define BG_PAL_A2 4 1568c2ecf20Sopenharmony_ci#define BG_PAL_NICAM 5 1578c2ecf20Sopenharmony_ci#define BG_PAL_MONO 6 1588c2ecf20Sopenharmony_ci#define I_PAL_NICAM 7 1598c2ecf20Sopenharmony_ci#define I_PAL_NICAM_MONO 8 1608c2ecf20Sopenharmony_ci#define DK_PAL_A2 9 1618c2ecf20Sopenharmony_ci#define DK_PAL_NICAM 10 1628c2ecf20Sopenharmony_ci#define DK_PAL_MONO 11 1638c2ecf20Sopenharmony_ci#define DK_SECAM_A2DK1 12 1648c2ecf20Sopenharmony_ci#define DK_SECAM_A2LDK3 13 1658c2ecf20Sopenharmony_ci#define DK_SECAM_A2MONO 14 1668c2ecf20Sopenharmony_ci#define L_SECAM_NICAM 15 1678c2ecf20Sopenharmony_ci#define LC_SECAM_NICAM 16 1688c2ecf20Sopenharmony_ci#define DTV6 17 1698c2ecf20Sopenharmony_ci#define DTV8 18 1708c2ecf20Sopenharmony_ci#define DTV7_8 19 1718c2ecf20Sopenharmony_ci#define DTV7 20 1728c2ecf20Sopenharmony_ci#define FM_RADIO_INPUT2 21 1738c2ecf20Sopenharmony_ci#define FM_RADIO_INPUT1 22 1748c2ecf20Sopenharmony_ci#define FM_RADIO_INPUT1_MONO 23 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic struct XC_TV_STANDARD xc5000_standard[MAX_TV_STANDARD] = { 1778c2ecf20Sopenharmony_ci {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, 1788c2ecf20Sopenharmony_ci {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, 1798c2ecf20Sopenharmony_ci {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, 1808c2ecf20Sopenharmony_ci {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, 1818c2ecf20Sopenharmony_ci {"B/G-PAL-A2", 0x0A00, 0x8049}, 1828c2ecf20Sopenharmony_ci {"B/G-PAL-NICAM", 0x0C04, 0x8049}, 1838c2ecf20Sopenharmony_ci {"B/G-PAL-MONO", 0x0878, 0x8059}, 1848c2ecf20Sopenharmony_ci {"I-PAL-NICAM", 0x1080, 0x8009}, 1858c2ecf20Sopenharmony_ci {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, 1868c2ecf20Sopenharmony_ci {"D/K-PAL-A2", 0x1600, 0x8009}, 1878c2ecf20Sopenharmony_ci {"D/K-PAL-NICAM", 0x0E80, 0x8009}, 1888c2ecf20Sopenharmony_ci {"D/K-PAL-MONO", 0x1478, 0x8009}, 1898c2ecf20Sopenharmony_ci {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, 1908c2ecf20Sopenharmony_ci {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009}, 1918c2ecf20Sopenharmony_ci {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, 1928c2ecf20Sopenharmony_ci {"L-SECAM-NICAM", 0x8E82, 0x0009}, 1938c2ecf20Sopenharmony_ci {"L'-SECAM-NICAM", 0x8E82, 0x4009}, 1948c2ecf20Sopenharmony_ci {"DTV6", 0x00C0, 0x8002}, 1958c2ecf20Sopenharmony_ci {"DTV8", 0x00C0, 0x800B}, 1968c2ecf20Sopenharmony_ci {"DTV7/8", 0x00C0, 0x801B}, 1978c2ecf20Sopenharmony_ci {"DTV7", 0x00C0, 0x8007}, 1988c2ecf20Sopenharmony_ci {"FM Radio-INPUT2", 0x9802, 0x9002}, 1998c2ecf20Sopenharmony_ci {"FM Radio-INPUT1", 0x0208, 0x9002}, 2008c2ecf20Sopenharmony_ci {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistruct xc5000_fw_cfg { 2058c2ecf20Sopenharmony_ci char *name; 2068c2ecf20Sopenharmony_ci u16 size; 2078c2ecf20Sopenharmony_ci u16 pll_reg; 2088c2ecf20Sopenharmony_ci u8 init_status_supported; 2098c2ecf20Sopenharmony_ci u8 fw_checksum_supported; 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" 2138c2ecf20Sopenharmony_cistatic const struct xc5000_fw_cfg xc5000a_1_6_114 = { 2148c2ecf20Sopenharmony_ci .name = XC5000A_FIRMWARE, 2158c2ecf20Sopenharmony_ci .size = 12401, 2168c2ecf20Sopenharmony_ci .pll_reg = 0x806c, 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci#define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw" 2208c2ecf20Sopenharmony_cistatic const struct xc5000_fw_cfg xc5000c_41_024_5 = { 2218c2ecf20Sopenharmony_ci .name = XC5000C_FIRMWARE, 2228c2ecf20Sopenharmony_ci .size = 16497, 2238c2ecf20Sopenharmony_ci .pll_reg = 0x13, 2248c2ecf20Sopenharmony_ci .init_status_supported = 1, 2258c2ecf20Sopenharmony_ci .fw_checksum_supported = 1, 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci switch (chip_id) { 2318c2ecf20Sopenharmony_ci default: 2328c2ecf20Sopenharmony_ci case XC5000A: 2338c2ecf20Sopenharmony_ci return &xc5000a_1_6_114; 2348c2ecf20Sopenharmony_ci case XC5000C: 2358c2ecf20Sopenharmony_ci return &xc5000c_41_024_5; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force); 2408c2ecf20Sopenharmony_cistatic int xc5000_is_firmware_loaded(struct dvb_frontend *fe); 2418c2ecf20Sopenharmony_cistatic int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); 2428c2ecf20Sopenharmony_cistatic int xc5000_tuner_reset(struct dvb_frontend *fe); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_props.addr, 2478c2ecf20Sopenharmony_ci .flags = 0, .buf = buf, .len = len }; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { 2508c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); 2518c2ecf20Sopenharmony_ci return -EREMOTEIO; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci#if 0 2578c2ecf20Sopenharmony_ci/* This routine is never used because the only time we read data from the 2588c2ecf20Sopenharmony_ci i2c bus is when we read registers, and we want that to be an atomic i2c 2598c2ecf20Sopenharmony_ci transaction in case we are on a multi-master bus */ 2608c2ecf20Sopenharmony_cistatic int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = priv->i2c_props.addr, 2638c2ecf20Sopenharmony_ci .flags = I2C_M_RD, .buf = buf, .len = len }; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { 2668c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); 2678c2ecf20Sopenharmony_ci return -EREMOTEIO; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci#endif 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci u8 buf[2] = { reg >> 8, reg & 0xff }; 2768c2ecf20Sopenharmony_ci u8 bval[2] = { 0, 0 }; 2778c2ecf20Sopenharmony_ci struct i2c_msg msg[2] = { 2788c2ecf20Sopenharmony_ci { .addr = priv->i2c_props.addr, 2798c2ecf20Sopenharmony_ci .flags = 0, .buf = &buf[0], .len = 2 }, 2808c2ecf20Sopenharmony_ci { .addr = priv->i2c_props.addr, 2818c2ecf20Sopenharmony_ci .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, 2828c2ecf20Sopenharmony_ci }; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { 2858c2ecf20Sopenharmony_ci printk(KERN_WARNING "xc5000: I2C read failed\n"); 2868c2ecf20Sopenharmony_ci return -EREMOTEIO; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci *val = (bval[0] << 8) | bval[1]; 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic int xc5000_tuner_reset(struct dvb_frontend *fe) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 2968c2ecf20Sopenharmony_ci int ret; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (fe->callback) { 3018c2ecf20Sopenharmony_ci ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? 3028c2ecf20Sopenharmony_ci fe->dvb->priv : 3038c2ecf20Sopenharmony_ci priv->i2c_props.adap->algo_data, 3048c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, 3058c2ecf20Sopenharmony_ci XC5000_TUNER_RESET, 0); 3068c2ecf20Sopenharmony_ci if (ret) { 3078c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: reset failed\n"); 3088c2ecf20Sopenharmony_ci return ret; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); 3128c2ecf20Sopenharmony_ci return -EINVAL; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int xc_write_reg(struct xc5000_priv *priv, u16 reg_addr, u16 i2c_data) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci u8 buf[4]; 3208c2ecf20Sopenharmony_ci int watch_dog_timer = 100; 3218c2ecf20Sopenharmony_ci int result; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci buf[0] = (reg_addr >> 8) & 0xFF; 3248c2ecf20Sopenharmony_ci buf[1] = reg_addr & 0xFF; 3258c2ecf20Sopenharmony_ci buf[2] = (i2c_data >> 8) & 0xFF; 3268c2ecf20Sopenharmony_ci buf[3] = i2c_data & 0xFF; 3278c2ecf20Sopenharmony_ci result = xc_send_i2c_data(priv, buf, 4); 3288c2ecf20Sopenharmony_ci if (result == 0) { 3298c2ecf20Sopenharmony_ci /* wait for busy flag to clear */ 3308c2ecf20Sopenharmony_ci while ((watch_dog_timer > 0) && (result == 0)) { 3318c2ecf20Sopenharmony_ci result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); 3328c2ecf20Sopenharmony_ci if (result == 0) { 3338c2ecf20Sopenharmony_ci if ((buf[0] == 0) && (buf[1] == 0)) { 3348c2ecf20Sopenharmony_ci /* busy flag cleared */ 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci } else { 3378c2ecf20Sopenharmony_ci msleep(5); /* wait 5 ms */ 3388c2ecf20Sopenharmony_ci watch_dog_timer--; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci if (watch_dog_timer <= 0) 3448c2ecf20Sopenharmony_ci result = -EREMOTEIO; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return result; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci int i, nbytes_to_send, result; 3548c2ecf20Sopenharmony_ci unsigned int len, pos, index; 3558c2ecf20Sopenharmony_ci u8 buf[XC_MAX_I2C_WRITE_LENGTH]; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci index = 0; 3588c2ecf20Sopenharmony_ci while ((i2c_sequence[index] != 0xFF) || 3598c2ecf20Sopenharmony_ci (i2c_sequence[index + 1] != 0xFF)) { 3608c2ecf20Sopenharmony_ci len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; 3618c2ecf20Sopenharmony_ci if (len == 0x0000) { 3628c2ecf20Sopenharmony_ci /* RESET command */ 3638c2ecf20Sopenharmony_ci result = xc5000_tuner_reset(fe); 3648c2ecf20Sopenharmony_ci index += 2; 3658c2ecf20Sopenharmony_ci if (result != 0) 3668c2ecf20Sopenharmony_ci return result; 3678c2ecf20Sopenharmony_ci } else if (len & 0x8000) { 3688c2ecf20Sopenharmony_ci /* WAIT command */ 3698c2ecf20Sopenharmony_ci msleep(len & 0x7FFF); 3708c2ecf20Sopenharmony_ci index += 2; 3718c2ecf20Sopenharmony_ci } else { 3728c2ecf20Sopenharmony_ci /* Send i2c data whilst ensuring individual transactions 3738c2ecf20Sopenharmony_ci * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci index += 2; 3768c2ecf20Sopenharmony_ci buf[0] = i2c_sequence[index]; 3778c2ecf20Sopenharmony_ci buf[1] = i2c_sequence[index + 1]; 3788c2ecf20Sopenharmony_ci pos = 2; 3798c2ecf20Sopenharmony_ci while (pos < len) { 3808c2ecf20Sopenharmony_ci if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) 3818c2ecf20Sopenharmony_ci nbytes_to_send = 3828c2ecf20Sopenharmony_ci XC_MAX_I2C_WRITE_LENGTH; 3838c2ecf20Sopenharmony_ci else 3848c2ecf20Sopenharmony_ci nbytes_to_send = (len - pos + 2); 3858c2ecf20Sopenharmony_ci for (i = 2; i < nbytes_to_send; i++) { 3868c2ecf20Sopenharmony_ci buf[i] = i2c_sequence[index + pos + 3878c2ecf20Sopenharmony_ci i - 2]; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci result = xc_send_i2c_data(priv, buf, 3908c2ecf20Sopenharmony_ci nbytes_to_send); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (result != 0) 3938c2ecf20Sopenharmony_ci return result; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci pos += nbytes_to_send - 2; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci index += len; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int xc_initialize(struct xc5000_priv *priv) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 4068c2ecf20Sopenharmony_ci return xc_write_reg(priv, XREG_INIT, 0); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int xc_set_tv_standard(struct xc5000_priv *priv, 4108c2ecf20Sopenharmony_ci u16 video_mode, u16 audio_mode, u8 radio_mode) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci int ret; 4138c2ecf20Sopenharmony_ci dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); 4148c2ecf20Sopenharmony_ci if (radio_mode) { 4158c2ecf20Sopenharmony_ci dprintk(1, "%s() Standard = %s\n", 4168c2ecf20Sopenharmony_ci __func__, 4178c2ecf20Sopenharmony_ci xc5000_standard[radio_mode].name); 4188c2ecf20Sopenharmony_ci } else { 4198c2ecf20Sopenharmony_ci dprintk(1, "%s() Standard = %s\n", 4208c2ecf20Sopenharmony_ci __func__, 4218c2ecf20Sopenharmony_ci xc5000_standard[priv->video_standard].name); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); 4258c2ecf20Sopenharmony_ci if (ret == 0) 4268c2ecf20Sopenharmony_ci ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return ret; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int xc_set_signal_source(struct xc5000_priv *priv, u16 rf_mode) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, 4348c2ecf20Sopenharmony_ci rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { 4378c2ecf20Sopenharmony_ci rf_mode = XC_RF_MODE_CABLE; 4388c2ecf20Sopenharmony_ci printk(KERN_ERR 4398c2ecf20Sopenharmony_ci "%s(), Invalid mode, defaulting to CABLE", 4408c2ecf20Sopenharmony_ci __func__); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops xc5000_tuner_ops; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int xc_set_rf_frequency(struct xc5000_priv *priv, u32 freq_hz) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci u16 freq_code; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci dprintk(1, "%s(%u)\n", __func__, freq_hz); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if ((freq_hz > xc5000_tuner_ops.info.frequency_max_hz) || 4548c2ecf20Sopenharmony_ci (freq_hz < xc5000_tuner_ops.info.frequency_min_hz)) 4558c2ecf20Sopenharmony_ci return -EINVAL; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci freq_code = (u16)(freq_hz / 15625); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Starting in firmware version 1.1.44, Xceive recommends using the 4608c2ecf20Sopenharmony_ci FINERFREQ for all normal tuning (the doc indicates reg 0x03 should 4618c2ecf20Sopenharmony_ci only be used for fast scanning for channel lock) */ 4628c2ecf20Sopenharmony_ci return xc_write_reg(priv, XREG_FINERFREQ, freq_code); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci u32 freq_code = (freq_khz * 1024)/1000; 4698c2ecf20Sopenharmony_ci dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", 4708c2ecf20Sopenharmony_ci __func__, freq_khz, freq_code); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return xc_write_reg(priv, XREG_IF_OUT, freq_code); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int xc_get_adc_envelope(struct xc5000_priv *priv, u16 *adc_envelope) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci int result; 4848c2ecf20Sopenharmony_ci u16 reg_data; 4858c2ecf20Sopenharmony_ci u32 tmp; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®_data); 4888c2ecf20Sopenharmony_ci if (result != 0) 4898c2ecf20Sopenharmony_ci return result; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci tmp = (u32)reg_data; 4928c2ecf20Sopenharmony_ci (*freq_error_hz) = (tmp * 15625) / 1000; 4938c2ecf20Sopenharmony_ci return result; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci return xc5000_readreg(priv, XREG_LOCK, lock_status); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int xc_get_version(struct xc5000_priv *priv, 5028c2ecf20Sopenharmony_ci u8 *hw_majorversion, u8 *hw_minorversion, 5038c2ecf20Sopenharmony_ci u8 *fw_majorversion, u8 *fw_minorversion) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci u16 data; 5068c2ecf20Sopenharmony_ci int result; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci result = xc5000_readreg(priv, XREG_VERSION, &data); 5098c2ecf20Sopenharmony_ci if (result != 0) 5108c2ecf20Sopenharmony_ci return result; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci (*hw_majorversion) = (data >> 12) & 0x0F; 5138c2ecf20Sopenharmony_ci (*hw_minorversion) = (data >> 8) & 0x0F; 5148c2ecf20Sopenharmony_ci (*fw_majorversion) = (data >> 4) & 0x0F; 5158c2ecf20Sopenharmony_ci (*fw_minorversion) = data & 0x0F; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci return xc5000_readreg(priv, XREG_BUILD, buildrev); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci u16 reg_data; 5288c2ecf20Sopenharmony_ci int result; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®_data); 5318c2ecf20Sopenharmony_ci if (result != 0) 5328c2ecf20Sopenharmony_ci return result; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci (*hsync_freq_hz) = ((reg_data & 0x0fff) * 763)/100; 5358c2ecf20Sopenharmony_ci return result; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int xc_get_quality(struct xc5000_priv *priv, u16 *quality) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci return xc5000_readreg(priv, XREG_QUALITY, quality); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci return xc5000_readreg(priv, XREG_SNR, snr); 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci#define XC_TUNE_ANALOG 0 5598c2ecf20Sopenharmony_ci#define XC_TUNE_DIGITAL 1 5608c2ecf20Sopenharmony_cistatic int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci dprintk(1, "%s(%u)\n", __func__, freq_hz); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (xc_set_rf_frequency(priv, freq_hz) != 0) 5658c2ecf20Sopenharmony_ci return -EREMOTEIO; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic int xc_set_xtal(struct dvb_frontend *fe) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 5738c2ecf20Sopenharmony_ci int ret = 0; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci switch (priv->chip_id) { 5768c2ecf20Sopenharmony_ci default: 5778c2ecf20Sopenharmony_ci case XC5000A: 5788c2ecf20Sopenharmony_ci /* 32.000 MHz xtal is default */ 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci case XC5000C: 5818c2ecf20Sopenharmony_ci switch (priv->xtal_khz) { 5828c2ecf20Sopenharmony_ci default: 5838c2ecf20Sopenharmony_ci case 32000: 5848c2ecf20Sopenharmony_ci /* 32.000 MHz xtal is default */ 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci case 31875: 5878c2ecf20Sopenharmony_ci /* 31.875 MHz xtal configuration */ 5888c2ecf20Sopenharmony_ci ret = xc_write_reg(priv, 0x000f, 0x8081); 5898c2ecf20Sopenharmony_ci break; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci return ret; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic int xc5000_fwupload(struct dvb_frontend *fe, 5978c2ecf20Sopenharmony_ci const struct xc5000_fw_cfg *desired_fw, 5988c2ecf20Sopenharmony_ci const struct firmware *fw) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 6018c2ecf20Sopenharmony_ci int ret; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* request the firmware, this will block and timeout */ 6048c2ecf20Sopenharmony_ci dprintk(1, "waiting for firmware upload (%s)...\n", 6058c2ecf20Sopenharmony_ci desired_fw->name); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci priv->pll_register_no = desired_fw->pll_reg; 6088c2ecf20Sopenharmony_ci priv->init_status_supported = desired_fw->init_status_supported; 6098c2ecf20Sopenharmony_ci priv->fw_checksum_supported = desired_fw->fw_checksum_supported; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci dprintk(1, "firmware uploading...\n"); 6138c2ecf20Sopenharmony_ci ret = xc_load_i2c_sequence(fe, fw->data); 6148c2ecf20Sopenharmony_ci if (!ret) { 6158c2ecf20Sopenharmony_ci ret = xc_set_xtal(fe); 6168c2ecf20Sopenharmony_ci dprintk(1, "Firmware upload complete...\n"); 6178c2ecf20Sopenharmony_ci } else 6188c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: firmware upload failed...\n"); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return ret; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic void xc_debug_dump(struct xc5000_priv *priv) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci u16 adc_envelope; 6268c2ecf20Sopenharmony_ci u32 freq_error_hz = 0; 6278c2ecf20Sopenharmony_ci u16 lock_status; 6288c2ecf20Sopenharmony_ci u32 hsync_freq_hz = 0; 6298c2ecf20Sopenharmony_ci u16 frame_lines; 6308c2ecf20Sopenharmony_ci u16 quality; 6318c2ecf20Sopenharmony_ci u16 snr; 6328c2ecf20Sopenharmony_ci u16 totalgain; 6338c2ecf20Sopenharmony_ci u8 hw_majorversion = 0, hw_minorversion = 0; 6348c2ecf20Sopenharmony_ci u8 fw_majorversion = 0, fw_minorversion = 0; 6358c2ecf20Sopenharmony_ci u16 fw_buildversion = 0; 6368c2ecf20Sopenharmony_ci u16 regval; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Wait for stats to stabilize. 6398c2ecf20Sopenharmony_ci * Frame Lines needs two frame times after initial lock 6408c2ecf20Sopenharmony_ci * before it is valid. 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_ci msleep(100); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci xc_get_adc_envelope(priv, &adc_envelope); 6458c2ecf20Sopenharmony_ci dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci xc_get_frequency_error(priv, &freq_error_hz); 6488c2ecf20Sopenharmony_ci dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci xc_get_lock_status(priv, &lock_status); 6518c2ecf20Sopenharmony_ci dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", 6528c2ecf20Sopenharmony_ci lock_status); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci xc_get_version(priv, &hw_majorversion, &hw_minorversion, 6558c2ecf20Sopenharmony_ci &fw_majorversion, &fw_minorversion); 6568c2ecf20Sopenharmony_ci xc_get_buildversion(priv, &fw_buildversion); 6578c2ecf20Sopenharmony_ci dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n", 6588c2ecf20Sopenharmony_ci hw_majorversion, hw_minorversion, 6598c2ecf20Sopenharmony_ci fw_majorversion, fw_minorversion, fw_buildversion); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci xc_get_hsync_freq(priv, &hsync_freq_hz); 6628c2ecf20Sopenharmony_ci dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci xc_get_frame_lines(priv, &frame_lines); 6658c2ecf20Sopenharmony_ci dprintk(1, "*** Frame lines = %d\n", frame_lines); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci xc_get_quality(priv, &quality); 6688c2ecf20Sopenharmony_ci dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci xc_get_analogsnr(priv, &snr); 6718c2ecf20Sopenharmony_ci dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci xc_get_totalgain(priv, &totalgain); 6748c2ecf20Sopenharmony_ci dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256, 6758c2ecf20Sopenharmony_ci (totalgain % 256) * 100 / 256); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (priv->pll_register_no) { 6788c2ecf20Sopenharmony_ci if (!xc5000_readreg(priv, priv->pll_register_no, ®val)) 6798c2ecf20Sopenharmony_ci dprintk(1, "*** PLL lock status = 0x%04x\n", regval); 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int xc5000_tune_digital(struct dvb_frontend *fe) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 6868c2ecf20Sopenharmony_ci int ret; 6878c2ecf20Sopenharmony_ci u32 bw = fe->dtv_property_cache.bandwidth_hz; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 6908c2ecf20Sopenharmony_ci if (ret != 0) { 6918c2ecf20Sopenharmony_ci printk(KERN_ERR 6928c2ecf20Sopenharmony_ci "xc5000: xc_set_signal_source(%d) failed\n", 6938c2ecf20Sopenharmony_ci priv->rf_mode); 6948c2ecf20Sopenharmony_ci return -EREMOTEIO; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ret = xc_set_tv_standard(priv, 6988c2ecf20Sopenharmony_ci xc5000_standard[priv->video_standard].video_mode, 6998c2ecf20Sopenharmony_ci xc5000_standard[priv->video_standard].audio_mode, 0); 7008c2ecf20Sopenharmony_ci if (ret != 0) { 7018c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); 7028c2ecf20Sopenharmony_ci return -EREMOTEIO; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci ret = xc_set_IF_frequency(priv, priv->if_khz); 7068c2ecf20Sopenharmony_ci if (ret != 0) { 7078c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", 7088c2ecf20Sopenharmony_ci priv->if_khz); 7098c2ecf20Sopenharmony_ci return -EIO; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci dprintk(1, "%s() setting OUTPUT_AMP to 0x%x\n", 7138c2ecf20Sopenharmony_ci __func__, priv->output_amp); 7148c2ecf20Sopenharmony_ci xc_write_reg(priv, XREG_OUTPUT_AMP, priv->output_amp); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (debug) 7198c2ecf20Sopenharmony_ci xc_debug_dump(priv); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci priv->bandwidth = bw; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return 0; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic int xc5000_set_digital_params(struct dvb_frontend *fe) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci int b; 7298c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 7308c2ecf20Sopenharmony_ci u32 bw = fe->dtv_property_cache.bandwidth_hz; 7318c2ecf20Sopenharmony_ci u32 freq = fe->dtv_property_cache.frequency; 7328c2ecf20Sopenharmony_ci u32 delsys = fe->dtv_property_cache.delivery_system; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (xc_load_fw_and_init_tuner(fe, 0) != 0) { 7358c2ecf20Sopenharmony_ci dprintk(1, "Unable to load firmware and init tuner\n"); 7368c2ecf20Sopenharmony_ci return -EINVAL; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci switch (delsys) { 7428c2ecf20Sopenharmony_ci case SYS_ATSC: 7438c2ecf20Sopenharmony_ci dprintk(1, "%s() VSB modulation\n", __func__); 7448c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 7458c2ecf20Sopenharmony_ci priv->freq_offset = 1750000; 7468c2ecf20Sopenharmony_ci priv->video_standard = DTV6; 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_B: 7498c2ecf20Sopenharmony_ci dprintk(1, "%s() QAM modulation\n", __func__); 7508c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 7518c2ecf20Sopenharmony_ci priv->freq_offset = 1750000; 7528c2ecf20Sopenharmony_ci priv->video_standard = DTV6; 7538c2ecf20Sopenharmony_ci break; 7548c2ecf20Sopenharmony_ci case SYS_ISDBT: 7558c2ecf20Sopenharmony_ci /* All ISDB-T are currently for 6 MHz bw */ 7568c2ecf20Sopenharmony_ci if (!bw) 7578c2ecf20Sopenharmony_ci bw = 6000000; 7588c2ecf20Sopenharmony_ci /* fall to OFDM handling */ 7598c2ecf20Sopenharmony_ci fallthrough; 7608c2ecf20Sopenharmony_ci case SYS_DMBTH: 7618c2ecf20Sopenharmony_ci case SYS_DVBT: 7628c2ecf20Sopenharmony_ci case SYS_DVBT2: 7638c2ecf20Sopenharmony_ci dprintk(1, "%s() OFDM\n", __func__); 7648c2ecf20Sopenharmony_ci switch (bw) { 7658c2ecf20Sopenharmony_ci case 6000000: 7668c2ecf20Sopenharmony_ci priv->video_standard = DTV6; 7678c2ecf20Sopenharmony_ci priv->freq_offset = 1750000; 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci case 7000000: 7708c2ecf20Sopenharmony_ci priv->video_standard = DTV7; 7718c2ecf20Sopenharmony_ci priv->freq_offset = 2250000; 7728c2ecf20Sopenharmony_ci break; 7738c2ecf20Sopenharmony_ci case 8000000: 7748c2ecf20Sopenharmony_ci priv->video_standard = DTV8; 7758c2ecf20Sopenharmony_ci priv->freq_offset = 2750000; 7768c2ecf20Sopenharmony_ci break; 7778c2ecf20Sopenharmony_ci default: 7788c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000 bandwidth not set!\n"); 7798c2ecf20Sopenharmony_ci return -EINVAL; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_A: 7848c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_C: 7858c2ecf20Sopenharmony_ci dprintk(1, "%s() QAM modulation\n", __func__); 7868c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 7878c2ecf20Sopenharmony_ci if (bw <= 6000000) { 7888c2ecf20Sopenharmony_ci priv->video_standard = DTV6; 7898c2ecf20Sopenharmony_ci priv->freq_offset = 1750000; 7908c2ecf20Sopenharmony_ci b = 6; 7918c2ecf20Sopenharmony_ci } else if (bw <= 7000000) { 7928c2ecf20Sopenharmony_ci priv->video_standard = DTV7; 7938c2ecf20Sopenharmony_ci priv->freq_offset = 2250000; 7948c2ecf20Sopenharmony_ci b = 7; 7958c2ecf20Sopenharmony_ci } else { 7968c2ecf20Sopenharmony_ci priv->video_standard = DTV7_8; 7978c2ecf20Sopenharmony_ci priv->freq_offset = 2750000; 7988c2ecf20Sopenharmony_ci b = 8; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__, 8018c2ecf20Sopenharmony_ci b, bw); 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci default: 8048c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: delivery system is not supported!\n"); 8058c2ecf20Sopenharmony_ci return -EINVAL; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci priv->freq_hz = freq - priv->freq_offset; 8098c2ecf20Sopenharmony_ci priv->mode = V4L2_TUNER_DIGITAL_TV; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci dprintk(1, "%s() frequency=%d (compensated to %d)\n", 8128c2ecf20Sopenharmony_ci __func__, freq, priv->freq_hz); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return xc5000_tune_digital(fe); 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int xc5000_is_firmware_loaded(struct dvb_frontend *fe) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 8208c2ecf20Sopenharmony_ci int ret; 8218c2ecf20Sopenharmony_ci u16 id; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); 8248c2ecf20Sopenharmony_ci if (!ret) { 8258c2ecf20Sopenharmony_ci if (id == XC_PRODUCT_ID_FW_NOT_LOADED) 8268c2ecf20Sopenharmony_ci ret = -ENOENT; 8278c2ecf20Sopenharmony_ci else 8288c2ecf20Sopenharmony_ci ret = 0; 8298c2ecf20Sopenharmony_ci dprintk(1, "%s() returns id = 0x%x\n", __func__, id); 8308c2ecf20Sopenharmony_ci } else { 8318c2ecf20Sopenharmony_ci dprintk(1, "%s() returns error %d\n", __func__, ret); 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return ret; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic void xc5000_config_tv(struct dvb_frontend *fe, 8388c2ecf20Sopenharmony_ci struct analog_parameters *params) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", 8438c2ecf20Sopenharmony_ci __func__, params->frequency); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* Fix me: it could be air. */ 8468c2ecf20Sopenharmony_ci priv->rf_mode = params->mode; 8478c2ecf20Sopenharmony_ci if (params->mode > XC_RF_MODE_CABLE) 8488c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_CABLE; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* params->frequency is in units of 62.5khz */ 8518c2ecf20Sopenharmony_ci priv->freq_hz = params->frequency * 62500; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* FIX ME: Some video standards may have several possible audio 8548c2ecf20Sopenharmony_ci standards. We simply default to one of them here. 8558c2ecf20Sopenharmony_ci */ 8568c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_MN) { 8578c2ecf20Sopenharmony_ci /* default to BTSC audio standard */ 8588c2ecf20Sopenharmony_ci priv->video_standard = MN_NTSC_PAL_BTSC; 8598c2ecf20Sopenharmony_ci return; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_PAL_BG) { 8638c2ecf20Sopenharmony_ci /* default to NICAM audio standard */ 8648c2ecf20Sopenharmony_ci priv->video_standard = BG_PAL_NICAM; 8658c2ecf20Sopenharmony_ci return; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_PAL_I) { 8698c2ecf20Sopenharmony_ci /* default to NICAM audio standard */ 8708c2ecf20Sopenharmony_ci priv->video_standard = I_PAL_NICAM; 8718c2ecf20Sopenharmony_ci return; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_PAL_DK) { 8758c2ecf20Sopenharmony_ci /* default to NICAM audio standard */ 8768c2ecf20Sopenharmony_ci priv->video_standard = DK_PAL_NICAM; 8778c2ecf20Sopenharmony_ci return; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_SECAM_DK) { 8818c2ecf20Sopenharmony_ci /* default to A2 DK1 audio standard */ 8828c2ecf20Sopenharmony_ci priv->video_standard = DK_SECAM_A2DK1; 8838c2ecf20Sopenharmony_ci return; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_SECAM_L) { 8878c2ecf20Sopenharmony_ci priv->video_standard = L_SECAM_NICAM; 8888c2ecf20Sopenharmony_ci return; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (params->std & V4L2_STD_SECAM_LC) { 8928c2ecf20Sopenharmony_ci priv->video_standard = LC_SECAM_NICAM; 8938c2ecf20Sopenharmony_ci return; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int xc5000_set_tv_freq(struct dvb_frontend *fe) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 9008c2ecf20Sopenharmony_ci u16 pll_lock_status; 9018c2ecf20Sopenharmony_ci int ret; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_citune_channel: 9048c2ecf20Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 9058c2ecf20Sopenharmony_ci if (ret != 0) { 9068c2ecf20Sopenharmony_ci printk(KERN_ERR 9078c2ecf20Sopenharmony_ci "xc5000: xc_set_signal_source(%d) failed\n", 9088c2ecf20Sopenharmony_ci priv->rf_mode); 9098c2ecf20Sopenharmony_ci return -EREMOTEIO; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci ret = xc_set_tv_standard(priv, 9138c2ecf20Sopenharmony_ci xc5000_standard[priv->video_standard].video_mode, 9148c2ecf20Sopenharmony_ci xc5000_standard[priv->video_standard].audio_mode, 0); 9158c2ecf20Sopenharmony_ci if (ret != 0) { 9168c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); 9178c2ecf20Sopenharmony_ci return -EREMOTEIO; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (debug) 9258c2ecf20Sopenharmony_ci xc_debug_dump(priv); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (priv->pll_register_no != 0) { 9288c2ecf20Sopenharmony_ci msleep(20); 9298c2ecf20Sopenharmony_ci ret = xc5000_readreg(priv, priv->pll_register_no, 9308c2ecf20Sopenharmony_ci &pll_lock_status); 9318c2ecf20Sopenharmony_ci if (ret) 9328c2ecf20Sopenharmony_ci return ret; 9338c2ecf20Sopenharmony_ci if (pll_lock_status > 63) { 9348c2ecf20Sopenharmony_ci /* PLL is unlocked, force reload of the firmware */ 9358c2ecf20Sopenharmony_ci dprintk(1, "xc5000: PLL not locked (0x%x). Reloading...\n", 9368c2ecf20Sopenharmony_ci pll_lock_status); 9378c2ecf20Sopenharmony_ci if (xc_load_fw_and_init_tuner(fe, 1) != 0) { 9388c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: Unable to reload fw\n"); 9398c2ecf20Sopenharmony_ci return -EREMOTEIO; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci goto tune_channel; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci return 0; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic int xc5000_config_radio(struct dvb_frontend *fe, 9498c2ecf20Sopenharmony_ci struct analog_parameters *params) 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci dprintk(1, "%s() frequency=%d (in units of khz)\n", 9558c2ecf20Sopenharmony_ci __func__, params->frequency); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) { 9588c2ecf20Sopenharmony_ci dprintk(1, "%s() radio input not configured\n", __func__); 9598c2ecf20Sopenharmony_ci return -EINVAL; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci priv->freq_hz = params->frequency * 125 / 2; 9638c2ecf20Sopenharmony_ci priv->rf_mode = XC_RF_MODE_AIR; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci return 0; 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic int xc5000_set_radio_freq(struct dvb_frontend *fe) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 9718c2ecf20Sopenharmony_ci int ret; 9728c2ecf20Sopenharmony_ci u8 radio_input; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (priv->radio_input == XC5000_RADIO_FM1) 9758c2ecf20Sopenharmony_ci radio_input = FM_RADIO_INPUT1; 9768c2ecf20Sopenharmony_ci else if (priv->radio_input == XC5000_RADIO_FM2) 9778c2ecf20Sopenharmony_ci radio_input = FM_RADIO_INPUT2; 9788c2ecf20Sopenharmony_ci else if (priv->radio_input == XC5000_RADIO_FM1_MONO) 9798c2ecf20Sopenharmony_ci radio_input = FM_RADIO_INPUT1_MONO; 9808c2ecf20Sopenharmony_ci else { 9818c2ecf20Sopenharmony_ci dprintk(1, "%s() unknown radio input %d\n", __func__, 9828c2ecf20Sopenharmony_ci priv->radio_input); 9838c2ecf20Sopenharmony_ci return -EINVAL; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode, 9878c2ecf20Sopenharmony_ci xc5000_standard[radio_input].audio_mode, radio_input); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (ret != 0) { 9908c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); 9918c2ecf20Sopenharmony_ci return -EREMOTEIO; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci ret = xc_set_signal_source(priv, priv->rf_mode); 9958c2ecf20Sopenharmony_ci if (ret != 0) { 9968c2ecf20Sopenharmony_ci printk(KERN_ERR 9978c2ecf20Sopenharmony_ci "xc5000: xc_set_signal_source(%d) failed\n", 9988c2ecf20Sopenharmony_ci priv->rf_mode); 9998c2ecf20Sopenharmony_ci return -EREMOTEIO; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if ((priv->radio_input == XC5000_RADIO_FM1) || 10038c2ecf20Sopenharmony_ci (priv->radio_input == XC5000_RADIO_FM2)) 10048c2ecf20Sopenharmony_ci xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); 10058c2ecf20Sopenharmony_ci else if (priv->radio_input == XC5000_RADIO_FM1_MONO) 10068c2ecf20Sopenharmony_ci xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic int xc5000_set_params(struct dvb_frontend *fe) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (xc_load_fw_and_init_tuner(fe, 0) != 0) { 10188c2ecf20Sopenharmony_ci dprintk(1, "Unable to load firmware and init tuner\n"); 10198c2ecf20Sopenharmony_ci return -EINVAL; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci switch (priv->mode) { 10238c2ecf20Sopenharmony_ci case V4L2_TUNER_RADIO: 10248c2ecf20Sopenharmony_ci return xc5000_set_radio_freq(fe); 10258c2ecf20Sopenharmony_ci case V4L2_TUNER_ANALOG_TV: 10268c2ecf20Sopenharmony_ci return xc5000_set_tv_freq(fe); 10278c2ecf20Sopenharmony_ci case V4L2_TUNER_DIGITAL_TV: 10288c2ecf20Sopenharmony_ci return xc5000_tune_digital(fe); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci return 0; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic int xc5000_set_analog_params(struct dvb_frontend *fe, 10358c2ecf20Sopenharmony_ci struct analog_parameters *params) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 10388c2ecf20Sopenharmony_ci int ret; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (priv->i2c_props.adap == NULL) 10418c2ecf20Sopenharmony_ci return -EINVAL; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci switch (params->mode) { 10448c2ecf20Sopenharmony_ci case V4L2_TUNER_RADIO: 10458c2ecf20Sopenharmony_ci ret = xc5000_config_radio(fe, params); 10468c2ecf20Sopenharmony_ci if (ret) 10478c2ecf20Sopenharmony_ci return ret; 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci case V4L2_TUNER_ANALOG_TV: 10508c2ecf20Sopenharmony_ci xc5000_config_tv(fe, params); 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci default: 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci priv->mode = params->mode; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci return xc5000_set_params(fe); 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 10638c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10648c2ecf20Sopenharmony_ci *freq = priv->freq_hz + priv->freq_offset; 10658c2ecf20Sopenharmony_ci return 0; 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 10718c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10728c2ecf20Sopenharmony_ci *freq = priv->if_khz * 1000; 10738c2ecf20Sopenharmony_ci return 0; 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 10798c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci *bw = priv->bandwidth; 10828c2ecf20Sopenharmony_ci return 0; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic int xc5000_get_status(struct dvb_frontend *fe, u32 *status) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 10888c2ecf20Sopenharmony_ci u16 lock_status = 0; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci xc_get_lock_status(priv, &lock_status); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci *status = lock_status; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci return 0; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 11028c2ecf20Sopenharmony_ci const struct xc5000_fw_cfg *desired_fw = xc5000_assign_firmware(priv->chip_id); 11038c2ecf20Sopenharmony_ci const struct firmware *fw; 11048c2ecf20Sopenharmony_ci int ret, i; 11058c2ecf20Sopenharmony_ci u16 pll_lock_status; 11068c2ecf20Sopenharmony_ci u16 fw_ck; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci cancel_delayed_work(&priv->timer_sleep); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (!force && xc5000_is_firmware_loaded(fe) == 0) 11118c2ecf20Sopenharmony_ci return 0; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (!priv->firmware) { 11148c2ecf20Sopenharmony_ci ret = request_firmware(&fw, desired_fw->name, 11158c2ecf20Sopenharmony_ci priv->i2c_props.adap->dev.parent); 11168c2ecf20Sopenharmony_ci if (ret) { 11178c2ecf20Sopenharmony_ci pr_err("xc5000: Upload failed. rc %d\n", ret); 11188c2ecf20Sopenharmony_ci return ret; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci dprintk(1, "firmware read %zu bytes.\n", fw->size); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (fw->size != desired_fw->size) { 11238c2ecf20Sopenharmony_ci pr_err("xc5000: Firmware file with incorrect size\n"); 11248c2ecf20Sopenharmony_ci release_firmware(fw); 11258c2ecf20Sopenharmony_ci return -EINVAL; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci priv->firmware = fw; 11288c2ecf20Sopenharmony_ci } else 11298c2ecf20Sopenharmony_ci fw = priv->firmware; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* Try up to 5 times to load firmware */ 11328c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 11338c2ecf20Sopenharmony_ci if (i) 11348c2ecf20Sopenharmony_ci printk(KERN_CONT " - retrying to upload firmware.\n"); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci ret = xc5000_fwupload(fe, desired_fw, fw); 11378c2ecf20Sopenharmony_ci if (ret != 0) 11388c2ecf20Sopenharmony_ci goto err; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci msleep(20); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (priv->fw_checksum_supported) { 11438c2ecf20Sopenharmony_ci if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)) { 11448c2ecf20Sopenharmony_ci printk(KERN_ERR 11458c2ecf20Sopenharmony_ci "xc5000: FW checksum reading failed."); 11468c2ecf20Sopenharmony_ci continue; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (!fw_ck) { 11508c2ecf20Sopenharmony_ci printk(KERN_ERR 11518c2ecf20Sopenharmony_ci "xc5000: FW checksum failed = 0x%04x.", 11528c2ecf20Sopenharmony_ci fw_ck); 11538c2ecf20Sopenharmony_ci continue; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* Start the tuner self-calibration process */ 11588c2ecf20Sopenharmony_ci ret = xc_initialize(priv); 11598c2ecf20Sopenharmony_ci if (ret) { 11608c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: Can't request self-calibration."); 11618c2ecf20Sopenharmony_ci continue; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* Wait for calibration to complete. 11658c2ecf20Sopenharmony_ci * We could continue but XC5000 will clock stretch subsequent 11668c2ecf20Sopenharmony_ci * I2C transactions until calibration is complete. This way we 11678c2ecf20Sopenharmony_ci * don't have to rely on clock stretching working. 11688c2ecf20Sopenharmony_ci */ 11698c2ecf20Sopenharmony_ci msleep(100); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (priv->init_status_supported) { 11728c2ecf20Sopenharmony_ci if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck)) { 11738c2ecf20Sopenharmony_ci printk(KERN_ERR 11748c2ecf20Sopenharmony_ci "xc5000: FW failed reading init status."); 11758c2ecf20Sopenharmony_ci continue; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (!fw_ck) { 11798c2ecf20Sopenharmony_ci printk(KERN_ERR 11808c2ecf20Sopenharmony_ci "xc5000: FW init status failed = 0x%04x.", 11818c2ecf20Sopenharmony_ci fw_ck); 11828c2ecf20Sopenharmony_ci continue; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci if (priv->pll_register_no) { 11878c2ecf20Sopenharmony_ci ret = xc5000_readreg(priv, priv->pll_register_no, 11888c2ecf20Sopenharmony_ci &pll_lock_status); 11898c2ecf20Sopenharmony_ci if (ret) 11908c2ecf20Sopenharmony_ci continue; 11918c2ecf20Sopenharmony_ci if (pll_lock_status > 63) { 11928c2ecf20Sopenharmony_ci /* PLL is unlocked, force reload of the firmware */ 11938c2ecf20Sopenharmony_ci printk(KERN_ERR 11948c2ecf20Sopenharmony_ci "xc5000: PLL not running after fwload."); 11958c2ecf20Sopenharmony_ci continue; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Default to "CABLE" mode */ 12008c2ecf20Sopenharmony_ci ret = xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); 12018c2ecf20Sopenharmony_ci if (!ret) 12028c2ecf20Sopenharmony_ci break; 12038c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: can't set to cable mode."); 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cierr: 12078c2ecf20Sopenharmony_ci if (!ret) 12088c2ecf20Sopenharmony_ci printk(KERN_INFO "xc5000: Firmware %s loaded and running.\n", 12098c2ecf20Sopenharmony_ci desired_fw->name); 12108c2ecf20Sopenharmony_ci else 12118c2ecf20Sopenharmony_ci printk(KERN_CONT " - too many retries. Giving up\n"); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci return ret; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic void xc5000_do_timer_sleep(struct work_struct *timer_sleep) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct xc5000_priv *priv =container_of(timer_sleep, struct xc5000_priv, 12198c2ecf20Sopenharmony_ci timer_sleep.work); 12208c2ecf20Sopenharmony_ci struct dvb_frontend *fe = priv->fe; 12218c2ecf20Sopenharmony_ci int ret; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci /* According to Xceive technical support, the "powerdown" register 12268c2ecf20Sopenharmony_ci was removed in newer versions of the firmware. The "supported" 12278c2ecf20Sopenharmony_ci way to sleep the tuner is to pull the reset pin low for 10ms */ 12288c2ecf20Sopenharmony_ci ret = xc5000_tuner_reset(fe); 12298c2ecf20Sopenharmony_ci if (ret != 0) 12308c2ecf20Sopenharmony_ci printk(KERN_ERR 12318c2ecf20Sopenharmony_ci "xc5000: %s() unable to shutdown tuner\n", 12328c2ecf20Sopenharmony_ci __func__); 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_cistatic int xc5000_sleep(struct dvb_frontend *fe) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* Avoid firmware reload on slow devices */ 12428c2ecf20Sopenharmony_ci if (no_poweroff) 12438c2ecf20Sopenharmony_ci return 0; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci schedule_delayed_work(&priv->timer_sleep, 12468c2ecf20Sopenharmony_ci msecs_to_jiffies(XC5000_SLEEP_TIME)); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci return 0; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_cistatic int xc5000_suspend(struct dvb_frontend *fe) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 12548c2ecf20Sopenharmony_ci int ret; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci cancel_delayed_work(&priv->timer_sleep); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci ret = xc5000_tuner_reset(fe); 12618c2ecf20Sopenharmony_ci if (ret != 0) 12628c2ecf20Sopenharmony_ci printk(KERN_ERR 12638c2ecf20Sopenharmony_ci "xc5000: %s() unable to shutdown tuner\n", 12648c2ecf20Sopenharmony_ci __func__); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci return 0; 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic int xc5000_resume(struct dvb_frontend *fe) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* suspended before firmware is loaded. 12768c2ecf20Sopenharmony_ci Avoid firmware load in resume path. */ 12778c2ecf20Sopenharmony_ci if (!priv->firmware) 12788c2ecf20Sopenharmony_ci return 0; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci return xc5000_set_params(fe); 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic int xc5000_init(struct dvb_frontend *fe) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 12868c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (xc_load_fw_and_init_tuner(fe, 0) != 0) { 12898c2ecf20Sopenharmony_ci printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); 12908c2ecf20Sopenharmony_ci return -EREMOTEIO; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (debug) 12948c2ecf20Sopenharmony_ci xc_debug_dump(priv); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci return 0; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic void xc5000_release(struct dvb_frontend *fe) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci mutex_lock(&xc5000_list_mutex); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci if (priv) { 13088c2ecf20Sopenharmony_ci cancel_delayed_work(&priv->timer_sleep); 13098c2ecf20Sopenharmony_ci if (priv->firmware) { 13108c2ecf20Sopenharmony_ci release_firmware(priv->firmware); 13118c2ecf20Sopenharmony_ci priv->firmware = NULL; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci hybrid_tuner_release_state(priv); 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci mutex_unlock(&xc5000_list_mutex); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci struct xc5000_priv *priv = fe->tuner_priv; 13248c2ecf20Sopenharmony_ci struct xc5000_config *p = priv_cfg; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci dprintk(1, "%s()\n", __func__); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci if (p->if_khz) 13298c2ecf20Sopenharmony_ci priv->if_khz = p->if_khz; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (p->radio_input) 13328c2ecf20Sopenharmony_ci priv->radio_input = p->radio_input; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (p->output_amp) 13358c2ecf20Sopenharmony_ci priv->output_amp = p->output_amp; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci return 0; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops xc5000_tuner_ops = { 13428c2ecf20Sopenharmony_ci .info = { 13438c2ecf20Sopenharmony_ci .name = "Xceive XC5000", 13448c2ecf20Sopenharmony_ci .frequency_min_hz = 1 * MHz, 13458c2ecf20Sopenharmony_ci .frequency_max_hz = 1023 * MHz, 13468c2ecf20Sopenharmony_ci .frequency_step_hz = 50 * kHz, 13478c2ecf20Sopenharmony_ci }, 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci .release = xc5000_release, 13508c2ecf20Sopenharmony_ci .init = xc5000_init, 13518c2ecf20Sopenharmony_ci .sleep = xc5000_sleep, 13528c2ecf20Sopenharmony_ci .suspend = xc5000_suspend, 13538c2ecf20Sopenharmony_ci .resume = xc5000_resume, 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci .set_config = xc5000_set_config, 13568c2ecf20Sopenharmony_ci .set_params = xc5000_set_digital_params, 13578c2ecf20Sopenharmony_ci .set_analog_params = xc5000_set_analog_params, 13588c2ecf20Sopenharmony_ci .get_frequency = xc5000_get_frequency, 13598c2ecf20Sopenharmony_ci .get_if_frequency = xc5000_get_if_frequency, 13608c2ecf20Sopenharmony_ci .get_bandwidth = xc5000_get_bandwidth, 13618c2ecf20Sopenharmony_ci .get_status = xc5000_get_status 13628c2ecf20Sopenharmony_ci}; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cistruct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, 13658c2ecf20Sopenharmony_ci struct i2c_adapter *i2c, 13668c2ecf20Sopenharmony_ci const struct xc5000_config *cfg) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci struct xc5000_priv *priv = NULL; 13698c2ecf20Sopenharmony_ci int instance; 13708c2ecf20Sopenharmony_ci u16 id = 0; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci dprintk(1, "%s(%d-%04x)\n", __func__, 13738c2ecf20Sopenharmony_ci i2c ? i2c_adapter_id(i2c) : -1, 13748c2ecf20Sopenharmony_ci cfg ? cfg->i2c_address : -1); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci mutex_lock(&xc5000_list_mutex); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci instance = hybrid_tuner_request_state(struct xc5000_priv, priv, 13798c2ecf20Sopenharmony_ci hybrid_tuner_instance_list, 13808c2ecf20Sopenharmony_ci i2c, cfg->i2c_address, "xc5000"); 13818c2ecf20Sopenharmony_ci switch (instance) { 13828c2ecf20Sopenharmony_ci case 0: 13838c2ecf20Sopenharmony_ci goto fail; 13848c2ecf20Sopenharmony_ci case 1: 13858c2ecf20Sopenharmony_ci /* new tuner instance */ 13868c2ecf20Sopenharmony_ci priv->bandwidth = 6000000; 13878c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 13888c2ecf20Sopenharmony_ci priv->fe = fe; 13898c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&priv->timer_sleep, xc5000_do_timer_sleep); 13908c2ecf20Sopenharmony_ci break; 13918c2ecf20Sopenharmony_ci default: 13928c2ecf20Sopenharmony_ci /* existing tuner instance */ 13938c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 13948c2ecf20Sopenharmony_ci break; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (priv->if_khz == 0) { 13988c2ecf20Sopenharmony_ci /* If the IF hasn't been set yet, use the value provided by 13998c2ecf20Sopenharmony_ci the caller (occurs in hybrid devices where the analog 14008c2ecf20Sopenharmony_ci call to xc5000_attach occurs before the digital side) */ 14018c2ecf20Sopenharmony_ci priv->if_khz = cfg->if_khz; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci if (priv->xtal_khz == 0) 14058c2ecf20Sopenharmony_ci priv->xtal_khz = cfg->xtal_khz; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (priv->radio_input == 0) 14088c2ecf20Sopenharmony_ci priv->radio_input = cfg->radio_input; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci /* don't override chip id if it's already been set 14118c2ecf20Sopenharmony_ci unless explicitly specified */ 14128c2ecf20Sopenharmony_ci if ((priv->chip_id == 0) || (cfg->chip_id)) 14138c2ecf20Sopenharmony_ci /* use default chip id if none specified, set to 0 so 14148c2ecf20Sopenharmony_ci it can be overridden if this is a hybrid driver */ 14158c2ecf20Sopenharmony_ci priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* don't override output_amp if it's already been set 14188c2ecf20Sopenharmony_ci unless explicitly specified */ 14198c2ecf20Sopenharmony_ci if ((priv->output_amp == 0) || (cfg->output_amp)) 14208c2ecf20Sopenharmony_ci /* use default output_amp value if none specified */ 14218c2ecf20Sopenharmony_ci priv->output_amp = (cfg->output_amp) ? cfg->output_amp : 0x8a; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* Check if firmware has been loaded. It is possible that another 14248c2ecf20Sopenharmony_ci instance of the driver has loaded the firmware. 14258c2ecf20Sopenharmony_ci */ 14268c2ecf20Sopenharmony_ci if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) 14278c2ecf20Sopenharmony_ci goto fail; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci switch (id) { 14308c2ecf20Sopenharmony_ci case XC_PRODUCT_ID_FW_LOADED: 14318c2ecf20Sopenharmony_ci printk(KERN_INFO 14328c2ecf20Sopenharmony_ci "xc5000: Successfully identified at address 0x%02x\n", 14338c2ecf20Sopenharmony_ci cfg->i2c_address); 14348c2ecf20Sopenharmony_ci printk(KERN_INFO 14358c2ecf20Sopenharmony_ci "xc5000: Firmware has been loaded previously\n"); 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci case XC_PRODUCT_ID_FW_NOT_LOADED: 14388c2ecf20Sopenharmony_ci printk(KERN_INFO 14398c2ecf20Sopenharmony_ci "xc5000: Successfully identified at address 0x%02x\n", 14408c2ecf20Sopenharmony_ci cfg->i2c_address); 14418c2ecf20Sopenharmony_ci printk(KERN_INFO 14428c2ecf20Sopenharmony_ci "xc5000: Firmware has not been loaded previously\n"); 14438c2ecf20Sopenharmony_ci break; 14448c2ecf20Sopenharmony_ci default: 14458c2ecf20Sopenharmony_ci printk(KERN_ERR 14468c2ecf20Sopenharmony_ci "xc5000: Device not found at addr 0x%02x (0x%x)\n", 14478c2ecf20Sopenharmony_ci cfg->i2c_address, id); 14488c2ecf20Sopenharmony_ci goto fail; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci mutex_unlock(&xc5000_list_mutex); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, 14548c2ecf20Sopenharmony_ci sizeof(struct dvb_tuner_ops)); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci return fe; 14578c2ecf20Sopenharmony_cifail: 14588c2ecf20Sopenharmony_ci mutex_unlock(&xc5000_list_mutex); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci xc5000_release(fe); 14618c2ecf20Sopenharmony_ci return NULL; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xc5000_attach); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steven Toth"); 14668c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); 14678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 14688c2ecf20Sopenharmony_ciMODULE_FIRMWARE(XC5000A_FIRMWARE); 14698c2ecf20Sopenharmony_ciMODULE_FIRMWARE(XC5000C_FIRMWARE); 1470