18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// tuner-xc2028 38c2ecf20Sopenharmony_ci// 48c2ecf20Sopenharmony_ci// Copyright (c) 2007-2008 Mauro Carvalho Chehab <mchehab@kernel.org> 58c2ecf20Sopenharmony_ci// 68c2ecf20Sopenharmony_ci// Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) 78c2ecf20Sopenharmony_ci// - frontend interface 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/i2c.h> 108c2ecf20Sopenharmony_ci#include <asm/div64.h> 118c2ecf20Sopenharmony_ci#include <linux/firmware.h> 128c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <media/tuner.h> 158c2ecf20Sopenharmony_ci#include <linux/mutex.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 188c2ecf20Sopenharmony_ci#include "tuner-i2c.h" 198c2ecf20Sopenharmony_ci#include "tuner-xc2028.h" 208c2ecf20Sopenharmony_ci#include "tuner-xc2028-types.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/dvb/frontend.h> 238c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Max transfer size done by I2C transfer functions */ 268c2ecf20Sopenharmony_ci#define MAX_XFER_SIZE 80 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Registers (Write-only) */ 298c2ecf20Sopenharmony_ci#define XREG_INIT 0x00 308c2ecf20Sopenharmony_ci#define XREG_RF_FREQ 0x02 318c2ecf20Sopenharmony_ci#define XREG_POWER_DOWN 0x08 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Registers (Read-only) */ 348c2ecf20Sopenharmony_ci#define XREG_FREQ_ERROR 0x01 358c2ecf20Sopenharmony_ci#define XREG_LOCK 0x02 368c2ecf20Sopenharmony_ci#define XREG_VERSION 0x04 378c2ecf20Sopenharmony_ci#define XREG_PRODUCT_ID 0x08 388c2ecf20Sopenharmony_ci#define XREG_HSYNC_FREQ 0x10 398c2ecf20Sopenharmony_ci#define XREG_FRAME_LINES 0x20 408c2ecf20Sopenharmony_ci#define XREG_SNR 0x40 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define XREG_ADC_ENV 0x0100 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int debug; 458c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "enable verbose debug messages"); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int no_poweroff; 498c2ecf20Sopenharmony_cimodule_param(no_poweroff, int, 0644); 508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" 518c2ecf20Sopenharmony_ci "1 keep device energized and with tuner ready all the times.\n" 528c2ecf20Sopenharmony_ci " Faster, but consumes more power and keeps the device hotter\n"); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic char audio_std[8]; 558c2ecf20Sopenharmony_cimodule_param_string(audio_std, audio_std, sizeof(audio_std), 0); 568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(audio_std, 578c2ecf20Sopenharmony_ci "Audio standard. XC3028 audio decoder explicitly needs to know what audio\n" 588c2ecf20Sopenharmony_ci "standard is needed for some video standards with audio A2 or NICAM.\n" 598c2ecf20Sopenharmony_ci "The valid values are:\n" 608c2ecf20Sopenharmony_ci "A2\n" 618c2ecf20Sopenharmony_ci "A2/A\n" 628c2ecf20Sopenharmony_ci "A2/B\n" 638c2ecf20Sopenharmony_ci "NICAM\n" 648c2ecf20Sopenharmony_ci "NICAM/A\n" 658c2ecf20Sopenharmony_ci "NICAM/B\n"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic char firmware_name[30]; 688c2ecf20Sopenharmony_cimodule_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); 698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(firmware_name, 708c2ecf20Sopenharmony_ci "Firmware file name. Allows overriding the default firmware name\n"); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list); 738c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(xc2028_list_mutex); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* struct for storing firmware table */ 768c2ecf20Sopenharmony_cistruct firmware_description { 778c2ecf20Sopenharmony_ci unsigned int type; 788c2ecf20Sopenharmony_ci v4l2_std_id id; 798c2ecf20Sopenharmony_ci __u16 int_freq; 808c2ecf20Sopenharmony_ci unsigned char *ptr; 818c2ecf20Sopenharmony_ci unsigned int size; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct firmware_properties { 858c2ecf20Sopenharmony_ci unsigned int type; 868c2ecf20Sopenharmony_ci v4l2_std_id id; 878c2ecf20Sopenharmony_ci v4l2_std_id std_req; 888c2ecf20Sopenharmony_ci __u16 int_freq; 898c2ecf20Sopenharmony_ci unsigned int scode_table; 908c2ecf20Sopenharmony_ci int scode_nr; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cienum xc2028_state { 948c2ecf20Sopenharmony_ci XC2028_NO_FIRMWARE = 0, 958c2ecf20Sopenharmony_ci XC2028_WAITING_FIRMWARE, 968c2ecf20Sopenharmony_ci XC2028_ACTIVE, 978c2ecf20Sopenharmony_ci XC2028_SLEEP, 988c2ecf20Sopenharmony_ci XC2028_NODEV, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct xc2028_data { 1028c2ecf20Sopenharmony_ci struct list_head hybrid_tuner_instance_list; 1038c2ecf20Sopenharmony_ci struct tuner_i2c_props i2c_props; 1048c2ecf20Sopenharmony_ci __u32 frequency; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci enum xc2028_state state; 1078c2ecf20Sopenharmony_ci const char *fname; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci struct firmware_description *firm; 1108c2ecf20Sopenharmony_ci int firm_size; 1118c2ecf20Sopenharmony_ci __u16 firm_version; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci __u16 hwmodel; 1148c2ecf20Sopenharmony_ci __u16 hwvers; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci struct xc2028_ctrl ctrl; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci struct firmware_properties cur_fw; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci struct mutex lock; 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#define i2c_send(priv, buf, size) ({ \ 1248c2ecf20Sopenharmony_ci int _rc; \ 1258c2ecf20Sopenharmony_ci _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ 1268c2ecf20Sopenharmony_ci if (size != _rc) \ 1278c2ecf20Sopenharmony_ci tuner_info("i2c output error: rc = %d (should be %d)\n",\ 1288c2ecf20Sopenharmony_ci _rc, (int)size); \ 1298c2ecf20Sopenharmony_ci if (priv->ctrl.msleep) \ 1308c2ecf20Sopenharmony_ci msleep(priv->ctrl.msleep); \ 1318c2ecf20Sopenharmony_ci _rc; \ 1328c2ecf20Sopenharmony_ci}) 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ 1358c2ecf20Sopenharmony_ci int _rc; \ 1368c2ecf20Sopenharmony_ci _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ 1378c2ecf20Sopenharmony_ci ibuf, isize); \ 1388c2ecf20Sopenharmony_ci if (isize != _rc) \ 1398c2ecf20Sopenharmony_ci tuner_err("i2c input error: rc = %d (should be %d)\n", \ 1408c2ecf20Sopenharmony_ci _rc, (int)isize); \ 1418c2ecf20Sopenharmony_ci if (priv->ctrl.msleep) \ 1428c2ecf20Sopenharmony_ci msleep(priv->ctrl.msleep); \ 1438c2ecf20Sopenharmony_ci _rc; \ 1448c2ecf20Sopenharmony_ci}) 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#define send_seq(priv, data...) ({ \ 1478c2ecf20Sopenharmony_ci static u8 _val[] = data; \ 1488c2ecf20Sopenharmony_ci int _rc; \ 1498c2ecf20Sopenharmony_ci if (sizeof(_val) != \ 1508c2ecf20Sopenharmony_ci (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ 1518c2ecf20Sopenharmony_ci _val, sizeof(_val)))) { \ 1528c2ecf20Sopenharmony_ci tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ 1538c2ecf20Sopenharmony_ci } else if (priv->ctrl.msleep) \ 1548c2ecf20Sopenharmony_ci msleep(priv->ctrl.msleep); \ 1558c2ecf20Sopenharmony_ci _rc; \ 1568c2ecf20Sopenharmony_ci}) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci unsigned char buf[2]; 1618c2ecf20Sopenharmony_ci unsigned char ibuf[2]; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci tuner_dbg("%s %04x called\n", __func__, reg); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci buf[0] = reg >> 8; 1668c2ecf20Sopenharmony_ci buf[1] = (unsigned char) reg; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) 1698c2ecf20Sopenharmony_ci return -EIO; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci *val = (ibuf[1]) | (ibuf[0] << 8); 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) 1768c2ecf20Sopenharmony_cistatic void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci if (type & BASE) 1798c2ecf20Sopenharmony_ci printk(KERN_CONT "BASE "); 1808c2ecf20Sopenharmony_ci if (type & INIT1) 1818c2ecf20Sopenharmony_ci printk(KERN_CONT "INIT1 "); 1828c2ecf20Sopenharmony_ci if (type & F8MHZ) 1838c2ecf20Sopenharmony_ci printk(KERN_CONT "F8MHZ "); 1848c2ecf20Sopenharmony_ci if (type & MTS) 1858c2ecf20Sopenharmony_ci printk(KERN_CONT "MTS "); 1868c2ecf20Sopenharmony_ci if (type & D2620) 1878c2ecf20Sopenharmony_ci printk(KERN_CONT "D2620 "); 1888c2ecf20Sopenharmony_ci if (type & D2633) 1898c2ecf20Sopenharmony_ci printk(KERN_CONT "D2633 "); 1908c2ecf20Sopenharmony_ci if (type & DTV6) 1918c2ecf20Sopenharmony_ci printk(KERN_CONT "DTV6 "); 1928c2ecf20Sopenharmony_ci if (type & QAM) 1938c2ecf20Sopenharmony_ci printk(KERN_CONT "QAM "); 1948c2ecf20Sopenharmony_ci if (type & DTV7) 1958c2ecf20Sopenharmony_ci printk(KERN_CONT "DTV7 "); 1968c2ecf20Sopenharmony_ci if (type & DTV78) 1978c2ecf20Sopenharmony_ci printk(KERN_CONT "DTV78 "); 1988c2ecf20Sopenharmony_ci if (type & DTV8) 1998c2ecf20Sopenharmony_ci printk(KERN_CONT "DTV8 "); 2008c2ecf20Sopenharmony_ci if (type & FM) 2018c2ecf20Sopenharmony_ci printk(KERN_CONT "FM "); 2028c2ecf20Sopenharmony_ci if (type & INPUT1) 2038c2ecf20Sopenharmony_ci printk(KERN_CONT "INPUT1 "); 2048c2ecf20Sopenharmony_ci if (type & LCD) 2058c2ecf20Sopenharmony_ci printk(KERN_CONT "LCD "); 2068c2ecf20Sopenharmony_ci if (type & NOGD) 2078c2ecf20Sopenharmony_ci printk(KERN_CONT "NOGD "); 2088c2ecf20Sopenharmony_ci if (type & MONO) 2098c2ecf20Sopenharmony_ci printk(KERN_CONT "MONO "); 2108c2ecf20Sopenharmony_ci if (type & ATSC) 2118c2ecf20Sopenharmony_ci printk(KERN_CONT "ATSC "); 2128c2ecf20Sopenharmony_ci if (type & IF) 2138c2ecf20Sopenharmony_ci printk(KERN_CONT "IF "); 2148c2ecf20Sopenharmony_ci if (type & LG60) 2158c2ecf20Sopenharmony_ci printk(KERN_CONT "LG60 "); 2168c2ecf20Sopenharmony_ci if (type & ATI638) 2178c2ecf20Sopenharmony_ci printk(KERN_CONT "ATI638 "); 2188c2ecf20Sopenharmony_ci if (type & OREN538) 2198c2ecf20Sopenharmony_ci printk(KERN_CONT "OREN538 "); 2208c2ecf20Sopenharmony_ci if (type & OREN36) 2218c2ecf20Sopenharmony_ci printk(KERN_CONT "OREN36 "); 2228c2ecf20Sopenharmony_ci if (type & TOYOTA388) 2238c2ecf20Sopenharmony_ci printk(KERN_CONT "TOYOTA388 "); 2248c2ecf20Sopenharmony_ci if (type & TOYOTA794) 2258c2ecf20Sopenharmony_ci printk(KERN_CONT "TOYOTA794 "); 2268c2ecf20Sopenharmony_ci if (type & DIBCOM52) 2278c2ecf20Sopenharmony_ci printk(KERN_CONT "DIBCOM52 "); 2288c2ecf20Sopenharmony_ci if (type & ZARLINK456) 2298c2ecf20Sopenharmony_ci printk(KERN_CONT "ZARLINK456 "); 2308c2ecf20Sopenharmony_ci if (type & CHINA) 2318c2ecf20Sopenharmony_ci printk(KERN_CONT "CHINA "); 2328c2ecf20Sopenharmony_ci if (type & F6MHZ) 2338c2ecf20Sopenharmony_ci printk(KERN_CONT "F6MHZ "); 2348c2ecf20Sopenharmony_ci if (type & INPUT2) 2358c2ecf20Sopenharmony_ci printk(KERN_CONT "INPUT2 "); 2368c2ecf20Sopenharmony_ci if (type & SCODE) 2378c2ecf20Sopenharmony_ci printk(KERN_CONT "SCODE "); 2388c2ecf20Sopenharmony_ci if (type & HAS_IF) 2398c2ecf20Sopenharmony_ci printk(KERN_CONT "HAS_IF_%d ", int_freq); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic v4l2_std_id parse_audio_std_option(void) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci if (strcasecmp(audio_std, "A2") == 0) 2458c2ecf20Sopenharmony_ci return V4L2_STD_A2; 2468c2ecf20Sopenharmony_ci if (strcasecmp(audio_std, "A2/A") == 0) 2478c2ecf20Sopenharmony_ci return V4L2_STD_A2_A; 2488c2ecf20Sopenharmony_ci if (strcasecmp(audio_std, "A2/B") == 0) 2498c2ecf20Sopenharmony_ci return V4L2_STD_A2_B; 2508c2ecf20Sopenharmony_ci if (strcasecmp(audio_std, "NICAM") == 0) 2518c2ecf20Sopenharmony_ci return V4L2_STD_NICAM; 2528c2ecf20Sopenharmony_ci if (strcasecmp(audio_std, "NICAM/A") == 0) 2538c2ecf20Sopenharmony_ci return V4L2_STD_NICAM_A; 2548c2ecf20Sopenharmony_ci if (strcasecmp(audio_std, "NICAM/B") == 0) 2558c2ecf20Sopenharmony_ci return V4L2_STD_NICAM_B; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int check_device_status(struct xc2028_data *priv) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci switch (priv->state) { 2638c2ecf20Sopenharmony_ci case XC2028_NO_FIRMWARE: 2648c2ecf20Sopenharmony_ci case XC2028_WAITING_FIRMWARE: 2658c2ecf20Sopenharmony_ci return -EAGAIN; 2668c2ecf20Sopenharmony_ci case XC2028_ACTIVE: 2678c2ecf20Sopenharmony_ci return 1; 2688c2ecf20Sopenharmony_ci case XC2028_SLEEP: 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci case XC2028_NODEV: 2718c2ecf20Sopenharmony_ci return -ENODEV; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void free_firmware(struct xc2028_data *priv) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci int i; 2798c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* free allocated f/w string */ 2828c2ecf20Sopenharmony_ci if (priv->fname != firmware_name) 2838c2ecf20Sopenharmony_ci kfree(priv->fname); 2848c2ecf20Sopenharmony_ci priv->fname = NULL; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci priv->state = XC2028_NO_FIRMWARE; 2878c2ecf20Sopenharmony_ci memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (!priv->firm) 2908c2ecf20Sopenharmony_ci return; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci for (i = 0; i < priv->firm_size; i++) 2938c2ecf20Sopenharmony_ci kfree(priv->firm[i].ptr); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci kfree(priv->firm); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci priv->firm = NULL; 2988c2ecf20Sopenharmony_ci priv->firm_size = 0; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int load_all_firmwares(struct dvb_frontend *fe, 3028c2ecf20Sopenharmony_ci const struct firmware *fw) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 3058c2ecf20Sopenharmony_ci const unsigned char *p, *endp; 3068c2ecf20Sopenharmony_ci int rc = 0; 3078c2ecf20Sopenharmony_ci int n, n_array; 3088c2ecf20Sopenharmony_ci char name[33]; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci p = fw->data; 3138c2ecf20Sopenharmony_ci endp = p + fw->size; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (fw->size < sizeof(name) - 1 + 2 + 2) { 3168c2ecf20Sopenharmony_ci tuner_err("Error: firmware file %s has invalid size!\n", 3178c2ecf20Sopenharmony_ci priv->fname); 3188c2ecf20Sopenharmony_ci goto corrupt; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci memcpy(name, p, sizeof(name) - 1); 3228c2ecf20Sopenharmony_ci name[sizeof(name) - 1] = 0; 3238c2ecf20Sopenharmony_ci p += sizeof(name) - 1; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci priv->firm_version = get_unaligned_le16(p); 3268c2ecf20Sopenharmony_ci p += 2; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci n_array = get_unaligned_le16(p); 3298c2ecf20Sopenharmony_ci p += 2; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", 3328c2ecf20Sopenharmony_ci n_array, priv->fname, name, 3338c2ecf20Sopenharmony_ci priv->firm_version >> 8, priv->firm_version & 0xff); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); 3368c2ecf20Sopenharmony_ci if (priv->firm == NULL) { 3378c2ecf20Sopenharmony_ci tuner_err("Not enough memory to load firmware file.\n"); 3388c2ecf20Sopenharmony_ci rc = -ENOMEM; 3398c2ecf20Sopenharmony_ci goto err; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci priv->firm_size = n_array; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci n = -1; 3448c2ecf20Sopenharmony_ci while (p < endp) { 3458c2ecf20Sopenharmony_ci __u32 type, size; 3468c2ecf20Sopenharmony_ci v4l2_std_id id; 3478c2ecf20Sopenharmony_ci __u16 int_freq = 0; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci n++; 3508c2ecf20Sopenharmony_ci if (n >= n_array) { 3518c2ecf20Sopenharmony_ci tuner_err("More firmware images in file than were expected!\n"); 3528c2ecf20Sopenharmony_ci goto corrupt; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Checks if there's enough bytes to read */ 3568c2ecf20Sopenharmony_ci if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) 3578c2ecf20Sopenharmony_ci goto header; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci type = get_unaligned_le32(p); 3608c2ecf20Sopenharmony_ci p += sizeof(type); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci id = get_unaligned_le64(p); 3638c2ecf20Sopenharmony_ci p += sizeof(id); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (type & HAS_IF) { 3668c2ecf20Sopenharmony_ci int_freq = get_unaligned_le16(p); 3678c2ecf20Sopenharmony_ci p += sizeof(int_freq); 3688c2ecf20Sopenharmony_ci if (endp - p < sizeof(size)) 3698c2ecf20Sopenharmony_ci goto header; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci size = get_unaligned_le32(p); 3738c2ecf20Sopenharmony_ci p += sizeof(size); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (!size || size > endp - p) { 3768c2ecf20Sopenharmony_ci tuner_err("Firmware type "); 3778c2ecf20Sopenharmony_ci dump_firm_type(type); 3788c2ecf20Sopenharmony_ci printk(KERN_CONT 3798c2ecf20Sopenharmony_ci "(%x), id %llx is corrupted (size=%zd, expected %d)\n", 3808c2ecf20Sopenharmony_ci type, (unsigned long long)id, (endp - p), size); 3818c2ecf20Sopenharmony_ci goto corrupt; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci priv->firm[n].ptr = kmemdup(p, size, GFP_KERNEL); 3858c2ecf20Sopenharmony_ci if (priv->firm[n].ptr == NULL) { 3868c2ecf20Sopenharmony_ci tuner_err("Not enough memory to load firmware file.\n"); 3878c2ecf20Sopenharmony_ci rc = -ENOMEM; 3888c2ecf20Sopenharmony_ci goto err; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci tuner_dbg("Reading firmware type "); 3918c2ecf20Sopenharmony_ci if (debug) { 3928c2ecf20Sopenharmony_ci dump_firm_type_and_int_freq(type, int_freq); 3938c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), id %llx, size=%d.\n", 3948c2ecf20Sopenharmony_ci type, (unsigned long long)id, size); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci priv->firm[n].type = type; 3988c2ecf20Sopenharmony_ci priv->firm[n].id = id; 3998c2ecf20Sopenharmony_ci priv->firm[n].size = size; 4008c2ecf20Sopenharmony_ci priv->firm[n].int_freq = int_freq; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci p += size; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (n + 1 != priv->firm_size) { 4068c2ecf20Sopenharmony_ci tuner_err("Firmware file is incomplete!\n"); 4078c2ecf20Sopenharmony_ci goto corrupt; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci goto done; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ciheader: 4138c2ecf20Sopenharmony_ci tuner_err("Firmware header is incomplete!\n"); 4148c2ecf20Sopenharmony_cicorrupt: 4158c2ecf20Sopenharmony_ci rc = -EINVAL; 4168c2ecf20Sopenharmony_ci tuner_err("Error: firmware file is corrupted!\n"); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cierr: 4198c2ecf20Sopenharmony_ci tuner_info("Releasing partially loaded firmware file.\n"); 4208c2ecf20Sopenharmony_ci free_firmware(priv); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cidone: 4238c2ecf20Sopenharmony_ci if (rc == 0) 4248c2ecf20Sopenharmony_ci tuner_dbg("Firmware files loaded.\n"); 4258c2ecf20Sopenharmony_ci else 4268c2ecf20Sopenharmony_ci priv->state = XC2028_NODEV; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return rc; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int seek_firmware(struct dvb_frontend *fe, unsigned int type, 4328c2ecf20Sopenharmony_ci v4l2_std_id *id) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 4358c2ecf20Sopenharmony_ci int i, best_i = -1, best_nr_matches = 0; 4368c2ecf20Sopenharmony_ci unsigned int type_mask = 0; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci tuner_dbg("%s called, want type=", __func__); 4398c2ecf20Sopenharmony_ci if (debug) { 4408c2ecf20Sopenharmony_ci dump_firm_type(type); 4418c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx.\n", 4428c2ecf20Sopenharmony_ci type, (unsigned long long)*id); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (!priv->firm) { 4468c2ecf20Sopenharmony_ci tuner_err("Error! firmware not loaded\n"); 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (((type & ~SCODE) == 0) && (*id == 0)) 4518c2ecf20Sopenharmony_ci *id = V4L2_STD_PAL; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (type & BASE) 4548c2ecf20Sopenharmony_ci type_mask = BASE_TYPES; 4558c2ecf20Sopenharmony_ci else if (type & SCODE) { 4568c2ecf20Sopenharmony_ci type &= SCODE_TYPES; 4578c2ecf20Sopenharmony_ci type_mask = SCODE_TYPES & ~HAS_IF; 4588c2ecf20Sopenharmony_ci } else if (type & DTV_TYPES) 4598c2ecf20Sopenharmony_ci type_mask = DTV_TYPES; 4608c2ecf20Sopenharmony_ci else if (type & STD_SPECIFIC_TYPES) 4618c2ecf20Sopenharmony_ci type_mask = STD_SPECIFIC_TYPES; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci type &= type_mask; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (!(type & SCODE)) 4668c2ecf20Sopenharmony_ci type_mask = ~0; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* Seek for exact match */ 4698c2ecf20Sopenharmony_ci for (i = 0; i < priv->firm_size; i++) { 4708c2ecf20Sopenharmony_ci if ((type == (priv->firm[i].type & type_mask)) && 4718c2ecf20Sopenharmony_ci (*id == priv->firm[i].id)) 4728c2ecf20Sopenharmony_ci goto found; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Seek for generic video standard match */ 4768c2ecf20Sopenharmony_ci for (i = 0; i < priv->firm_size; i++) { 4778c2ecf20Sopenharmony_ci v4l2_std_id match_mask; 4788c2ecf20Sopenharmony_ci int nr_matches; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (type != (priv->firm[i].type & type_mask)) 4818c2ecf20Sopenharmony_ci continue; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci match_mask = *id & priv->firm[i].id; 4848c2ecf20Sopenharmony_ci if (!match_mask) 4858c2ecf20Sopenharmony_ci continue; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if ((*id & match_mask) == *id) 4888c2ecf20Sopenharmony_ci goto found; /* Supports all the requested standards */ 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci nr_matches = hweight64(match_mask); 4918c2ecf20Sopenharmony_ci if (nr_matches > best_nr_matches) { 4928c2ecf20Sopenharmony_ci best_nr_matches = nr_matches; 4938c2ecf20Sopenharmony_ci best_i = i; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (best_nr_matches > 0) { 4988c2ecf20Sopenharmony_ci tuner_dbg("Selecting best matching firmware (%d bits) for type=", 4998c2ecf20Sopenharmony_ci best_nr_matches); 5008c2ecf20Sopenharmony_ci dump_firm_type(type); 5018c2ecf20Sopenharmony_ci printk(KERN_CONT 5028c2ecf20Sopenharmony_ci "(%x), id %016llx:\n", type, (unsigned long long)*id); 5038c2ecf20Sopenharmony_ci i = best_i; 5048c2ecf20Sopenharmony_ci goto found; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /*FIXME: Would make sense to seek for type "hint" match ? */ 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci i = -ENOENT; 5108c2ecf20Sopenharmony_ci goto ret; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cifound: 5138c2ecf20Sopenharmony_ci *id = priv->firm[i].id; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ciret: 5168c2ecf20Sopenharmony_ci tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); 5178c2ecf20Sopenharmony_ci if (debug) { 5188c2ecf20Sopenharmony_ci dump_firm_type(type); 5198c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx.\n", 5208c2ecf20Sopenharmony_ci type, (unsigned long long)*id); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci return i; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* analog side (tuner-core) uses i2c_adap->algo_data. 5308c2ecf20Sopenharmony_ci * digital side is not guaranteed to have algo_data defined. 5318c2ecf20Sopenharmony_ci * 5328c2ecf20Sopenharmony_ci * digital side will always have fe->dvb defined. 5338c2ecf20Sopenharmony_ci * analog side (tuner-core) doesn't (yet) define fe->dvb. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return (!fe->callback) ? -EINVAL : 5378c2ecf20Sopenharmony_ci fe->callback(((fe->dvb) && (fe->dvb->priv)) ? 5388c2ecf20Sopenharmony_ci fe->dvb->priv : priv->i2c_props.adap->algo_data, 5398c2ecf20Sopenharmony_ci DVB_FRONTEND_COMPONENT_TUNER, cmd, arg); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int load_firmware(struct dvb_frontend *fe, unsigned int type, 5438c2ecf20Sopenharmony_ci v4l2_std_id *id) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 5468c2ecf20Sopenharmony_ci int pos, rc; 5478c2ecf20Sopenharmony_ci unsigned char *p, *endp, buf[MAX_XFER_SIZE]; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (priv->ctrl.max_len > sizeof(buf)) 5508c2ecf20Sopenharmony_ci priv->ctrl.max_len = sizeof(buf); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci pos = seek_firmware(fe, type, id); 5558c2ecf20Sopenharmony_ci if (pos < 0) 5568c2ecf20Sopenharmony_ci return pos; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci tuner_info("Loading firmware for type="); 5598c2ecf20Sopenharmony_ci dump_firm_type(priv->firm[pos].type); 5608c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx.\n", 5618c2ecf20Sopenharmony_ci priv->firm[pos].type, (unsigned long long)*id); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci p = priv->firm[pos].ptr; 5648c2ecf20Sopenharmony_ci endp = p + priv->firm[pos].size; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci while (p < endp) { 5678c2ecf20Sopenharmony_ci __u16 size; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* Checks if there's enough bytes to read */ 5708c2ecf20Sopenharmony_ci if (p + sizeof(size) > endp) { 5718c2ecf20Sopenharmony_ci tuner_err("Firmware chunk size is wrong\n"); 5728c2ecf20Sopenharmony_ci return -EINVAL; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci size = le16_to_cpu(*(__le16 *) p); 5768c2ecf20Sopenharmony_ci p += sizeof(size); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (size == 0xffff) 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (!size) { 5828c2ecf20Sopenharmony_ci /* Special callback command received */ 5838c2ecf20Sopenharmony_ci rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); 5848c2ecf20Sopenharmony_ci if (rc < 0) { 5858c2ecf20Sopenharmony_ci tuner_err("Error at RESET code %d\n", 5868c2ecf20Sopenharmony_ci (*p) & 0x7f); 5878c2ecf20Sopenharmony_ci return -EINVAL; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci continue; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci if (size >= 0xff00) { 5928c2ecf20Sopenharmony_ci switch (size) { 5938c2ecf20Sopenharmony_ci case 0xff00: 5948c2ecf20Sopenharmony_ci rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); 5958c2ecf20Sopenharmony_ci if (rc < 0) { 5968c2ecf20Sopenharmony_ci tuner_err("Error at RESET code %d\n", 5978c2ecf20Sopenharmony_ci (*p) & 0x7f); 5988c2ecf20Sopenharmony_ci return -EINVAL; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci default: 6028c2ecf20Sopenharmony_ci tuner_info("Invalid RESET code %d\n", 6038c2ecf20Sopenharmony_ci size & 0x7f); 6048c2ecf20Sopenharmony_ci return -EINVAL; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci continue; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* Checks for a sleep command */ 6118c2ecf20Sopenharmony_ci if (size & 0x8000) { 6128c2ecf20Sopenharmony_ci msleep(size & 0x7fff); 6138c2ecf20Sopenharmony_ci continue; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if ((size + p > endp)) { 6178c2ecf20Sopenharmony_ci tuner_err("missing bytes: need %d, have %zd\n", 6188c2ecf20Sopenharmony_ci size, (endp - p)); 6198c2ecf20Sopenharmony_ci return -EINVAL; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci buf[0] = *p; 6238c2ecf20Sopenharmony_ci p++; 6248c2ecf20Sopenharmony_ci size--; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Sends message chunks */ 6278c2ecf20Sopenharmony_ci while (size > 0) { 6288c2ecf20Sopenharmony_ci int len = (size < priv->ctrl.max_len - 1) ? 6298c2ecf20Sopenharmony_ci size : priv->ctrl.max_len - 1; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci memcpy(buf + 1, p, len); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci rc = i2c_send(priv, buf, len + 1); 6348c2ecf20Sopenharmony_ci if (rc < 0) { 6358c2ecf20Sopenharmony_ci tuner_err("%d returned from send\n", rc); 6368c2ecf20Sopenharmony_ci return -EINVAL; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci p += len; 6408c2ecf20Sopenharmony_ci size -= len; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* silently fail if the frontend doesn't support I2C flush */ 6448c2ecf20Sopenharmony_ci rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0); 6458c2ecf20Sopenharmony_ci if ((rc < 0) && (rc != -EINVAL)) { 6468c2ecf20Sopenharmony_ci tuner_err("error executing flush: %d\n", rc); 6478c2ecf20Sopenharmony_ci return rc; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci return 0; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic int load_scode(struct dvb_frontend *fe, unsigned int type, 6548c2ecf20Sopenharmony_ci v4l2_std_id *id, __u16 int_freq, int scode) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 6578c2ecf20Sopenharmony_ci int pos, rc; 6588c2ecf20Sopenharmony_ci unsigned char *p; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (!int_freq) { 6638c2ecf20Sopenharmony_ci pos = seek_firmware(fe, type, id); 6648c2ecf20Sopenharmony_ci if (pos < 0) 6658c2ecf20Sopenharmony_ci return pos; 6668c2ecf20Sopenharmony_ci } else { 6678c2ecf20Sopenharmony_ci for (pos = 0; pos < priv->firm_size; pos++) { 6688c2ecf20Sopenharmony_ci if ((priv->firm[pos].int_freq == int_freq) && 6698c2ecf20Sopenharmony_ci (priv->firm[pos].type & HAS_IF)) 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci if (pos == priv->firm_size) 6738c2ecf20Sopenharmony_ci return -ENOENT; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci p = priv->firm[pos].ptr; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (priv->firm[pos].type & HAS_IF) { 6798c2ecf20Sopenharmony_ci if (priv->firm[pos].size != 12 * 16 || scode >= 16) 6808c2ecf20Sopenharmony_ci return -EINVAL; 6818c2ecf20Sopenharmony_ci p += 12 * scode; 6828c2ecf20Sopenharmony_ci } else { 6838c2ecf20Sopenharmony_ci /* 16 SCODE entries per file; each SCODE entry is 12 bytes and 6848c2ecf20Sopenharmony_ci * has a 2-byte size header in the firmware format. */ 6858c2ecf20Sopenharmony_ci if (priv->firm[pos].size != 14 * 16 || scode >= 16 || 6868c2ecf20Sopenharmony_ci le16_to_cpu(*(__le16 *)(p + 14 * scode)) != 12) 6878c2ecf20Sopenharmony_ci return -EINVAL; 6888c2ecf20Sopenharmony_ci p += 14 * scode + 2; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci tuner_info("Loading SCODE for type="); 6928c2ecf20Sopenharmony_ci dump_firm_type_and_int_freq(priv->firm[pos].type, 6938c2ecf20Sopenharmony_ci priv->firm[pos].int_freq); 6948c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, 6958c2ecf20Sopenharmony_ci (unsigned long long)*id); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (priv->firm_version < 0x0202) 6988c2ecf20Sopenharmony_ci rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); 6998c2ecf20Sopenharmony_ci else 7008c2ecf20Sopenharmony_ci rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); 7018c2ecf20Sopenharmony_ci if (rc < 0) 7028c2ecf20Sopenharmony_ci return -EIO; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci rc = i2c_send(priv, p, 12); 7058c2ecf20Sopenharmony_ci if (rc < 0) 7068c2ecf20Sopenharmony_ci return -EIO; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci rc = send_seq(priv, {0x00, 0x8c}); 7098c2ecf20Sopenharmony_ci if (rc < 0) 7108c2ecf20Sopenharmony_ci return -EIO; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return 0; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic int xc2028_sleep(struct dvb_frontend *fe); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic int check_firmware(struct dvb_frontend *fe, unsigned int type, 7188c2ecf20Sopenharmony_ci v4l2_std_id std, __u16 int_freq) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 7218c2ecf20Sopenharmony_ci struct firmware_properties new_fw; 7228c2ecf20Sopenharmony_ci int rc, retry_count = 0; 7238c2ecf20Sopenharmony_ci u16 version, hwmodel; 7248c2ecf20Sopenharmony_ci v4l2_std_id std0; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci rc = check_device_status(priv); 7298c2ecf20Sopenharmony_ci if (rc < 0) 7308c2ecf20Sopenharmony_ci return rc; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (priv->ctrl.mts && !(type & FM)) 7338c2ecf20Sopenharmony_ci type |= MTS; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ciretry: 7368c2ecf20Sopenharmony_ci new_fw.type = type; 7378c2ecf20Sopenharmony_ci new_fw.id = std; 7388c2ecf20Sopenharmony_ci new_fw.std_req = std; 7398c2ecf20Sopenharmony_ci new_fw.scode_table = SCODE | priv->ctrl.scode_table; 7408c2ecf20Sopenharmony_ci new_fw.scode_nr = 0; 7418c2ecf20Sopenharmony_ci new_fw.int_freq = int_freq; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci tuner_dbg("checking firmware, user requested type="); 7448c2ecf20Sopenharmony_ci if (debug) { 7458c2ecf20Sopenharmony_ci dump_firm_type(new_fw.type); 7468c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, 7478c2ecf20Sopenharmony_ci (unsigned long long)new_fw.std_req); 7488c2ecf20Sopenharmony_ci if (!int_freq) { 7498c2ecf20Sopenharmony_ci printk(KERN_CONT "scode_tbl "); 7508c2ecf20Sopenharmony_ci dump_firm_type(priv->ctrl.scode_table); 7518c2ecf20Sopenharmony_ci printk(KERN_CONT "(%x), ", priv->ctrl.scode_table); 7528c2ecf20Sopenharmony_ci } else 7538c2ecf20Sopenharmony_ci printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); 7548c2ecf20Sopenharmony_ci printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* 7588c2ecf20Sopenharmony_ci * No need to reload base firmware if it matches and if the tuner 7598c2ecf20Sopenharmony_ci * is not at sleep mode 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci if ((priv->state == XC2028_ACTIVE) && 7628c2ecf20Sopenharmony_ci (((BASE | new_fw.type) & BASE_TYPES) == 7638c2ecf20Sopenharmony_ci (priv->cur_fw.type & BASE_TYPES))) { 7648c2ecf20Sopenharmony_ci tuner_dbg("BASE firmware not changed.\n"); 7658c2ecf20Sopenharmony_ci goto skip_base; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* Updating BASE - forget about all currently loaded firmware */ 7698c2ecf20Sopenharmony_ci memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* Reset is needed before loading firmware */ 7728c2ecf20Sopenharmony_ci rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); 7738c2ecf20Sopenharmony_ci if (rc < 0) 7748c2ecf20Sopenharmony_ci goto fail; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* BASE firmwares are all std0 */ 7778c2ecf20Sopenharmony_ci std0 = 0; 7788c2ecf20Sopenharmony_ci rc = load_firmware(fe, BASE | new_fw.type, &std0); 7798c2ecf20Sopenharmony_ci if (rc < 0) { 7808c2ecf20Sopenharmony_ci tuner_err("Error %d while loading base firmware\n", 7818c2ecf20Sopenharmony_ci rc); 7828c2ecf20Sopenharmony_ci goto fail; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* Load INIT1, if needed */ 7868c2ecf20Sopenharmony_ci tuner_dbg("Load init1 firmware, if exists\n"); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); 7898c2ecf20Sopenharmony_ci if (rc == -ENOENT) 7908c2ecf20Sopenharmony_ci rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, 7918c2ecf20Sopenharmony_ci &std0); 7928c2ecf20Sopenharmony_ci if (rc < 0 && rc != -ENOENT) { 7938c2ecf20Sopenharmony_ci tuner_err("Error %d while loading init1 firmware\n", 7948c2ecf20Sopenharmony_ci rc); 7958c2ecf20Sopenharmony_ci goto fail; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ciskip_base: 7998c2ecf20Sopenharmony_ci /* 8008c2ecf20Sopenharmony_ci * No need to reload standard specific firmware if base firmware 8018c2ecf20Sopenharmony_ci * was not reloaded and requested video standards have not changed. 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_ci if (priv->cur_fw.type == (BASE | new_fw.type) && 8048c2ecf20Sopenharmony_ci priv->cur_fw.std_req == std) { 8058c2ecf20Sopenharmony_ci tuner_dbg("Std-specific firmware already loaded.\n"); 8068c2ecf20Sopenharmony_ci goto skip_std_specific; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Reloading std-specific firmware forces a SCODE update */ 8108c2ecf20Sopenharmony_ci priv->cur_fw.scode_table = 0; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci rc = load_firmware(fe, new_fw.type, &new_fw.id); 8138c2ecf20Sopenharmony_ci if (rc == -ENOENT) 8148c2ecf20Sopenharmony_ci rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (rc < 0) 8178c2ecf20Sopenharmony_ci goto fail; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ciskip_std_specific: 8208c2ecf20Sopenharmony_ci if (priv->cur_fw.scode_table == new_fw.scode_table && 8218c2ecf20Sopenharmony_ci priv->cur_fw.scode_nr == new_fw.scode_nr) { 8228c2ecf20Sopenharmony_ci tuner_dbg("SCODE firmware already loaded.\n"); 8238c2ecf20Sopenharmony_ci goto check_device; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (new_fw.type & FM) 8278c2ecf20Sopenharmony_ci goto check_device; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* Load SCODE firmware, if exists */ 8308c2ecf20Sopenharmony_ci tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, 8338c2ecf20Sopenharmony_ci new_fw.int_freq, new_fw.scode_nr); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cicheck_device: 8368c2ecf20Sopenharmony_ci if (xc2028_get_reg(priv, 0x0004, &version) < 0 || 8378c2ecf20Sopenharmony_ci xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { 8388c2ecf20Sopenharmony_ci tuner_err("Unable to read tuner registers.\n"); 8398c2ecf20Sopenharmony_ci goto fail; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci tuner_dbg("Device is Xceive %d version %d.%d, firmware version %d.%d\n", 8438c2ecf20Sopenharmony_ci hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, 8448c2ecf20Sopenharmony_ci (version & 0xf0) >> 4, version & 0xf); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (priv->ctrl.read_not_reliable) 8488c2ecf20Sopenharmony_ci goto read_not_reliable; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Check firmware version against what we downloaded. */ 8518c2ecf20Sopenharmony_ci if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { 8528c2ecf20Sopenharmony_ci if (!priv->ctrl.read_not_reliable) { 8538c2ecf20Sopenharmony_ci tuner_err("Incorrect readback of firmware version.\n"); 8548c2ecf20Sopenharmony_ci goto fail; 8558c2ecf20Sopenharmony_ci } else { 8568c2ecf20Sopenharmony_ci tuner_err("Returned an incorrect version. However, read is not reliable enough. Ignoring it.\n"); 8578c2ecf20Sopenharmony_ci hwmodel = 3028; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* Check that the tuner hardware model remains consistent over time. */ 8628c2ecf20Sopenharmony_ci if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { 8638c2ecf20Sopenharmony_ci priv->hwmodel = hwmodel; 8648c2ecf20Sopenharmony_ci priv->hwvers = version & 0xff00; 8658c2ecf20Sopenharmony_ci } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || 8668c2ecf20Sopenharmony_ci priv->hwvers != (version & 0xff00)) { 8678c2ecf20Sopenharmony_ci tuner_err("Read invalid device hardware information - tuner hung?\n"); 8688c2ecf20Sopenharmony_ci goto fail; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ciread_not_reliable: 8728c2ecf20Sopenharmony_ci priv->cur_fw = new_fw; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* 8758c2ecf20Sopenharmony_ci * By setting BASE in cur_fw.type only after successfully loading all 8768c2ecf20Sopenharmony_ci * firmwares, we can: 8778c2ecf20Sopenharmony_ci * 1. Identify that BASE firmware with type=0 has been loaded; 8788c2ecf20Sopenharmony_ci * 2. Tell whether BASE firmware was just changed the next time through. 8798c2ecf20Sopenharmony_ci */ 8808c2ecf20Sopenharmony_ci priv->cur_fw.type |= BASE; 8818c2ecf20Sopenharmony_ci priv->state = XC2028_ACTIVE; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci return 0; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cifail: 8868c2ecf20Sopenharmony_ci free_firmware(priv); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (retry_count < 8) { 8898c2ecf20Sopenharmony_ci msleep(50); 8908c2ecf20Sopenharmony_ci retry_count++; 8918c2ecf20Sopenharmony_ci tuner_dbg("Retrying firmware load\n"); 8928c2ecf20Sopenharmony_ci goto retry; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* Firmware didn't load. Put the device to sleep */ 8968c2ecf20Sopenharmony_ci xc2028_sleep(fe); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (rc == -ENOENT) 8998c2ecf20Sopenharmony_ci rc = -EINVAL; 9008c2ecf20Sopenharmony_ci return rc; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic int xc2028_signal(struct dvb_frontend *fe, u16 *strength) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 9068c2ecf20Sopenharmony_ci u16 frq_lock, signal = 0; 9078c2ecf20Sopenharmony_ci int rc, i; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci rc = check_device_status(priv); 9128c2ecf20Sopenharmony_ci if (rc < 0) 9138c2ecf20Sopenharmony_ci return rc; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* If the device is sleeping, no channel is tuned */ 9168c2ecf20Sopenharmony_ci if (!rc) { 9178c2ecf20Sopenharmony_ci *strength = 0; 9188c2ecf20Sopenharmony_ci return 0; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Sync Lock Indicator */ 9248c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 9258c2ecf20Sopenharmony_ci rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); 9268c2ecf20Sopenharmony_ci if (rc < 0) 9278c2ecf20Sopenharmony_ci goto ret; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (frq_lock) 9308c2ecf20Sopenharmony_ci break; 9318c2ecf20Sopenharmony_ci msleep(6); 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* Frequency didn't lock */ 9358c2ecf20Sopenharmony_ci if (frq_lock == 2) 9368c2ecf20Sopenharmony_ci goto ret; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* Get SNR of the video signal */ 9398c2ecf20Sopenharmony_ci rc = xc2028_get_reg(priv, XREG_SNR, &signal); 9408c2ecf20Sopenharmony_ci if (rc < 0) 9418c2ecf20Sopenharmony_ci goto ret; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* Signal level is 3 bits only */ 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci signal = ((1 << 12) - 1) | ((signal & 0x07) << 12); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ciret: 9488c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci *strength = signal; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci tuner_dbg("signal strength is %d\n", signal); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci return rc; 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 9608c2ecf20Sopenharmony_ci int i, rc; 9618c2ecf20Sopenharmony_ci u16 frq_lock = 0; 9628c2ecf20Sopenharmony_ci s16 afc_reg = 0; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci rc = check_device_status(priv); 9658c2ecf20Sopenharmony_ci if (rc < 0) 9668c2ecf20Sopenharmony_ci return rc; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* If the device is sleeping, no channel is tuned */ 9698c2ecf20Sopenharmony_ci if (!rc) { 9708c2ecf20Sopenharmony_ci *afc = 0; 9718c2ecf20Sopenharmony_ci return 0; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* Sync Lock Indicator */ 9778c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 9788c2ecf20Sopenharmony_ci rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); 9798c2ecf20Sopenharmony_ci if (rc < 0) 9808c2ecf20Sopenharmony_ci goto ret; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (frq_lock) 9838c2ecf20Sopenharmony_ci break; 9848c2ecf20Sopenharmony_ci msleep(6); 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* Frequency didn't lock */ 9888c2ecf20Sopenharmony_ci if (frq_lock == 2) 9898c2ecf20Sopenharmony_ci goto ret; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* Get AFC */ 9928c2ecf20Sopenharmony_ci rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg); 9938c2ecf20Sopenharmony_ci if (rc < 0) 9948c2ecf20Sopenharmony_ci goto ret; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci *afc = afc_reg * 15625; /* Hz */ 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci tuner_dbg("AFC is %d Hz\n", *afc); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ciret: 10018c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci return rc; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci#define DIV 15625 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, 10098c2ecf20Sopenharmony_ci enum v4l2_tuner_type new_type, 10108c2ecf20Sopenharmony_ci unsigned int type, 10118c2ecf20Sopenharmony_ci v4l2_std_id std, 10128c2ecf20Sopenharmony_ci u16 int_freq) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 10158c2ecf20Sopenharmony_ci int rc = -EINVAL; 10168c2ecf20Sopenharmony_ci unsigned char buf[4]; 10178c2ecf20Sopenharmony_ci u32 div, offset = 0; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci tuner_dbg("should set frequency %d kHz\n", freq / 1000); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (check_firmware(fe, type, std, int_freq) < 0) 10268c2ecf20Sopenharmony_ci goto ret; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* On some cases xc2028 can disable video output, if 10298c2ecf20Sopenharmony_ci * very weak signals are received. By sending a soft 10308c2ecf20Sopenharmony_ci * reset, this is re-enabled. So, it is better to always 10318c2ecf20Sopenharmony_ci * send a soft reset before changing channels, to be sure 10328c2ecf20Sopenharmony_ci * that xc2028 will be in a safe state. 10338c2ecf20Sopenharmony_ci * Maybe this might also be needed for DTV. 10348c2ecf20Sopenharmony_ci */ 10358c2ecf20Sopenharmony_ci switch (new_type) { 10368c2ecf20Sopenharmony_ci case V4L2_TUNER_ANALOG_TV: 10378c2ecf20Sopenharmony_ci rc = send_seq(priv, {0x00, 0x00}); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* Analog mode requires offset = 0 */ 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci case V4L2_TUNER_RADIO: 10428c2ecf20Sopenharmony_ci /* Radio mode requires offset = 0 */ 10438c2ecf20Sopenharmony_ci break; 10448c2ecf20Sopenharmony_ci case V4L2_TUNER_DIGITAL_TV: 10458c2ecf20Sopenharmony_ci /* 10468c2ecf20Sopenharmony_ci * Digital modes require an offset to adjust to the 10478c2ecf20Sopenharmony_ci * proper frequency. The offset depends on what 10488c2ecf20Sopenharmony_ci * firmware version is used. 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* 10528c2ecf20Sopenharmony_ci * Adjust to the center frequency. This is calculated by the 10538c2ecf20Sopenharmony_ci * formula: offset = 1.25MHz - BW/2 10548c2ecf20Sopenharmony_ci * For DTV 7/8, the firmware uses BW = 8000, so it needs a 10558c2ecf20Sopenharmony_ci * further adjustment to get the frequency center on VHF 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* 10598c2ecf20Sopenharmony_ci * The firmware DTV78 used to work fine in UHF band (8 MHz 10608c2ecf20Sopenharmony_ci * bandwidth) but not at all in VHF band (7 MHz bandwidth). 10618c2ecf20Sopenharmony_ci * The real problem was connected to the formula used to 10628c2ecf20Sopenharmony_ci * calculate the center frequency offset in VHF band. 10638c2ecf20Sopenharmony_ci * In fact, removing the 500KHz adjustment fixed the problem. 10648c2ecf20Sopenharmony_ci * This is coherent to what was implemented for the DTV7 10658c2ecf20Sopenharmony_ci * firmware. 10668c2ecf20Sopenharmony_ci * In the end, now the center frequency is the same for all 3 10678c2ecf20Sopenharmony_ci * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel 10688c2ecf20Sopenharmony_ci * bandwidth. 10698c2ecf20Sopenharmony_ci */ 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (priv->cur_fw.type & DTV6) 10728c2ecf20Sopenharmony_ci offset = 1750000; 10738c2ecf20Sopenharmony_ci else /* DTV7 or DTV8 or DTV78 */ 10748c2ecf20Sopenharmony_ci offset = 2750000; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci /* 10778c2ecf20Sopenharmony_ci * xc3028 additional "magic" 10788c2ecf20Sopenharmony_ci * Depending on the firmware version, it needs some adjustments 10798c2ecf20Sopenharmony_ci * to properly centralize the frequency. This seems to be 10808c2ecf20Sopenharmony_ci * needed to compensate the SCODE table adjustments made by 10818c2ecf20Sopenharmony_ci * newer firmwares 10828c2ecf20Sopenharmony_ci */ 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* 10858c2ecf20Sopenharmony_ci * The proper adjustment would be to do it at s-code table. 10868c2ecf20Sopenharmony_ci * However, this didn't work, as reported by 10878c2ecf20Sopenharmony_ci * Robert Lowery <rglowery@exemail.com.au> 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci#if 0 10918c2ecf20Sopenharmony_ci /* 10928c2ecf20Sopenharmony_ci * Still need tests for XC3028L (firmware 3.2 or upper) 10938c2ecf20Sopenharmony_ci * So, for now, let's just comment the per-firmware 10948c2ecf20Sopenharmony_ci * version of this change. Reports with xc3028l working 10958c2ecf20Sopenharmony_ci * with and without the lines below are welcome 10968c2ecf20Sopenharmony_ci */ 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (priv->firm_version < 0x0302) { 10998c2ecf20Sopenharmony_ci if (priv->cur_fw.type & DTV7) 11008c2ecf20Sopenharmony_ci offset += 500000; 11018c2ecf20Sopenharmony_ci } else { 11028c2ecf20Sopenharmony_ci if (priv->cur_fw.type & DTV7) 11038c2ecf20Sopenharmony_ci offset -= 300000; 11048c2ecf20Sopenharmony_ci else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */ 11058c2ecf20Sopenharmony_ci offset += 200000; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci#endif 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci default: 11108c2ecf20Sopenharmony_ci tuner_err("Unsupported tuner type %d.\n", new_type); 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci div = (freq - offset + DIV / 2) / DIV; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* CMD= Set frequency */ 11178c2ecf20Sopenharmony_ci if (priv->firm_version < 0x0202) 11188c2ecf20Sopenharmony_ci rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00}); 11198c2ecf20Sopenharmony_ci else 11208c2ecf20Sopenharmony_ci rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00}); 11218c2ecf20Sopenharmony_ci if (rc < 0) 11228c2ecf20Sopenharmony_ci goto ret; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci /* Return code shouldn't be checked. 11258c2ecf20Sopenharmony_ci The reset CLK is needed only with tm6000. 11268c2ecf20Sopenharmony_ci Driver should work fine even if this fails. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci if (priv->ctrl.msleep) 11298c2ecf20Sopenharmony_ci msleep(priv->ctrl.msleep); 11308c2ecf20Sopenharmony_ci do_tuner_callback(fe, XC2028_RESET_CLK, 1); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci msleep(10); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci buf[0] = 0xff & (div >> 24); 11358c2ecf20Sopenharmony_ci buf[1] = 0xff & (div >> 16); 11368c2ecf20Sopenharmony_ci buf[2] = 0xff & (div >> 8); 11378c2ecf20Sopenharmony_ci buf[3] = 0xff & (div); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci rc = i2c_send(priv, buf, sizeof(buf)); 11408c2ecf20Sopenharmony_ci if (rc < 0) 11418c2ecf20Sopenharmony_ci goto ret; 11428c2ecf20Sopenharmony_ci msleep(100); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci priv->frequency = freq; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci tuner_dbg("divisor= %*ph (freq=%d.%03d)\n", 4, buf, 11478c2ecf20Sopenharmony_ci freq / 1000000, (freq % 1000000) / 1000); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci rc = 0; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ciret: 11528c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return rc; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic int xc2028_set_analog_freq(struct dvb_frontend *fe, 11588c2ecf20Sopenharmony_ci struct analog_parameters *p) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 11618c2ecf20Sopenharmony_ci unsigned int type=0; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci if (p->mode == V4L2_TUNER_RADIO) { 11668c2ecf20Sopenharmony_ci type |= FM; 11678c2ecf20Sopenharmony_ci if (priv->ctrl.input1) 11688c2ecf20Sopenharmony_ci type |= INPUT1; 11698c2ecf20Sopenharmony_ci return generic_set_freq(fe, (625l * p->frequency) / 10, 11708c2ecf20Sopenharmony_ci V4L2_TUNER_RADIO, type, 0, 0); 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* if std is not defined, choose one */ 11748c2ecf20Sopenharmony_ci if (!p->std) 11758c2ecf20Sopenharmony_ci p->std = V4L2_STD_MN; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ 11788c2ecf20Sopenharmony_ci if (!(p->std & V4L2_STD_MN)) 11798c2ecf20Sopenharmony_ci type |= F8MHZ; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* Add audio hack to std mask */ 11828c2ecf20Sopenharmony_ci p->std |= parse_audio_std_option(); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci return generic_set_freq(fe, 62500l * p->frequency, 11858c2ecf20Sopenharmony_ci V4L2_TUNER_ANALOG_TV, type, p->std, 0); 11868c2ecf20Sopenharmony_ci} 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic int xc2028_set_params(struct dvb_frontend *fe) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 11918c2ecf20Sopenharmony_ci u32 delsys = c->delivery_system; 11928c2ecf20Sopenharmony_ci u32 bw = c->bandwidth_hz; 11938c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 11948c2ecf20Sopenharmony_ci int rc; 11958c2ecf20Sopenharmony_ci unsigned int type = 0; 11968c2ecf20Sopenharmony_ci u16 demod = 0; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci rc = check_device_status(priv); 12018c2ecf20Sopenharmony_ci if (rc < 0) 12028c2ecf20Sopenharmony_ci return rc; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci switch (delsys) { 12058c2ecf20Sopenharmony_ci case SYS_DVBT: 12068c2ecf20Sopenharmony_ci case SYS_DVBT2: 12078c2ecf20Sopenharmony_ci /* 12088c2ecf20Sopenharmony_ci * The only countries with 6MHz seem to be Taiwan/Uruguay. 12098c2ecf20Sopenharmony_ci * Both seem to require QAM firmware for OFDM decoding 12108c2ecf20Sopenharmony_ci * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com> 12118c2ecf20Sopenharmony_ci */ 12128c2ecf20Sopenharmony_ci if (bw <= 6000000) 12138c2ecf20Sopenharmony_ci type |= QAM; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci switch (priv->ctrl.type) { 12168c2ecf20Sopenharmony_ci case XC2028_D2633: 12178c2ecf20Sopenharmony_ci type |= D2633; 12188c2ecf20Sopenharmony_ci break; 12198c2ecf20Sopenharmony_ci case XC2028_D2620: 12208c2ecf20Sopenharmony_ci type |= D2620; 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci case XC2028_AUTO: 12238c2ecf20Sopenharmony_ci default: 12248c2ecf20Sopenharmony_ci /* Zarlink seems to need D2633 */ 12258c2ecf20Sopenharmony_ci if (priv->ctrl.demod == XC3028_FE_ZARLINK456) 12268c2ecf20Sopenharmony_ci type |= D2633; 12278c2ecf20Sopenharmony_ci else 12288c2ecf20Sopenharmony_ci type |= D2620; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci break; 12318c2ecf20Sopenharmony_ci case SYS_ATSC: 12328c2ecf20Sopenharmony_ci /* The only ATSC firmware (at least on v2.7) is D2633 */ 12338c2ecf20Sopenharmony_ci type |= ATSC | D2633; 12348c2ecf20Sopenharmony_ci break; 12358c2ecf20Sopenharmony_ci /* DVB-S and pure QAM (FE_QAM) are not supported */ 12368c2ecf20Sopenharmony_ci default: 12378c2ecf20Sopenharmony_ci return -EINVAL; 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (bw <= 6000000) { 12418c2ecf20Sopenharmony_ci type |= DTV6; 12428c2ecf20Sopenharmony_ci priv->ctrl.vhfbw7 = 0; 12438c2ecf20Sopenharmony_ci priv->ctrl.uhfbw8 = 0; 12448c2ecf20Sopenharmony_ci } else if (bw <= 7000000) { 12458c2ecf20Sopenharmony_ci if (c->frequency < 470000000) 12468c2ecf20Sopenharmony_ci priv->ctrl.vhfbw7 = 1; 12478c2ecf20Sopenharmony_ci else 12488c2ecf20Sopenharmony_ci priv->ctrl.uhfbw8 = 0; 12498c2ecf20Sopenharmony_ci type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; 12508c2ecf20Sopenharmony_ci type |= F8MHZ; 12518c2ecf20Sopenharmony_ci } else { 12528c2ecf20Sopenharmony_ci if (c->frequency < 470000000) 12538c2ecf20Sopenharmony_ci priv->ctrl.vhfbw7 = 0; 12548c2ecf20Sopenharmony_ci else 12558c2ecf20Sopenharmony_ci priv->ctrl.uhfbw8 = 1; 12568c2ecf20Sopenharmony_ci type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; 12578c2ecf20Sopenharmony_ci type |= F8MHZ; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* All S-code tables need a 200kHz shift */ 12618c2ecf20Sopenharmony_ci if (priv->ctrl.demod) { 12628c2ecf20Sopenharmony_ci demod = priv->ctrl.demod; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci /* 12658c2ecf20Sopenharmony_ci * Newer firmwares require a 200 kHz offset only for ATSC 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci if (type == ATSC || priv->firm_version < 0x0302) 12688c2ecf20Sopenharmony_ci demod += 200; 12698c2ecf20Sopenharmony_ci /* 12708c2ecf20Sopenharmony_ci * The DTV7 S-code table needs a 700 kHz shift. 12718c2ecf20Sopenharmony_ci * 12728c2ecf20Sopenharmony_ci * DTV7 is only used in Australia. Germany or Italy may also 12738c2ecf20Sopenharmony_ci * use this firmware after initialization, but a tune to a UHF 12748c2ecf20Sopenharmony_ci * channel should then cause DTV78 to be used. 12758c2ecf20Sopenharmony_ci * 12768c2ecf20Sopenharmony_ci * Unfortunately, on real-field tests, the s-code offset 12778c2ecf20Sopenharmony_ci * didn't work as expected, as reported by 12788c2ecf20Sopenharmony_ci * Robert Lowery <rglowery@exemail.com.au> 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci return generic_set_freq(fe, c->frequency, 12838c2ecf20Sopenharmony_ci V4L2_TUNER_DIGITAL_TV, type, 0, demod); 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic int xc2028_sleep(struct dvb_frontend *fe) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 12898c2ecf20Sopenharmony_ci int rc; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci rc = check_device_status(priv); 12928c2ecf20Sopenharmony_ci if (rc < 0) 12938c2ecf20Sopenharmony_ci return rc; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* Device is already in sleep mode */ 12968c2ecf20Sopenharmony_ci if (!rc) 12978c2ecf20Sopenharmony_ci return 0; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci /* Avoid firmware reload on slow devices or if PM disabled */ 13008c2ecf20Sopenharmony_ci if (no_poweroff || priv->ctrl.disable_power_mgmt) 13018c2ecf20Sopenharmony_ci return 0; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci tuner_dbg("Putting xc2028/3028 into poweroff mode.\n"); 13048c2ecf20Sopenharmony_ci if (debug > 1) { 13058c2ecf20Sopenharmony_ci tuner_dbg("Printing sleep stack trace:\n"); 13068c2ecf20Sopenharmony_ci dump_stack(); 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (priv->firm_version < 0x0202) 13128c2ecf20Sopenharmony_ci rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00}); 13138c2ecf20Sopenharmony_ci else 13148c2ecf20Sopenharmony_ci rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (rc >= 0) 13178c2ecf20Sopenharmony_ci priv->state = XC2028_SLEEP; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci return rc; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic void xc2028_dvb_release(struct dvb_frontend *fe) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci mutex_lock(&xc2028_list_mutex); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* only perform final cleanup if this is the last instance */ 13338c2ecf20Sopenharmony_ci if (hybrid_tuner_report_instance_count(priv) == 1) 13348c2ecf20Sopenharmony_ci free_firmware(priv); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (priv) 13378c2ecf20Sopenharmony_ci hybrid_tuner_release_state(priv); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci mutex_unlock(&xc2028_list_mutex); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 13428c2ecf20Sopenharmony_ci} 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_cistatic int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 13478c2ecf20Sopenharmony_ci int rc; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci rc = check_device_status(priv); 13528c2ecf20Sopenharmony_ci if (rc < 0) 13538c2ecf20Sopenharmony_ci return rc; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci *frequency = priv->frequency; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci return 0; 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_cistatic void load_firmware_cb(const struct firmware *fw, 13618c2ecf20Sopenharmony_ci void *context) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct dvb_frontend *fe = context; 13648c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 13658c2ecf20Sopenharmony_ci int rc; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error"); 13688c2ecf20Sopenharmony_ci if (!fw) { 13698c2ecf20Sopenharmony_ci tuner_err("Could not load firmware %s.\n", priv->fname); 13708c2ecf20Sopenharmony_ci priv->state = XC2028_NODEV; 13718c2ecf20Sopenharmony_ci return; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci rc = load_all_firmwares(fe, fw); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci release_firmware(fw); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci if (rc < 0) 13798c2ecf20Sopenharmony_ci return; 13808c2ecf20Sopenharmony_ci priv->state = XC2028_ACTIVE; 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct xc2028_data *priv = fe->tuner_priv; 13868c2ecf20Sopenharmony_ci struct xc2028_ctrl *p = priv_cfg; 13878c2ecf20Sopenharmony_ci int rc = 0; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci tuner_dbg("%s called\n", __func__); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci /* 13948c2ecf20Sopenharmony_ci * Copy the config data. 13958c2ecf20Sopenharmony_ci */ 13968c2ecf20Sopenharmony_ci memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci /* 13998c2ecf20Sopenharmony_ci * If firmware name changed, frees firmware. As free_firmware will 14008c2ecf20Sopenharmony_ci * reset the status to NO_FIRMWARE, this forces a new request_firmware 14018c2ecf20Sopenharmony_ci */ 14028c2ecf20Sopenharmony_ci if (!firmware_name[0] && p->fname && 14038c2ecf20Sopenharmony_ci priv->fname && strcmp(p->fname, priv->fname)) 14048c2ecf20Sopenharmony_ci free_firmware(priv); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (priv->ctrl.max_len < 9) 14078c2ecf20Sopenharmony_ci priv->ctrl.max_len = 13; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (priv->state == XC2028_NO_FIRMWARE) { 14108c2ecf20Sopenharmony_ci if (!firmware_name[0]) 14118c2ecf20Sopenharmony_ci priv->fname = kstrdup(p->fname, GFP_KERNEL); 14128c2ecf20Sopenharmony_ci else 14138c2ecf20Sopenharmony_ci priv->fname = firmware_name; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (!priv->fname) { 14168c2ecf20Sopenharmony_ci rc = -ENOMEM; 14178c2ecf20Sopenharmony_ci goto unlock; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci rc = request_firmware_nowait(THIS_MODULE, 1, 14218c2ecf20Sopenharmony_ci priv->fname, 14228c2ecf20Sopenharmony_ci priv->i2c_props.adap->dev.parent, 14238c2ecf20Sopenharmony_ci GFP_KERNEL, 14248c2ecf20Sopenharmony_ci fe, load_firmware_cb); 14258c2ecf20Sopenharmony_ci if (rc < 0) { 14268c2ecf20Sopenharmony_ci tuner_err("Failed to request firmware %s\n", 14278c2ecf20Sopenharmony_ci priv->fname); 14288c2ecf20Sopenharmony_ci priv->state = XC2028_NODEV; 14298c2ecf20Sopenharmony_ci } else 14308c2ecf20Sopenharmony_ci priv->state = XC2028_WAITING_FIRMWARE; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ciunlock: 14338c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return rc; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { 14398c2ecf20Sopenharmony_ci .info = { 14408c2ecf20Sopenharmony_ci .name = "Xceive XC3028", 14418c2ecf20Sopenharmony_ci .frequency_min_hz = 42 * MHz, 14428c2ecf20Sopenharmony_ci .frequency_max_hz = 864 * MHz, 14438c2ecf20Sopenharmony_ci .frequency_step_hz = 50 * kHz, 14448c2ecf20Sopenharmony_ci }, 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci .set_config = xc2028_set_config, 14478c2ecf20Sopenharmony_ci .set_analog_params = xc2028_set_analog_freq, 14488c2ecf20Sopenharmony_ci .release = xc2028_dvb_release, 14498c2ecf20Sopenharmony_ci .get_frequency = xc2028_get_frequency, 14508c2ecf20Sopenharmony_ci .get_rf_strength = xc2028_signal, 14518c2ecf20Sopenharmony_ci .get_afc = xc2028_get_afc, 14528c2ecf20Sopenharmony_ci .set_params = xc2028_set_params, 14538c2ecf20Sopenharmony_ci .sleep = xc2028_sleep, 14548c2ecf20Sopenharmony_ci}; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_cistruct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, 14578c2ecf20Sopenharmony_ci struct xc2028_config *cfg) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci struct xc2028_data *priv; 14608c2ecf20Sopenharmony_ci int instance; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci if (debug) 14638c2ecf20Sopenharmony_ci printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (NULL == cfg) 14668c2ecf20Sopenharmony_ci return NULL; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci if (!fe) { 14698c2ecf20Sopenharmony_ci printk(KERN_ERR "xc2028: No frontend!\n"); 14708c2ecf20Sopenharmony_ci return NULL; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci mutex_lock(&xc2028_list_mutex); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci instance = hybrid_tuner_request_state(struct xc2028_data, priv, 14768c2ecf20Sopenharmony_ci hybrid_tuner_instance_list, 14778c2ecf20Sopenharmony_ci cfg->i2c_adap, cfg->i2c_addr, 14788c2ecf20Sopenharmony_ci "xc2028"); 14798c2ecf20Sopenharmony_ci switch (instance) { 14808c2ecf20Sopenharmony_ci case 0: 14818c2ecf20Sopenharmony_ci /* memory allocation failure */ 14828c2ecf20Sopenharmony_ci goto fail; 14838c2ecf20Sopenharmony_ci case 1: 14848c2ecf20Sopenharmony_ci /* new tuner instance */ 14858c2ecf20Sopenharmony_ci priv->ctrl.max_len = 13; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci mutex_init(&priv->lock); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 14908c2ecf20Sopenharmony_ci break; 14918c2ecf20Sopenharmony_ci case 2: 14928c2ecf20Sopenharmony_ci /* existing tuner instance */ 14938c2ecf20Sopenharmony_ci fe->tuner_priv = priv; 14948c2ecf20Sopenharmony_ci break; 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, 14988c2ecf20Sopenharmony_ci sizeof(xc2028_dvb_tuner_ops)); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci if (cfg->ctrl) 15038c2ecf20Sopenharmony_ci xc2028_set_config(fe, cfg->ctrl); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci mutex_unlock(&xc2028_list_mutex); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci return fe; 15088c2ecf20Sopenharmony_cifail: 15098c2ecf20Sopenharmony_ci mutex_unlock(&xc2028_list_mutex); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci xc2028_dvb_release(fe); 15128c2ecf20Sopenharmony_ci return NULL; 15138c2ecf20Sopenharmony_ci} 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(xc2028_attach); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); 15188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>"); 15198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>"); 15208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 15218c2ecf20Sopenharmony_ciMODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE); 15228c2ecf20Sopenharmony_ciMODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE); 1523