18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for mt2063 Micronas tuner 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2011 Mauro Carvalho Chehab 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This driver came from a driver originally written by: 88c2ecf20Sopenharmony_ci * Henry Wang <Henry.wang@AzureWave.com> 98c2ecf20Sopenharmony_ci * Made publicly available by Terratec, at: 108c2ecf20Sopenharmony_ci * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/string.h> 178c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 188c2ecf20Sopenharmony_ci#include <linux/gcd.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "mt2063.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic unsigned int debug; 238c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Set Verbosity level"); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...) do { \ 278c2ecf20Sopenharmony_ciif (debug >= level) \ 288c2ecf20Sopenharmony_ci printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \ 298c2ecf20Sopenharmony_ci} while (0) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* positive error codes used internally */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Info: Unavoidable LO-related spur may be present in the output */ 358c2ecf20Sopenharmony_ci#define MT2063_SPUR_PRESENT_ERR (0x00800000) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */ 388c2ecf20Sopenharmony_ci#define MT2063_SPUR_CNT_MASK (0x001f0000) 398c2ecf20Sopenharmony_ci#define MT2063_SPUR_SHIFT (16) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */ 428c2ecf20Sopenharmony_ci#define MT2063_UPC_RANGE (0x04000000) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */ 458c2ecf20Sopenharmony_ci#define MT2063_DNC_RANGE (0x08000000) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Constant defining the version of the following structure 498c2ecf20Sopenharmony_ci * and therefore the API for this code. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * When compiling the tuner driver, the preprocessor will 528c2ecf20Sopenharmony_ci * check against this version number to make sure that 538c2ecf20Sopenharmony_ci * it matches the version that the tuner driver knows about. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* DECT Frequency Avoidance */ 578c2ecf20Sopenharmony_ci#define MT2063_DECT_AVOID_US_FREQS 0x00000001 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cienum MT2063_DECT_Avoid_Type { 668c2ecf20Sopenharmony_ci MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */ 678c2ecf20Sopenharmony_ci MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */ 688c2ecf20Sopenharmony_ci MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */ 698c2ecf20Sopenharmony_ci MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */ 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define MT2063_MAX_ZONES 48 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct MT2063_ExclZone_t { 758c2ecf20Sopenharmony_ci u32 min_; 768c2ecf20Sopenharmony_ci u32 max_; 778c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *next_; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * Structure of data needed for Spur Avoidance 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cistruct MT2063_AvoidSpursData_t { 848c2ecf20Sopenharmony_ci u32 f_ref; 858c2ecf20Sopenharmony_ci u32 f_in; 868c2ecf20Sopenharmony_ci u32 f_LO1; 878c2ecf20Sopenharmony_ci u32 f_if1_Center; 888c2ecf20Sopenharmony_ci u32 f_if1_Request; 898c2ecf20Sopenharmony_ci u32 f_if1_bw; 908c2ecf20Sopenharmony_ci u32 f_LO2; 918c2ecf20Sopenharmony_ci u32 f_out; 928c2ecf20Sopenharmony_ci u32 f_out_bw; 938c2ecf20Sopenharmony_ci u32 f_LO1_Step; 948c2ecf20Sopenharmony_ci u32 f_LO2_Step; 958c2ecf20Sopenharmony_ci u32 f_LO1_FracN_Avoid; 968c2ecf20Sopenharmony_ci u32 f_LO2_FracN_Avoid; 978c2ecf20Sopenharmony_ci u32 f_zif_bw; 988c2ecf20Sopenharmony_ci u32 f_min_LO_Separation; 998c2ecf20Sopenharmony_ci u32 maxH1; 1008c2ecf20Sopenharmony_ci u32 maxH2; 1018c2ecf20Sopenharmony_ci enum MT2063_DECT_Avoid_Type avoidDECT; 1028c2ecf20Sopenharmony_ci u32 bSpurPresent; 1038c2ecf20Sopenharmony_ci u32 bSpurAvoided; 1048c2ecf20Sopenharmony_ci u32 nSpursFound; 1058c2ecf20Sopenharmony_ci u32 nZones; 1068c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *freeZones; 1078c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *usedZones; 1088c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES]; 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * Parameter for function MT2063_SetPowerMask that specifies the power down 1138c2ecf20Sopenharmony_ci * of various sections of the MT2063. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_cienum MT2063_Mask_Bits { 1168c2ecf20Sopenharmony_ci MT2063_REG_SD = 0x0040, /* Shutdown regulator */ 1178c2ecf20Sopenharmony_ci MT2063_SRO_SD = 0x0020, /* Shutdown SRO */ 1188c2ecf20Sopenharmony_ci MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */ 1198c2ecf20Sopenharmony_ci MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */ 1208c2ecf20Sopenharmony_ci MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */ 1218c2ecf20Sopenharmony_ci MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */ 1228c2ecf20Sopenharmony_ci MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */ 1238c2ecf20Sopenharmony_ci MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */ 1248c2ecf20Sopenharmony_ci MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */ 1258c2ecf20Sopenharmony_ci MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */ 1268c2ecf20Sopenharmony_ci MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */ 1278c2ecf20Sopenharmony_ci MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */ 1288c2ecf20Sopenharmony_ci MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */ 1298c2ecf20Sopenharmony_ci MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */ 1308c2ecf20Sopenharmony_ci MT2063_NONE_SD = 0x0000 /* No shutdown bits */ 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* 1348c2ecf20Sopenharmony_ci * Possible values for MT2063_DNC_OUTPUT 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_cienum MT2063_DNC_Output_Enable { 1378c2ecf20Sopenharmony_ci MT2063_DNC_NONE = 0, 1388c2ecf20Sopenharmony_ci MT2063_DNC_1, 1398c2ecf20Sopenharmony_ci MT2063_DNC_2, 1408c2ecf20Sopenharmony_ci MT2063_DNC_BOTH 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * Two-wire serial bus subaddresses of the tuner registers. 1458c2ecf20Sopenharmony_ci * Also known as the tuner's register addresses. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_cienum MT2063_Register_Offsets { 1488c2ecf20Sopenharmony_ci MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */ 1498c2ecf20Sopenharmony_ci MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */ 1508c2ecf20Sopenharmony_ci MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */ 1518c2ecf20Sopenharmony_ci MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */ 1528c2ecf20Sopenharmony_ci MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */ 1538c2ecf20Sopenharmony_ci MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */ 1548c2ecf20Sopenharmony_ci MT2063_REG_RSVD_06, /* 0x06: Reserved */ 1558c2ecf20Sopenharmony_ci MT2063_REG_LO_STATUS, /* 0x07: LO Status */ 1568c2ecf20Sopenharmony_ci MT2063_REG_FIFFC, /* 0x08: FIFF Center */ 1578c2ecf20Sopenharmony_ci MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */ 1588c2ecf20Sopenharmony_ci MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */ 1598c2ecf20Sopenharmony_ci MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */ 1608c2ecf20Sopenharmony_ci MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */ 1618c2ecf20Sopenharmony_ci MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */ 1628c2ecf20Sopenharmony_ci MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */ 1638c2ecf20Sopenharmony_ci MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */ 1648c2ecf20Sopenharmony_ci MT2063_REG_RSVD_10, /* 0x10: Reserved */ 1658c2ecf20Sopenharmony_ci MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */ 1668c2ecf20Sopenharmony_ci MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */ 1678c2ecf20Sopenharmony_ci MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */ 1688c2ecf20Sopenharmony_ci MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */ 1698c2ecf20Sopenharmony_ci MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */ 1708c2ecf20Sopenharmony_ci MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */ 1718c2ecf20Sopenharmony_ci MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */ 1728c2ecf20Sopenharmony_ci MT2063_REG_RF_OV, /* 0x18: RF Attn Override */ 1738c2ecf20Sopenharmony_ci MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */ 1748c2ecf20Sopenharmony_ci MT2063_REG_LNA_TGT, /* 0x1A: Reserved */ 1758c2ecf20Sopenharmony_ci MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */ 1768c2ecf20Sopenharmony_ci MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */ 1778c2ecf20Sopenharmony_ci MT2063_REG_RSVD_1D, /* 0x1D: Reserved */ 1788c2ecf20Sopenharmony_ci MT2063_REG_RSVD_1E, /* 0x1E: Reserved */ 1798c2ecf20Sopenharmony_ci MT2063_REG_RSVD_1F, /* 0x1F: Reserved */ 1808c2ecf20Sopenharmony_ci MT2063_REG_RSVD_20, /* 0x20: Reserved */ 1818c2ecf20Sopenharmony_ci MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */ 1828c2ecf20Sopenharmony_ci MT2063_REG_RSVD_22, /* 0x22: Reserved */ 1838c2ecf20Sopenharmony_ci MT2063_REG_RSVD_23, /* 0x23: Reserved */ 1848c2ecf20Sopenharmony_ci MT2063_REG_RSVD_24, /* 0x24: Reserved */ 1858c2ecf20Sopenharmony_ci MT2063_REG_RSVD_25, /* 0x25: Reserved */ 1868c2ecf20Sopenharmony_ci MT2063_REG_RSVD_26, /* 0x26: Reserved */ 1878c2ecf20Sopenharmony_ci MT2063_REG_RSVD_27, /* 0x27: Reserved */ 1888c2ecf20Sopenharmony_ci MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */ 1898c2ecf20Sopenharmony_ci MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */ 1908c2ecf20Sopenharmony_ci MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */ 1918c2ecf20Sopenharmony_ci MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */ 1928c2ecf20Sopenharmony_ci MT2063_REG_CTRL_2C, /* 0x2C: Reserved */ 1938c2ecf20Sopenharmony_ci MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */ 1948c2ecf20Sopenharmony_ci MT2063_REG_RSVD_2E, /* 0x2E: Reserved */ 1958c2ecf20Sopenharmony_ci MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */ 1968c2ecf20Sopenharmony_ci MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */ 1978c2ecf20Sopenharmony_ci MT2063_REG_RSVD_31, /* 0x31: Reserved */ 1988c2ecf20Sopenharmony_ci MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */ 1998c2ecf20Sopenharmony_ci MT2063_REG_RSVD_33, /* 0x33: Reserved */ 2008c2ecf20Sopenharmony_ci MT2063_REG_RSVD_34, /* 0x34: Reserved */ 2018c2ecf20Sopenharmony_ci MT2063_REG_RSVD_35, /* 0x35: Reserved */ 2028c2ecf20Sopenharmony_ci MT2063_REG_RSVD_36, /* 0x36: Reserved */ 2038c2ecf20Sopenharmony_ci MT2063_REG_RSVD_37, /* 0x37: Reserved */ 2048c2ecf20Sopenharmony_ci MT2063_REG_RSVD_38, /* 0x38: Reserved */ 2058c2ecf20Sopenharmony_ci MT2063_REG_RSVD_39, /* 0x39: Reserved */ 2068c2ecf20Sopenharmony_ci MT2063_REG_RSVD_3A, /* 0x3A: Reserved */ 2078c2ecf20Sopenharmony_ci MT2063_REG_RSVD_3B, /* 0x3B: Reserved */ 2088c2ecf20Sopenharmony_ci MT2063_REG_RSVD_3C, /* 0x3C: Reserved */ 2098c2ecf20Sopenharmony_ci MT2063_REG_END_REGS 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistruct mt2063_state { 2138c2ecf20Sopenharmony_ci struct i2c_adapter *i2c; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci bool init; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci const struct mt2063_config *config; 2188c2ecf20Sopenharmony_ci struct dvb_tuner_ops ops; 2198c2ecf20Sopenharmony_ci struct dvb_frontend *frontend; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci u32 frequency; 2228c2ecf20Sopenharmony_ci u32 srate; 2238c2ecf20Sopenharmony_ci u32 bandwidth; 2248c2ecf20Sopenharmony_ci u32 reference; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci u32 tuner_id; 2278c2ecf20Sopenharmony_ci struct MT2063_AvoidSpursData_t AS_Data; 2288c2ecf20Sopenharmony_ci u32 f_IF1_actual; 2298c2ecf20Sopenharmony_ci u32 rcvr_mode; 2308c2ecf20Sopenharmony_ci u32 ctfilt_sw; 2318c2ecf20Sopenharmony_ci u32 CTFiltMax[31]; 2328c2ecf20Sopenharmony_ci u32 num_regs; 2338c2ecf20Sopenharmony_ci u8 reg[MT2063_REG_END_REGS]; 2348c2ecf20Sopenharmony_ci}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/* 2378c2ecf20Sopenharmony_ci * mt2063_write - Write data into the I2C bus 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_cistatic int mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct dvb_frontend *fe = state->frontend; 2428c2ecf20Sopenharmony_ci int ret; 2438c2ecf20Sopenharmony_ci u8 buf[60]; 2448c2ecf20Sopenharmony_ci struct i2c_msg msg = { 2458c2ecf20Sopenharmony_ci .addr = state->config->tuner_address, 2468c2ecf20Sopenharmony_ci .flags = 0, 2478c2ecf20Sopenharmony_ci .buf = buf, 2488c2ecf20Sopenharmony_ci .len = len + 1 2498c2ecf20Sopenharmony_ci }; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci dprintk(2, "\n"); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci msg.buf[0] = reg; 2548c2ecf20Sopenharmony_ci memcpy(msg.buf + 1, data, len); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 2578c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 2588c2ecf20Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 2598c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 2608c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (ret < 0) 2638c2ecf20Sopenharmony_ci printk(KERN_ERR "%s error ret=%d\n", __func__, ret); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return ret; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* 2698c2ecf20Sopenharmony_ci * mt2063_write - Write register data into the I2C bus, caching the value 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cistatic int mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci int status; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci dprintk(2, "\n"); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (reg >= MT2063_REG_END_REGS) 2788c2ecf20Sopenharmony_ci return -ERANGE; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci status = mt2063_write(state, reg, &val, 1); 2818c2ecf20Sopenharmony_ci if (status < 0) 2828c2ecf20Sopenharmony_ci return status; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci state->reg[reg] = val; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci/* 2908c2ecf20Sopenharmony_ci * mt2063_read - Read data from the I2C bus 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_cistatic int mt2063_read(struct mt2063_state *state, 2938c2ecf20Sopenharmony_ci u8 subAddress, u8 *pData, u32 cnt) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci int status = 0; /* Status to be returned */ 2968c2ecf20Sopenharmony_ci struct dvb_frontend *fe = state->frontend; 2978c2ecf20Sopenharmony_ci u32 i = 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3028c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 3058c2ecf20Sopenharmony_ci u8 b0[] = { subAddress + i }; 3068c2ecf20Sopenharmony_ci struct i2c_msg msg[] = { 3078c2ecf20Sopenharmony_ci { 3088c2ecf20Sopenharmony_ci .addr = state->config->tuner_address, 3098c2ecf20Sopenharmony_ci .flags = 0, 3108c2ecf20Sopenharmony_ci .buf = b0, 3118c2ecf20Sopenharmony_ci .len = 1 3128c2ecf20Sopenharmony_ci }, { 3138c2ecf20Sopenharmony_ci .addr = state->config->tuner_address, 3148c2ecf20Sopenharmony_ci .flags = I2C_M_RD, 3158c2ecf20Sopenharmony_ci .buf = pData + i, 3168c2ecf20Sopenharmony_ci .len = 1 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci }; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci status = i2c_transfer(state->i2c, msg, 2); 3218c2ecf20Sopenharmony_ci dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n", 3228c2ecf20Sopenharmony_ci subAddress + i, status, *(pData + i)); 3238c2ecf20Sopenharmony_ci if (status < 0) 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3278c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (status < 0) 3308c2ecf20Sopenharmony_ci printk(KERN_ERR "Can't read from address 0x%02x,\n", 3318c2ecf20Sopenharmony_ci subAddress + i); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return status; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/* 3378c2ecf20Sopenharmony_ci * FIXME: Is this really needed? 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_cistatic int MT2063_Sleep(struct dvb_frontend *fe) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci /* 3428c2ecf20Sopenharmony_ci * ToDo: Add code here to implement a OS blocking 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci msleep(100); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * Microtune spur avoidance 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* Implement ceiling, floor functions. */ 3548c2ecf20Sopenharmony_ci#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0)) 3558c2ecf20Sopenharmony_ci#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d)) 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistruct MT2063_FIFZone_t { 3588c2ecf20Sopenharmony_ci s32 min_; 3598c2ecf20Sopenharmony_ci s32 max_; 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t 3638c2ecf20Sopenharmony_ci *pAS_Info, 3648c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *pPrevNode) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *pNode; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci dprintk(2, "\n"); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Check for a node in the free list */ 3718c2ecf20Sopenharmony_ci if (pAS_Info->freeZones != NULL) { 3728c2ecf20Sopenharmony_ci /* Use one from the free list */ 3738c2ecf20Sopenharmony_ci pNode = pAS_Info->freeZones; 3748c2ecf20Sopenharmony_ci pAS_Info->freeZones = pNode->next_; 3758c2ecf20Sopenharmony_ci } else { 3768c2ecf20Sopenharmony_ci /* Grab a node from the array */ 3778c2ecf20Sopenharmony_ci pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones]; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (pPrevNode != NULL) { 3818c2ecf20Sopenharmony_ci pNode->next_ = pPrevNode->next_; 3828c2ecf20Sopenharmony_ci pPrevNode->next_ = pNode; 3838c2ecf20Sopenharmony_ci } else { /* insert at the beginning of the list */ 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci pNode->next_ = pAS_Info->usedZones; 3868c2ecf20Sopenharmony_ci pAS_Info->usedZones = pNode; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci pAS_Info->nZones++; 3908c2ecf20Sopenharmony_ci return pNode; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t 3948c2ecf20Sopenharmony_ci *pAS_Info, 3958c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *pPrevNode, 3968c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t 3978c2ecf20Sopenharmony_ci *pNodeToRemove) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci dprintk(2, "\n"); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Make previous node point to the subsequent node */ 4048c2ecf20Sopenharmony_ci if (pPrevNode != NULL) 4058c2ecf20Sopenharmony_ci pPrevNode->next_ = pNext; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Add pNodeToRemove to the beginning of the freeZones */ 4088c2ecf20Sopenharmony_ci pNodeToRemove->next_ = pAS_Info->freeZones; 4098c2ecf20Sopenharmony_ci pAS_Info->freeZones = pNodeToRemove; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Decrement node count */ 4128c2ecf20Sopenharmony_ci pAS_Info->nZones--; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return pNext; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/* 4188c2ecf20Sopenharmony_ci * MT_AddExclZone() 4198c2ecf20Sopenharmony_ci * 4208c2ecf20Sopenharmony_ci * Add (and merge) an exclusion zone into the list. 4218c2ecf20Sopenharmony_ci * If the range (f_min, f_max) is totally outside the 4228c2ecf20Sopenharmony_ci * 1st IF BW, ignore the entry. 4238c2ecf20Sopenharmony_ci * If the range (f_min, f_max) is negative, ignore the entry. 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_cistatic void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, 4268c2ecf20Sopenharmony_ci u32 f_min, u32 f_max) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; 4298c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *pPrev = NULL; 4308c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *pNext = NULL; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci dprintk(2, "\n"); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Check to see if this overlaps the 1st IF filter */ 4358c2ecf20Sopenharmony_ci if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2))) 4368c2ecf20Sopenharmony_ci && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2))) 4378c2ecf20Sopenharmony_ci && (f_min < f_max)) { 4388c2ecf20Sopenharmony_ci /* 4398c2ecf20Sopenharmony_ci * 1 2 3 4 5 6 4408c2ecf20Sopenharmony_ci * 4418c2ecf20Sopenharmony_ci * New entry: |---| |--| |--| |-| |---| |--| 4428c2ecf20Sopenharmony_ci * or or or or or 4438c2ecf20Sopenharmony_ci * Existing: |--| |--| |--| |---| |-| |--| 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* Check for our place in the list */ 4478c2ecf20Sopenharmony_ci while ((pNode != NULL) && (pNode->max_ < f_min)) { 4488c2ecf20Sopenharmony_ci pPrev = pNode; 4498c2ecf20Sopenharmony_ci pNode = pNode->next_; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if ((pNode != NULL) && (pNode->min_ < f_max)) { 4538c2ecf20Sopenharmony_ci /* Combine me with pNode */ 4548c2ecf20Sopenharmony_ci if (f_min < pNode->min_) 4558c2ecf20Sopenharmony_ci pNode->min_ = f_min; 4568c2ecf20Sopenharmony_ci if (f_max > pNode->max_) 4578c2ecf20Sopenharmony_ci pNode->max_ = f_max; 4588c2ecf20Sopenharmony_ci } else { 4598c2ecf20Sopenharmony_ci pNode = InsertNode(pAS_Info, pPrev); 4608c2ecf20Sopenharmony_ci pNode->min_ = f_min; 4618c2ecf20Sopenharmony_ci pNode->max_ = f_max; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Look for merging possibilities */ 4658c2ecf20Sopenharmony_ci pNext = pNode->next_; 4668c2ecf20Sopenharmony_ci while ((pNext != NULL) && (pNext->min_ < pNode->max_)) { 4678c2ecf20Sopenharmony_ci if (pNext->max_ > pNode->max_) 4688c2ecf20Sopenharmony_ci pNode->max_ = pNext->max_; 4698c2ecf20Sopenharmony_ci /* Remove pNext, return ptr to pNext->next */ 4708c2ecf20Sopenharmony_ci pNext = RemoveNode(pAS_Info, pNode, pNext); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* 4768c2ecf20Sopenharmony_ci * Reset all exclusion zones. 4778c2ecf20Sopenharmony_ci * Add zones to protect the PLL FracN regions near zero 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_cistatic void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci u32 center; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci dprintk(2, "\n"); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci pAS_Info->nZones = 0; /* this clears the used list */ 4868c2ecf20Sopenharmony_ci pAS_Info->usedZones = NULL; /* reset ptr */ 4878c2ecf20Sopenharmony_ci pAS_Info->freeZones = NULL; /* reset ptr */ 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci center = 4908c2ecf20Sopenharmony_ci pAS_Info->f_ref * 4918c2ecf20Sopenharmony_ci ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 + 4928c2ecf20Sopenharmony_ci pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in; 4938c2ecf20Sopenharmony_ci while (center < 4948c2ecf20Sopenharmony_ci pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + 4958c2ecf20Sopenharmony_ci pAS_Info->f_LO1_FracN_Avoid) { 4968c2ecf20Sopenharmony_ci /* Exclude LO1 FracN */ 4978c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 4988c2ecf20Sopenharmony_ci center - pAS_Info->f_LO1_FracN_Avoid, 4998c2ecf20Sopenharmony_ci center - 1); 5008c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, center + 1, 5018c2ecf20Sopenharmony_ci center + pAS_Info->f_LO1_FracN_Avoid); 5028c2ecf20Sopenharmony_ci center += pAS_Info->f_ref; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci center = 5068c2ecf20Sopenharmony_ci pAS_Info->f_ref * 5078c2ecf20Sopenharmony_ci ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 - 5088c2ecf20Sopenharmony_ci pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out; 5098c2ecf20Sopenharmony_ci while (center < 5108c2ecf20Sopenharmony_ci pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + 5118c2ecf20Sopenharmony_ci pAS_Info->f_LO2_FracN_Avoid) { 5128c2ecf20Sopenharmony_ci /* Exclude LO2 FracN */ 5138c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 5148c2ecf20Sopenharmony_ci center - pAS_Info->f_LO2_FracN_Avoid, 5158c2ecf20Sopenharmony_ci center - 1); 5168c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, center + 1, 5178c2ecf20Sopenharmony_ci center + pAS_Info->f_LO2_FracN_Avoid); 5188c2ecf20Sopenharmony_ci center += pAS_Info->f_ref; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { 5228c2ecf20Sopenharmony_ci /* Exclude LO1 values that conflict with DECT channels */ 5238c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */ 5248c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */ 5258c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */ 5268c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */ 5278c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */ 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { 5318c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */ 5328c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */ 5338c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */ 5348c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */ 5358c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */ 5368c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */ 5378c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */ 5388c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */ 5398c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */ 5408c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */ 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci/* 5458c2ecf20Sopenharmony_ci * MT_ChooseFirstIF - Choose the best available 1st IF 5468c2ecf20Sopenharmony_ci * If f_Desired is not excluded, choose that first. 5478c2ecf20Sopenharmony_ci * Otherwise, return the value closest to f_Center that is 5488c2ecf20Sopenharmony_ci * not excluded 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_cistatic u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci /* 5538c2ecf20Sopenharmony_ci * Update "f_Desired" to be the nearest "combinational-multiple" of 5548c2ecf20Sopenharmony_ci * "f_LO1_Step". 5558c2ecf20Sopenharmony_ci * The resulting number, F_LO1 must be a multiple of f_LO1_Step. 5568c2ecf20Sopenharmony_ci * And F_LO1 is the arithmetic sum of f_in + f_Center. 5578c2ecf20Sopenharmony_ci * Neither f_in, nor f_Center must be a multiple of f_LO1_Step. 5588c2ecf20Sopenharmony_ci * However, the sum must be. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci const u32 f_Desired = 5618c2ecf20Sopenharmony_ci pAS_Info->f_LO1_Step * 5628c2ecf20Sopenharmony_ci ((pAS_Info->f_if1_Request + pAS_Info->f_in + 5638c2ecf20Sopenharmony_ci pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) - 5648c2ecf20Sopenharmony_ci pAS_Info->f_in; 5658c2ecf20Sopenharmony_ci const u32 f_Step = 5668c2ecf20Sopenharmony_ci (pAS_Info->f_LO1_Step > 5678c2ecf20Sopenharmony_ci pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info-> 5688c2ecf20Sopenharmony_ci f_LO2_Step; 5698c2ecf20Sopenharmony_ci u32 f_Center; 5708c2ecf20Sopenharmony_ci s32 i; 5718c2ecf20Sopenharmony_ci s32 j = 0; 5728c2ecf20Sopenharmony_ci u32 bDesiredExcluded = 0; 5738c2ecf20Sopenharmony_ci u32 bZeroExcluded = 0; 5748c2ecf20Sopenharmony_ci s32 tmpMin, tmpMax; 5758c2ecf20Sopenharmony_ci s32 bestDiff; 5768c2ecf20Sopenharmony_ci struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; 5778c2ecf20Sopenharmony_ci struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES]; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci dprintk(2, "\n"); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (pAS_Info->nZones == 0) 5828c2ecf20Sopenharmony_ci return f_Desired; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* 5858c2ecf20Sopenharmony_ci * f_Center needs to be an integer multiple of f_Step away 5868c2ecf20Sopenharmony_ci * from f_Desired 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci if (pAS_Info->f_if1_Center > f_Desired) 5898c2ecf20Sopenharmony_ci f_Center = 5908c2ecf20Sopenharmony_ci f_Desired + 5918c2ecf20Sopenharmony_ci f_Step * 5928c2ecf20Sopenharmony_ci ((pAS_Info->f_if1_Center - f_Desired + 5938c2ecf20Sopenharmony_ci f_Step / 2) / f_Step); 5948c2ecf20Sopenharmony_ci else 5958c2ecf20Sopenharmony_ci f_Center = 5968c2ecf20Sopenharmony_ci f_Desired - 5978c2ecf20Sopenharmony_ci f_Step * 5988c2ecf20Sopenharmony_ci ((f_Desired - pAS_Info->f_if1_Center + 5998c2ecf20Sopenharmony_ci f_Step / 2) / f_Step); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * Take MT_ExclZones, center around f_Center and change the 6038c2ecf20Sopenharmony_ci * resolution to f_Step 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci while (pNode != NULL) { 6068c2ecf20Sopenharmony_ci /* floor function */ 6078c2ecf20Sopenharmony_ci tmpMin = 6088c2ecf20Sopenharmony_ci floor((s32) (pNode->min_ - f_Center), (s32) f_Step); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* ceil function */ 6118c2ecf20Sopenharmony_ci tmpMax = 6128c2ecf20Sopenharmony_ci ceil((s32) (pNode->max_ - f_Center), (s32) f_Step); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired)) 6158c2ecf20Sopenharmony_ci bDesiredExcluded = 1; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if ((tmpMin < 0) && (tmpMax > 0)) 6188c2ecf20Sopenharmony_ci bZeroExcluded = 1; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* See if this zone overlaps the previous */ 6218c2ecf20Sopenharmony_ci if ((j > 0) && (tmpMin < zones[j - 1].max_)) 6228c2ecf20Sopenharmony_ci zones[j - 1].max_ = tmpMax; 6238c2ecf20Sopenharmony_ci else { 6248c2ecf20Sopenharmony_ci /* Add new zone */ 6258c2ecf20Sopenharmony_ci zones[j].min_ = tmpMin; 6268c2ecf20Sopenharmony_ci zones[j].max_ = tmpMax; 6278c2ecf20Sopenharmony_ci j++; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci pNode = pNode->next_; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* 6338c2ecf20Sopenharmony_ci * If the desired is okay, return with it 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci if (bDesiredExcluded == 0) 6368c2ecf20Sopenharmony_ci return f_Desired; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* 6398c2ecf20Sopenharmony_ci * If the desired is excluded and the center is okay, return with it 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_ci if (bZeroExcluded == 0) 6428c2ecf20Sopenharmony_ci return f_Center; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Find the value closest to 0 (f_Center) */ 6458c2ecf20Sopenharmony_ci bestDiff = zones[0].min_; 6468c2ecf20Sopenharmony_ci for (i = 0; i < j; i++) { 6478c2ecf20Sopenharmony_ci if (abs(zones[i].min_) < abs(bestDiff)) 6488c2ecf20Sopenharmony_ci bestDiff = zones[i].min_; 6498c2ecf20Sopenharmony_ci if (abs(zones[i].max_) < abs(bestDiff)) 6508c2ecf20Sopenharmony_ci bestDiff = zones[i].max_; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (bestDiff < 0) 6548c2ecf20Sopenharmony_ci return f_Center - ((u32) (-bestDiff) * f_Step); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci return f_Center + (bestDiff * f_Step); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci/** 6608c2ecf20Sopenharmony_ci * IsSpurInBand() - Checks to see if a spur will be present within the IF's 6618c2ecf20Sopenharmony_ci * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) 6628c2ecf20Sopenharmony_ci * 6638c2ecf20Sopenharmony_ci * ma mb mc md 6648c2ecf20Sopenharmony_ci * <--+-+-+-------------------+-------------------+-+-+--> 6658c2ecf20Sopenharmony_ci * | ^ 0 ^ | 6668c2ecf20Sopenharmony_ci * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ 6678c2ecf20Sopenharmony_ci * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 6688c2ecf20Sopenharmony_ci * 6698c2ecf20Sopenharmony_ci * Note that some equations are doubled to prevent round-off 6708c2ecf20Sopenharmony_ci * problems when calculating fIFBW/2 6718c2ecf20Sopenharmony_ci * 6728c2ecf20Sopenharmony_ci * @pAS_Info: Avoid Spurs information block 6738c2ecf20Sopenharmony_ci * @fm: If spur, amount f_IF1 has to move negative 6748c2ecf20Sopenharmony_ci * @fp: If spur, amount f_IF1 has to move positive 6758c2ecf20Sopenharmony_ci * 6768c2ecf20Sopenharmony_ci * Returns 1 if an LO spur would be present, otherwise 0. 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_cistatic u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, 6798c2ecf20Sopenharmony_ci u32 *fm, u32 * fp) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci /* 6828c2ecf20Sopenharmony_ci ** Calculate LO frequency settings. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci u32 n, n0; 6858c2ecf20Sopenharmony_ci const u32 f_LO1 = pAS_Info->f_LO1; 6868c2ecf20Sopenharmony_ci const u32 f_LO2 = pAS_Info->f_LO2; 6878c2ecf20Sopenharmony_ci const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2; 6888c2ecf20Sopenharmony_ci const u32 c = d - pAS_Info->f_out_bw; 6898c2ecf20Sopenharmony_ci const u32 f = pAS_Info->f_zif_bw / 2; 6908c2ecf20Sopenharmony_ci const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1; 6918c2ecf20Sopenharmony_ci s32 f_nsLO1, f_nsLO2; 6928c2ecf20Sopenharmony_ci s32 f_Spur; 6938c2ecf20Sopenharmony_ci u32 ma, mb, mc, md, me, mf; 6948c2ecf20Sopenharmony_ci u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci dprintk(2, "\n"); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci *fm = 0; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* 7018c2ecf20Sopenharmony_ci ** For each edge (d, c & f), calculate a scale, based on the gcd 7028c2ecf20Sopenharmony_ci ** of f_LO1, f_LO2 and the edge value. Use the larger of this 7038c2ecf20Sopenharmony_ci ** gcd-based scale factor or f_Scale. 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_ci lo_gcd = gcd(f_LO1, f_LO2); 7068c2ecf20Sopenharmony_ci gd_Scale = max((u32) gcd(lo_gcd, d), f_Scale); 7078c2ecf20Sopenharmony_ci hgds = gd_Scale / 2; 7088c2ecf20Sopenharmony_ci gc_Scale = max((u32) gcd(lo_gcd, c), f_Scale); 7098c2ecf20Sopenharmony_ci hgcs = gc_Scale / 2; 7108c2ecf20Sopenharmony_ci gf_Scale = max((u32) gcd(lo_gcd, f), f_Scale); 7118c2ecf20Sopenharmony_ci hgfs = gf_Scale / 2; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */ 7168c2ecf20Sopenharmony_ci for (n = n0; n <= pAS_Info->maxH1; ++n) { 7178c2ecf20Sopenharmony_ci md = (n * ((f_LO1 + hgds) / gd_Scale) - 7188c2ecf20Sopenharmony_ci ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */ 7218c2ecf20Sopenharmony_ci if (md >= pAS_Info->maxH1) 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci ma = (n * ((f_LO1 + hgds) / gd_Scale) + 7258c2ecf20Sopenharmony_ci ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */ 7288c2ecf20Sopenharmony_ci if (md == ma) 7298c2ecf20Sopenharmony_ci continue; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci mc = (n * ((f_LO1 + hgcs) / gc_Scale) - 7328c2ecf20Sopenharmony_ci ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); 7338c2ecf20Sopenharmony_ci if (mc != md) { 7348c2ecf20Sopenharmony_ci f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale)); 7358c2ecf20Sopenharmony_ci f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale)); 7368c2ecf20Sopenharmony_ci f_Spur = 7378c2ecf20Sopenharmony_ci (gc_Scale * (f_nsLO1 - f_nsLO2)) + 7388c2ecf20Sopenharmony_ci n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci *fp = ((f_Spur - (s32) c) / (mc - n)) + 1; 7418c2ecf20Sopenharmony_ci *fm = (((s32) d - f_Spur) / (mc - n)) + 1; 7428c2ecf20Sopenharmony_ci return 1; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Location of Zero-IF-spur to be checked */ 7468c2ecf20Sopenharmony_ci me = (n * ((f_LO1 + hgfs) / gf_Scale) + 7478c2ecf20Sopenharmony_ci ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); 7488c2ecf20Sopenharmony_ci mf = (n * ((f_LO1 + hgfs) / gf_Scale) - 7498c2ecf20Sopenharmony_ci ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); 7508c2ecf20Sopenharmony_ci if (me != mf) { 7518c2ecf20Sopenharmony_ci f_nsLO1 = n * (f_LO1 / gf_Scale); 7528c2ecf20Sopenharmony_ci f_nsLO2 = me * (f_LO2 / gf_Scale); 7538c2ecf20Sopenharmony_ci f_Spur = 7548c2ecf20Sopenharmony_ci (gf_Scale * (f_nsLO1 - f_nsLO2)) + 7558c2ecf20Sopenharmony_ci n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci *fp = ((f_Spur + (s32) f) / (me - n)) + 1; 7588c2ecf20Sopenharmony_ci *fm = (((s32) f - f_Spur) / (me - n)) + 1; 7598c2ecf20Sopenharmony_ci return 1; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci mb = (n * ((f_LO1 + hgcs) / gc_Scale) + 7638c2ecf20Sopenharmony_ci ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); 7648c2ecf20Sopenharmony_ci if (ma != mb) { 7658c2ecf20Sopenharmony_ci f_nsLO1 = n * (f_LO1 / gc_Scale); 7668c2ecf20Sopenharmony_ci f_nsLO2 = ma * (f_LO2 / gc_Scale); 7678c2ecf20Sopenharmony_ci f_Spur = 7688c2ecf20Sopenharmony_ci (gc_Scale * (f_nsLO1 - f_nsLO2)) + 7698c2ecf20Sopenharmony_ci n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci *fp = (((s32) d + f_Spur) / (ma - n)) + 1; 7728c2ecf20Sopenharmony_ci *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1; 7738c2ecf20Sopenharmony_ci return 1; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* No spurs found */ 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci/* 7828c2ecf20Sopenharmony_ci * MT_AvoidSpurs() - Main entry point to avoid spurs. 7838c2ecf20Sopenharmony_ci * Checks for existing spurs in present LO1, LO2 freqs 7848c2ecf20Sopenharmony_ci * and if present, chooses spur-free LO1, LO2 combination 7858c2ecf20Sopenharmony_ci * that tunes the same input/output frequencies. 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_cistatic u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci int status = 0; 7908c2ecf20Sopenharmony_ci u32 fm, fp; /* restricted range on LO's */ 7918c2ecf20Sopenharmony_ci pAS_Info->bSpurAvoided = 0; 7928c2ecf20Sopenharmony_ci pAS_Info->nSpursFound = 0; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci dprintk(2, "\n"); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (pAS_Info->maxH1 == 0) 7978c2ecf20Sopenharmony_ci return 0; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* 8008c2ecf20Sopenharmony_ci * Avoid LO Generated Spurs 8018c2ecf20Sopenharmony_ci * 8028c2ecf20Sopenharmony_ci * Make sure that have no LO-related spurs within the IF output 8038c2ecf20Sopenharmony_ci * bandwidth. 8048c2ecf20Sopenharmony_ci * 8058c2ecf20Sopenharmony_ci * If there is an LO spur in this band, start at the current IF1 frequency 8068c2ecf20Sopenharmony_ci * and work out until we find a spur-free frequency or run up against the 8078c2ecf20Sopenharmony_ci * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they 8088c2ecf20Sopenharmony_ci * will be unchanged if a spur-free setting is not found. 8098c2ecf20Sopenharmony_ci */ 8108c2ecf20Sopenharmony_ci pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); 8118c2ecf20Sopenharmony_ci if (pAS_Info->bSpurPresent) { 8128c2ecf20Sopenharmony_ci u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */ 8138c2ecf20Sopenharmony_ci u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */ 8148c2ecf20Sopenharmony_ci u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */ 8158c2ecf20Sopenharmony_ci u32 delta_IF1; 8168c2ecf20Sopenharmony_ci u32 new_IF1; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* 8198c2ecf20Sopenharmony_ci ** Spur was found, attempt to find a spur-free 1st IF 8208c2ecf20Sopenharmony_ci */ 8218c2ecf20Sopenharmony_ci do { 8228c2ecf20Sopenharmony_ci pAS_Info->nSpursFound++; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Raise f_IF1_upper, if needed */ 8258c2ecf20Sopenharmony_ci MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci /* Choose next IF1 that is closest to f_IF1_CENTER */ 8288c2ecf20Sopenharmony_ci new_IF1 = MT2063_ChooseFirstIF(pAS_Info); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (new_IF1 > zfIF1) { 8318c2ecf20Sopenharmony_ci pAS_Info->f_LO1 += (new_IF1 - zfIF1); 8328c2ecf20Sopenharmony_ci pAS_Info->f_LO2 += (new_IF1 - zfIF1); 8338c2ecf20Sopenharmony_ci } else { 8348c2ecf20Sopenharmony_ci pAS_Info->f_LO1 -= (zfIF1 - new_IF1); 8358c2ecf20Sopenharmony_ci pAS_Info->f_LO2 -= (zfIF1 - new_IF1); 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci zfIF1 = new_IF1; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (zfIF1 > pAS_Info->f_if1_Center) 8408c2ecf20Sopenharmony_ci delta_IF1 = zfIF1 - pAS_Info->f_if1_Center; 8418c2ecf20Sopenharmony_ci else 8428c2ecf20Sopenharmony_ci delta_IF1 = pAS_Info->f_if1_Center - zfIF1; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); 8458c2ecf20Sopenharmony_ci /* 8468c2ecf20Sopenharmony_ci * Continue while the new 1st IF is still within the 1st IF bandwidth 8478c2ecf20Sopenharmony_ci * and there is a spur in the band (again) 8488c2ecf20Sopenharmony_ci */ 8498c2ecf20Sopenharmony_ci } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* 8528c2ecf20Sopenharmony_ci * Use the LO-spur free values found. If the search went all 8538c2ecf20Sopenharmony_ci * the way to the 1st IF band edge and always found spurs, just 8548c2ecf20Sopenharmony_ci * leave the original choice. It's as "good" as any other. 8558c2ecf20Sopenharmony_ci */ 8568c2ecf20Sopenharmony_ci if (pAS_Info->bSpurPresent == 1) { 8578c2ecf20Sopenharmony_ci status |= MT2063_SPUR_PRESENT_ERR; 8588c2ecf20Sopenharmony_ci pAS_Info->f_LO1 = zfLO1; 8598c2ecf20Sopenharmony_ci pAS_Info->f_LO2 = zfLO2; 8608c2ecf20Sopenharmony_ci } else 8618c2ecf20Sopenharmony_ci pAS_Info->bSpurAvoided = 1; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci status |= 8658c2ecf20Sopenharmony_ci ((pAS_Info-> 8668c2ecf20Sopenharmony_ci nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci return status; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci/* 8728c2ecf20Sopenharmony_ci * Constants used by the tuning algorithm 8738c2ecf20Sopenharmony_ci */ 8748c2ecf20Sopenharmony_ci#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */ 8758c2ecf20Sopenharmony_ci#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */ 8768c2ecf20Sopenharmony_ci#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */ 8778c2ecf20Sopenharmony_ci#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */ 8788c2ecf20Sopenharmony_ci#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */ 8798c2ecf20Sopenharmony_ci#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */ 8808c2ecf20Sopenharmony_ci#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */ 8818c2ecf20Sopenharmony_ci#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */ 8828c2ecf20Sopenharmony_ci#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */ 8838c2ecf20Sopenharmony_ci#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */ 8848c2ecf20Sopenharmony_ci#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */ 8858c2ecf20Sopenharmony_ci#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */ 8868c2ecf20Sopenharmony_ci#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */ 8878c2ecf20Sopenharmony_ci#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */ 8888c2ecf20Sopenharmony_ci#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */ 8898c2ecf20Sopenharmony_ci#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */ 8908c2ecf20Sopenharmony_ci#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */ 8918c2ecf20Sopenharmony_ci#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */ 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci/* 8948c2ecf20Sopenharmony_ci * Define the supported Part/Rev codes for the MT2063 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_ci#define MT2063_B0 (0x9B) 8978c2ecf20Sopenharmony_ci#define MT2063_B1 (0x9C) 8988c2ecf20Sopenharmony_ci#define MT2063_B2 (0x9D) 8998c2ecf20Sopenharmony_ci#define MT2063_B3 (0x9E) 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci/** 9028c2ecf20Sopenharmony_ci * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked 9038c2ecf20Sopenharmony_ci * 9048c2ecf20Sopenharmony_ci * @state: struct mt2063_state pointer 9058c2ecf20Sopenharmony_ci * 9068c2ecf20Sopenharmony_ci * This function returns 0, if no lock, 1 if locked and a value < 1 if error 9078c2ecf20Sopenharmony_ci */ 9088c2ecf20Sopenharmony_cistatic int mt2063_lockStatus(struct mt2063_state *state) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ 9118c2ecf20Sopenharmony_ci const u32 nPollRate = 2; /* poll status bits every 2 ms */ 9128c2ecf20Sopenharmony_ci const u32 nMaxLoops = nMaxWait / nPollRate; 9138c2ecf20Sopenharmony_ci const u8 LO1LK = 0x80; 9148c2ecf20Sopenharmony_ci u8 LO2LK = 0x08; 9158c2ecf20Sopenharmony_ci int status; 9168c2ecf20Sopenharmony_ci u32 nDelays = 0; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci dprintk(2, "\n"); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* LO2 Lock bit was in a different place for B0 version */ 9218c2ecf20Sopenharmony_ci if (state->tuner_id == MT2063_B0) 9228c2ecf20Sopenharmony_ci LO2LK = 0x40; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci do { 9258c2ecf20Sopenharmony_ci status = mt2063_read(state, MT2063_REG_LO_STATUS, 9268c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_LO_STATUS], 1); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (status < 0) 9298c2ecf20Sopenharmony_ci return status; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) == 9328c2ecf20Sopenharmony_ci (LO1LK | LO2LK)) { 9338c2ecf20Sopenharmony_ci return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci msleep(nPollRate); /* Wait between retries */ 9368c2ecf20Sopenharmony_ci } while (++nDelays < nMaxLoops); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* 9398c2ecf20Sopenharmony_ci * Got no lock or partial lock 9408c2ecf20Sopenharmony_ci */ 9418c2ecf20Sopenharmony_ci return 0; 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci/* 9458c2ecf20Sopenharmony_ci * Constants for setting receiver modes. 9468c2ecf20Sopenharmony_ci * (6 modes defined at this time, enumerated by mt2063_delivery_sys) 9478c2ecf20Sopenharmony_ci * (DNC1GC & DNC2GC are the values, which are used, when the specific 9488c2ecf20Sopenharmony_ci * DNC Output is selected, the other is always off) 9498c2ecf20Sopenharmony_ci * 9508c2ecf20Sopenharmony_ci * enum mt2063_delivery_sys 9518c2ecf20Sopenharmony_ci * -------------+---------------------------------------------- 9528c2ecf20Sopenharmony_ci * Mode 0 : | MT2063_CABLE_QAM 9538c2ecf20Sopenharmony_ci * Mode 1 : | MT2063_CABLE_ANALOG 9548c2ecf20Sopenharmony_ci * Mode 2 : | MT2063_OFFAIR_COFDM 9558c2ecf20Sopenharmony_ci * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS 9568c2ecf20Sopenharmony_ci * Mode 4 : | MT2063_OFFAIR_ANALOG 9578c2ecf20Sopenharmony_ci * Mode 5 : | MT2063_OFFAIR_8VSB 9588c2ecf20Sopenharmony_ci * --------------+---------------------------------------------- 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci * |<---------- Mode -------------->| 9618c2ecf20Sopenharmony_ci * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | 9628c2ecf20Sopenharmony_ci * ------------+-----+-----+-----+-----+-----+-----+ 9638c2ecf20Sopenharmony_ci * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF 9648c2ecf20Sopenharmony_ci * LNARin | 0 | 0 | 3 | 3 | 3 | 3 9658c2ecf20Sopenharmony_ci * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 9668c2ecf20Sopenharmony_ci * FIFFq | 0 | 0 | 0 | 0 | 0 | 0 9678c2ecf20Sopenharmony_ci * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 9688c2ecf20Sopenharmony_ci * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 9698c2ecf20Sopenharmony_ci * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 9708c2ecf20Sopenharmony_ci * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 9718c2ecf20Sopenharmony_ci * LNA Target | 44 | 43 | 43 | 43 | 43 | 43 9728c2ecf20Sopenharmony_ci * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 9738c2ecf20Sopenharmony_ci * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 9748c2ecf20Sopenharmony_ci * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 9758c2ecf20Sopenharmony_ci * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 9768c2ecf20Sopenharmony_ci * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 9778c2ecf20Sopenharmony_ci * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cienum mt2063_delivery_sys { 9818c2ecf20Sopenharmony_ci MT2063_CABLE_QAM = 0, 9828c2ecf20Sopenharmony_ci MT2063_CABLE_ANALOG, 9838c2ecf20Sopenharmony_ci MT2063_OFFAIR_COFDM, 9848c2ecf20Sopenharmony_ci MT2063_OFFAIR_COFDM_SAWLESS, 9858c2ecf20Sopenharmony_ci MT2063_OFFAIR_ANALOG, 9868c2ecf20Sopenharmony_ci MT2063_OFFAIR_8VSB, 9878c2ecf20Sopenharmony_ci MT2063_NUM_RCVR_MODES 9888c2ecf20Sopenharmony_ci}; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic const char *mt2063_mode_name[] = { 9918c2ecf20Sopenharmony_ci [MT2063_CABLE_QAM] = "digital cable", 9928c2ecf20Sopenharmony_ci [MT2063_CABLE_ANALOG] = "analog cable", 9938c2ecf20Sopenharmony_ci [MT2063_OFFAIR_COFDM] = "digital offair", 9948c2ecf20Sopenharmony_ci [MT2063_OFFAIR_COFDM_SAWLESS] = "digital offair without SAW", 9958c2ecf20Sopenharmony_ci [MT2063_OFFAIR_ANALOG] = "analog offair", 9968c2ecf20Sopenharmony_ci [MT2063_OFFAIR_8VSB] = "analog offair 8vsb", 9978c2ecf20Sopenharmony_ci}; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 }; 10008c2ecf20Sopenharmony_cistatic const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 }; 10018c2ecf20Sopenharmony_cistatic const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 }; 10028c2ecf20Sopenharmony_cistatic const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 }; 10038c2ecf20Sopenharmony_cistatic const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 }; 10048c2ecf20Sopenharmony_cistatic const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 }; 10058c2ecf20Sopenharmony_cistatic const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 }; 10068c2ecf20Sopenharmony_cistatic const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 }; 10078c2ecf20Sopenharmony_cistatic const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; 10088c2ecf20Sopenharmony_cistatic const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 }; 10098c2ecf20Sopenharmony_cistatic const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 }; 10108c2ecf20Sopenharmony_cistatic const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; 10118c2ecf20Sopenharmony_cistatic const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 }; 10128c2ecf20Sopenharmony_cistatic const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 }; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci/* 10158c2ecf20Sopenharmony_ci * mt2063_set_dnc_output_enable() 10168c2ecf20Sopenharmony_ci */ 10178c2ecf20Sopenharmony_cistatic u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, 10188c2ecf20Sopenharmony_ci enum MT2063_DNC_Output_Enable *pValue) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci dprintk(2, "\n"); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */ 10238c2ecf20Sopenharmony_ci if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ 10248c2ecf20Sopenharmony_ci *pValue = MT2063_DNC_NONE; 10258c2ecf20Sopenharmony_ci else 10268c2ecf20Sopenharmony_ci *pValue = MT2063_DNC_2; 10278c2ecf20Sopenharmony_ci } else { /* DNC1 is on */ 10288c2ecf20Sopenharmony_ci if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ 10298c2ecf20Sopenharmony_ci *pValue = MT2063_DNC_1; 10308c2ecf20Sopenharmony_ci else 10318c2ecf20Sopenharmony_ci *pValue = MT2063_DNC_BOTH; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci return 0; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci/* 10378c2ecf20Sopenharmony_ci * mt2063_set_dnc_output_enable() 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_cistatic u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, 10408c2ecf20Sopenharmony_ci enum MT2063_DNC_Output_Enable nValue) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci int status = 0; /* Status to be returned */ 10438c2ecf20Sopenharmony_ci u8 val = 0; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci dprintk(2, "\n"); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* selects, which DNC output is used */ 10488c2ecf20Sopenharmony_ci switch (nValue) { 10498c2ecf20Sopenharmony_ci case MT2063_DNC_NONE: 10508c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ 10518c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_DNC_GAIN] != 10528c2ecf20Sopenharmony_ci val) 10538c2ecf20Sopenharmony_ci status |= 10548c2ecf20Sopenharmony_ci mt2063_setreg(state, 10558c2ecf20Sopenharmony_ci MT2063_REG_DNC_GAIN, 10568c2ecf20Sopenharmony_ci val); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ 10598c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_VGA_GAIN] != 10608c2ecf20Sopenharmony_ci val) 10618c2ecf20Sopenharmony_ci status |= 10628c2ecf20Sopenharmony_ci mt2063_setreg(state, 10638c2ecf20Sopenharmony_ci MT2063_REG_VGA_GAIN, 10648c2ecf20Sopenharmony_ci val); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ 10678c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_RSVD_20] != 10688c2ecf20Sopenharmony_ci val) 10698c2ecf20Sopenharmony_ci status |= 10708c2ecf20Sopenharmony_ci mt2063_setreg(state, 10718c2ecf20Sopenharmony_ci MT2063_REG_RSVD_20, 10728c2ecf20Sopenharmony_ci val); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci case MT2063_DNC_1: 10768c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ 10778c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_DNC_GAIN] != 10788c2ecf20Sopenharmony_ci val) 10798c2ecf20Sopenharmony_ci status |= 10808c2ecf20Sopenharmony_ci mt2063_setreg(state, 10818c2ecf20Sopenharmony_ci MT2063_REG_DNC_GAIN, 10828c2ecf20Sopenharmony_ci val); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ 10858c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_VGA_GAIN] != 10868c2ecf20Sopenharmony_ci val) 10878c2ecf20Sopenharmony_ci status |= 10888c2ecf20Sopenharmony_ci mt2063_setreg(state, 10898c2ecf20Sopenharmony_ci MT2063_REG_VGA_GAIN, 10908c2ecf20Sopenharmony_ci val); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ 10938c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_RSVD_20] != 10948c2ecf20Sopenharmony_ci val) 10958c2ecf20Sopenharmony_ci status |= 10968c2ecf20Sopenharmony_ci mt2063_setreg(state, 10978c2ecf20Sopenharmony_ci MT2063_REG_RSVD_20, 10988c2ecf20Sopenharmony_ci val); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci case MT2063_DNC_2: 11028c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ 11038c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_DNC_GAIN] != 11048c2ecf20Sopenharmony_ci val) 11058c2ecf20Sopenharmony_ci status |= 11068c2ecf20Sopenharmony_ci mt2063_setreg(state, 11078c2ecf20Sopenharmony_ci MT2063_REG_DNC_GAIN, 11088c2ecf20Sopenharmony_ci val); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ 11118c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_VGA_GAIN] != 11128c2ecf20Sopenharmony_ci val) 11138c2ecf20Sopenharmony_ci status |= 11148c2ecf20Sopenharmony_ci mt2063_setreg(state, 11158c2ecf20Sopenharmony_ci MT2063_REG_VGA_GAIN, 11168c2ecf20Sopenharmony_ci val); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ 11198c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_RSVD_20] != 11208c2ecf20Sopenharmony_ci val) 11218c2ecf20Sopenharmony_ci status |= 11228c2ecf20Sopenharmony_ci mt2063_setreg(state, 11238c2ecf20Sopenharmony_ci MT2063_REG_RSVD_20, 11248c2ecf20Sopenharmony_ci val); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci break; 11278c2ecf20Sopenharmony_ci case MT2063_DNC_BOTH: 11288c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ 11298c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_DNC_GAIN] != 11308c2ecf20Sopenharmony_ci val) 11318c2ecf20Sopenharmony_ci status |= 11328c2ecf20Sopenharmony_ci mt2063_setreg(state, 11338c2ecf20Sopenharmony_ci MT2063_REG_DNC_GAIN, 11348c2ecf20Sopenharmony_ci val); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ 11378c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_VGA_GAIN] != 11388c2ecf20Sopenharmony_ci val) 11398c2ecf20Sopenharmony_ci status |= 11408c2ecf20Sopenharmony_ci mt2063_setreg(state, 11418c2ecf20Sopenharmony_ci MT2063_REG_VGA_GAIN, 11428c2ecf20Sopenharmony_ci val); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ 11458c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_RSVD_20] != 11468c2ecf20Sopenharmony_ci val) 11478c2ecf20Sopenharmony_ci status |= 11488c2ecf20Sopenharmony_ci mt2063_setreg(state, 11498c2ecf20Sopenharmony_ci MT2063_REG_RSVD_20, 11508c2ecf20Sopenharmony_ci val); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci default: 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci return status; 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci/* 11618c2ecf20Sopenharmony_ci * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with 11628c2ecf20Sopenharmony_ci * the selected enum mt2063_delivery_sys type. 11638c2ecf20Sopenharmony_ci * 11648c2ecf20Sopenharmony_ci * (DNC1GC & DNC2GC are the values, which are used, when the specific 11658c2ecf20Sopenharmony_ci * DNC Output is selected, the other is always off) 11668c2ecf20Sopenharmony_ci * 11678c2ecf20Sopenharmony_ci * @state: ptr to mt2063_state structure 11688c2ecf20Sopenharmony_ci * @Mode: desired receiver delivery system 11698c2ecf20Sopenharmony_ci * 11708c2ecf20Sopenharmony_ci * Note: Register cache must be valid for it to work 11718c2ecf20Sopenharmony_ci */ 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cistatic u32 MT2063_SetReceiverMode(struct mt2063_state *state, 11748c2ecf20Sopenharmony_ci enum mt2063_delivery_sys Mode) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci int status = 0; /* Status to be returned */ 11778c2ecf20Sopenharmony_ci u8 val; 11788c2ecf20Sopenharmony_ci u32 longval; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci dprintk(2, "\n"); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (Mode >= MT2063_NUM_RCVR_MODES) 11838c2ecf20Sopenharmony_ci status = -ERANGE; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* RFAGCen */ 11868c2ecf20Sopenharmony_ci if (status >= 0) { 11878c2ecf20Sopenharmony_ci val = 11888c2ecf20Sopenharmony_ci (state-> 11898c2ecf20Sopenharmony_ci reg[MT2063_REG_PD1_TGT] & ~0x40) | (RFAGCEN[Mode] 11908c2ecf20Sopenharmony_ci ? 0x40 : 11918c2ecf20Sopenharmony_ci 0x00); 11928c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_PD1_TGT] != val) 11938c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* LNARin */ 11978c2ecf20Sopenharmony_ci if (status >= 0) { 11988c2ecf20Sopenharmony_ci u8 val = (state->reg[MT2063_REG_CTRL_2C] & ~0x03) | 11998c2ecf20Sopenharmony_ci (LNARIN[Mode] & 0x03); 12008c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_CTRL_2C] != val) 12018c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* FIFFQEN and FIFFQ */ 12058c2ecf20Sopenharmony_ci if (status >= 0) { 12068c2ecf20Sopenharmony_ci val = 12078c2ecf20Sopenharmony_ci (state-> 12088c2ecf20Sopenharmony_ci reg[MT2063_REG_FIFF_CTRL2] & ~0xF0) | 12098c2ecf20Sopenharmony_ci (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); 12108c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { 12118c2ecf20Sopenharmony_ci status |= 12128c2ecf20Sopenharmony_ci mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); 12138c2ecf20Sopenharmony_ci /* trigger FIFF calibration, needed after changing FIFFQ */ 12148c2ecf20Sopenharmony_ci val = 12158c2ecf20Sopenharmony_ci (state->reg[MT2063_REG_FIFF_CTRL] | 0x01); 12168c2ecf20Sopenharmony_ci status |= 12178c2ecf20Sopenharmony_ci mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); 12188c2ecf20Sopenharmony_ci val = 12198c2ecf20Sopenharmony_ci (state-> 12208c2ecf20Sopenharmony_ci reg[MT2063_REG_FIFF_CTRL] & ~0x01); 12218c2ecf20Sopenharmony_ci status |= 12228c2ecf20Sopenharmony_ci mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* DNC1GC & DNC2GC */ 12278c2ecf20Sopenharmony_ci status |= mt2063_get_dnc_output_enable(state, &longval); 12288c2ecf20Sopenharmony_ci status |= mt2063_set_dnc_output_enable(state, longval); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* acLNAmax */ 12318c2ecf20Sopenharmony_ci if (status >= 0) { 12328c2ecf20Sopenharmony_ci u8 val = (state->reg[MT2063_REG_LNA_OV] & ~0x1F) | 12338c2ecf20Sopenharmony_ci (ACLNAMAX[Mode] & 0x1F); 12348c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_LNA_OV] != val) 12358c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* LNATGT */ 12398c2ecf20Sopenharmony_ci if (status >= 0) { 12408c2ecf20Sopenharmony_ci u8 val = (state->reg[MT2063_REG_LNA_TGT] & ~0x3F) | 12418c2ecf20Sopenharmony_ci (LNATGT[Mode] & 0x3F); 12428c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_LNA_TGT] != val) 12438c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* ACRF */ 12478c2ecf20Sopenharmony_ci if (status >= 0) { 12488c2ecf20Sopenharmony_ci u8 val = (state->reg[MT2063_REG_RF_OV] & ~0x1F) | 12498c2ecf20Sopenharmony_ci (ACRFMAX[Mode] & 0x1F); 12508c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_RF_OV] != val) 12518c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci /* PD1TGT */ 12558c2ecf20Sopenharmony_ci if (status >= 0) { 12568c2ecf20Sopenharmony_ci u8 val = (state->reg[MT2063_REG_PD1_TGT] & ~0x3F) | 12578c2ecf20Sopenharmony_ci (PD1TGT[Mode] & 0x3F); 12588c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_PD1_TGT] != val) 12598c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci /* FIFATN */ 12638c2ecf20Sopenharmony_ci if (status >= 0) { 12648c2ecf20Sopenharmony_ci u8 val = ACFIFMAX[Mode]; 12658c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) 12668c2ecf20Sopenharmony_ci val = 5; 12678c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_FIF_OV] & ~0x1F) | 12688c2ecf20Sopenharmony_ci (val & 0x1F); 12698c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_FIF_OV] != val) 12708c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* PD2TGT */ 12748c2ecf20Sopenharmony_ci if (status >= 0) { 12758c2ecf20Sopenharmony_ci u8 val = (state->reg[MT2063_REG_PD2_TGT] & ~0x3F) | 12768c2ecf20Sopenharmony_ci (PD2TGT[Mode] & 0x3F); 12778c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_PD2_TGT] != val) 12788c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Ignore ATN Overload */ 12828c2ecf20Sopenharmony_ci if (status >= 0) { 12838c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_LNA_TGT] & ~0x80) | 12848c2ecf20Sopenharmony_ci (RFOVDIS[Mode] ? 0x80 : 0x00); 12858c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_LNA_TGT] != val) 12868c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* Ignore FIF Overload */ 12908c2ecf20Sopenharmony_ci if (status >= 0) { 12918c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_PD1_TGT] & ~0x80) | 12928c2ecf20Sopenharmony_ci (FIFOVDIS[Mode] ? 0x80 : 0x00); 12938c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_PD1_TGT] != val) 12948c2ecf20Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (status >= 0) { 12988c2ecf20Sopenharmony_ci state->rcvr_mode = Mode; 12998c2ecf20Sopenharmony_ci dprintk(1, "mt2063 mode changed to %s\n", 13008c2ecf20Sopenharmony_ci mt2063_mode_name[state->rcvr_mode]); 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci return status; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci/* 13078c2ecf20Sopenharmony_ci * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various 13088c2ecf20Sopenharmony_ci * sections of the MT2063 13098c2ecf20Sopenharmony_ci * 13108c2ecf20Sopenharmony_ci * @Bits: Mask bits to be cleared. 13118c2ecf20Sopenharmony_ci * 13128c2ecf20Sopenharmony_ci * See definition of MT2063_Mask_Bits type for description 13138c2ecf20Sopenharmony_ci * of each of the power bits. 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_cistatic u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, 13168c2ecf20Sopenharmony_ci enum MT2063_Mask_Bits Bits) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci int status = 0; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci dprintk(2, "\n"); 13218c2ecf20Sopenharmony_ci Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ 13228c2ecf20Sopenharmony_ci if ((Bits & 0xFF00) != 0) { 13238c2ecf20Sopenharmony_ci state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8); 13248c2ecf20Sopenharmony_ci status |= 13258c2ecf20Sopenharmony_ci mt2063_write(state, 13268c2ecf20Sopenharmony_ci MT2063_REG_PWR_2, 13278c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_PWR_2], 1); 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci if ((Bits & 0xFF) != 0) { 13308c2ecf20Sopenharmony_ci state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF); 13318c2ecf20Sopenharmony_ci status |= 13328c2ecf20Sopenharmony_ci mt2063_write(state, 13338c2ecf20Sopenharmony_ci MT2063_REG_PWR_1, 13348c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_PWR_1], 1); 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci return status; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci/* 13418c2ecf20Sopenharmony_ci * MT2063_SoftwareShutdown() - Enables or disables software shutdown function. 13428c2ecf20Sopenharmony_ci * When Shutdown is 1, any section whose power 13438c2ecf20Sopenharmony_ci * mask is set will be shutdown. 13448c2ecf20Sopenharmony_ci */ 13458c2ecf20Sopenharmony_cistatic u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci int status; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci dprintk(2, "\n"); 13508c2ecf20Sopenharmony_ci if (Shutdown == 1) 13518c2ecf20Sopenharmony_ci state->reg[MT2063_REG_PWR_1] |= 0x04; 13528c2ecf20Sopenharmony_ci else 13538c2ecf20Sopenharmony_ci state->reg[MT2063_REG_PWR_1] &= ~0x04; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci status = mt2063_write(state, 13568c2ecf20Sopenharmony_ci MT2063_REG_PWR_1, 13578c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_PWR_1], 1); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci if (Shutdown != 1) { 13608c2ecf20Sopenharmony_ci state->reg[MT2063_REG_BYP_CTRL] = 13618c2ecf20Sopenharmony_ci (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40; 13628c2ecf20Sopenharmony_ci status |= 13638c2ecf20Sopenharmony_ci mt2063_write(state, 13648c2ecf20Sopenharmony_ci MT2063_REG_BYP_CTRL, 13658c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_BYP_CTRL], 13668c2ecf20Sopenharmony_ci 1); 13678c2ecf20Sopenharmony_ci state->reg[MT2063_REG_BYP_CTRL] = 13688c2ecf20Sopenharmony_ci (state->reg[MT2063_REG_BYP_CTRL] & 0x9F); 13698c2ecf20Sopenharmony_ci status |= 13708c2ecf20Sopenharmony_ci mt2063_write(state, 13718c2ecf20Sopenharmony_ci MT2063_REG_BYP_CTRL, 13728c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_BYP_CTRL], 13738c2ecf20Sopenharmony_ci 1); 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci return status; 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_cistatic u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci return f_ref * (f_LO / f_ref) 13828c2ecf20Sopenharmony_ci + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step); 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/** 13868c2ecf20Sopenharmony_ci * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom. 13878c2ecf20Sopenharmony_ci * This function preserves maximum precision without 13888c2ecf20Sopenharmony_ci * risk of overflow. It accurately calculates 13898c2ecf20Sopenharmony_ci * f_ref * num / denom to within 1 HZ with fixed math. 13908c2ecf20Sopenharmony_ci * 13918c2ecf20Sopenharmony_ci * @f_ref: SRO frequency. 13928c2ecf20Sopenharmony_ci * @num: Fractional portion of the multiplier 13938c2ecf20Sopenharmony_ci * @denom: denominator portion of the ratio 13948c2ecf20Sopenharmony_ci * 13958c2ecf20Sopenharmony_ci * This calculation handles f_ref as two separate 14-bit fields. 13968c2ecf20Sopenharmony_ci * Therefore, a maximum value of 2^28-1 may safely be used for f_ref. 13978c2ecf20Sopenharmony_ci * This is the genesis of the magic number "14" and the magic mask value of 13988c2ecf20Sopenharmony_ci * 0x03FFF. 13998c2ecf20Sopenharmony_ci * 14008c2ecf20Sopenharmony_ci * This routine successfully handles denom values up to and including 2^18. 14018c2ecf20Sopenharmony_ci * Returns: f_ref * num / denom 14028c2ecf20Sopenharmony_ci */ 14038c2ecf20Sopenharmony_cistatic u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci u32 t1 = (f_ref >> 14) * num; 14068c2ecf20Sopenharmony_ci u32 term1 = t1 / denom; 14078c2ecf20Sopenharmony_ci u32 loss = t1 % denom; 14088c2ecf20Sopenharmony_ci u32 term2 = 14098c2ecf20Sopenharmony_ci (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom; 14108c2ecf20Sopenharmony_ci return (term1 << 14) + term2; 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci/* 14148c2ecf20Sopenharmony_ci * CalcLO1Mult()- Calculates Integer divider value and the numerator 14158c2ecf20Sopenharmony_ci * value for a FracN PLL. 14168c2ecf20Sopenharmony_ci * 14178c2ecf20Sopenharmony_ci * This function assumes that the f_LO and f_Ref are 14188c2ecf20Sopenharmony_ci * evenly divisible by f_LO_Step. 14198c2ecf20Sopenharmony_ci * 14208c2ecf20Sopenharmony_ci * @Div: OUTPUT: Whole number portion of the multiplier 14218c2ecf20Sopenharmony_ci * @FracN: OUTPUT: Fractional portion of the multiplier 14228c2ecf20Sopenharmony_ci * @f_LO: desired LO frequency. 14238c2ecf20Sopenharmony_ci * @f_LO_Step: Minimum step size for the LO (in Hz). 14248c2ecf20Sopenharmony_ci * @f_Ref: SRO frequency. 14258c2ecf20Sopenharmony_ci * @f_Avoid: Range of PLL frequencies to avoid near integer multiples 14268c2ecf20Sopenharmony_ci * of f_Ref (in Hz). 14278c2ecf20Sopenharmony_ci * 14288c2ecf20Sopenharmony_ci * Returns: Recalculated LO frequency. 14298c2ecf20Sopenharmony_ci */ 14308c2ecf20Sopenharmony_cistatic u32 MT2063_CalcLO1Mult(u32 *Div, 14318c2ecf20Sopenharmony_ci u32 *FracN, 14328c2ecf20Sopenharmony_ci u32 f_LO, 14338c2ecf20Sopenharmony_ci u32 f_LO_Step, u32 f_Ref) 14348c2ecf20Sopenharmony_ci{ 14358c2ecf20Sopenharmony_ci /* Calculate the whole number portion of the divider */ 14368c2ecf20Sopenharmony_ci *Div = f_LO / f_Ref; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci /* Calculate the numerator value (round to nearest f_LO_Step) */ 14398c2ecf20Sopenharmony_ci *FracN = 14408c2ecf20Sopenharmony_ci (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + 14418c2ecf20Sopenharmony_ci (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64); 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci/** 14478c2ecf20Sopenharmony_ci * CalcLO2Mult() - Calculates Integer divider value and the numerator 14488c2ecf20Sopenharmony_ci * value for a FracN PLL. 14498c2ecf20Sopenharmony_ci * 14508c2ecf20Sopenharmony_ci * This function assumes that the f_LO and f_Ref are 14518c2ecf20Sopenharmony_ci * evenly divisible by f_LO_Step. 14528c2ecf20Sopenharmony_ci * 14538c2ecf20Sopenharmony_ci * @Div: OUTPUT: Whole number portion of the multiplier 14548c2ecf20Sopenharmony_ci * @FracN: OUTPUT: Fractional portion of the multiplier 14558c2ecf20Sopenharmony_ci * @f_LO: desired LO frequency. 14568c2ecf20Sopenharmony_ci * @f_LO_Step: Minimum step size for the LO (in Hz). 14578c2ecf20Sopenharmony_ci * @f_Ref: SRO frequency. 14588c2ecf20Sopenharmony_ci * 14598c2ecf20Sopenharmony_ci * Returns: Recalculated LO frequency. 14608c2ecf20Sopenharmony_ci */ 14618c2ecf20Sopenharmony_cistatic u32 MT2063_CalcLO2Mult(u32 *Div, 14628c2ecf20Sopenharmony_ci u32 *FracN, 14638c2ecf20Sopenharmony_ci u32 f_LO, 14648c2ecf20Sopenharmony_ci u32 f_LO_Step, u32 f_Ref) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci /* Calculate the whole number portion of the divider */ 14678c2ecf20Sopenharmony_ci *Div = f_LO / f_Ref; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci /* Calculate the numerator value (round to nearest f_LO_Step) */ 14708c2ecf20Sopenharmony_ci *FracN = 14718c2ecf20Sopenharmony_ci (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + 14728c2ecf20Sopenharmony_ci (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 14758c2ecf20Sopenharmony_ci 8191); 14768c2ecf20Sopenharmony_ci} 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci/* 14798c2ecf20Sopenharmony_ci * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be 14808c2ecf20Sopenharmony_ci * used for a given input frequency. 14818c2ecf20Sopenharmony_ci * 14828c2ecf20Sopenharmony_ci * @state: ptr to tuner data structure 14838c2ecf20Sopenharmony_ci * @f_in: RF input center frequency (in Hz). 14848c2ecf20Sopenharmony_ci * 14858c2ecf20Sopenharmony_ci * Returns: ClearTune filter number (0-31) 14868c2ecf20Sopenharmony_ci */ 14878c2ecf20Sopenharmony_cistatic u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci u32 RFBand; 14908c2ecf20Sopenharmony_ci u32 idx; /* index loop */ 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* 14938c2ecf20Sopenharmony_ci ** Find RF Band setting 14948c2ecf20Sopenharmony_ci */ 14958c2ecf20Sopenharmony_ci RFBand = 31; /* def when f_in > all */ 14968c2ecf20Sopenharmony_ci for (idx = 0; idx < 31; ++idx) { 14978c2ecf20Sopenharmony_ci if (state->CTFiltMax[idx] >= f_in) { 14988c2ecf20Sopenharmony_ci RFBand = idx; 14998c2ecf20Sopenharmony_ci break; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci return RFBand; 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci/* 15068c2ecf20Sopenharmony_ci * MT2063_Tune() - Change the tuner's tuned frequency to RFin. 15078c2ecf20Sopenharmony_ci */ 15088c2ecf20Sopenharmony_cistatic u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) 15098c2ecf20Sopenharmony_ci{ /* RF input center frequency */ 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci int status = 0; 15128c2ecf20Sopenharmony_ci u32 LO1; /* 1st LO register value */ 15138c2ecf20Sopenharmony_ci u32 Num1; /* Numerator for LO1 reg. value */ 15148c2ecf20Sopenharmony_ci u32 f_IF1; /* 1st IF requested */ 15158c2ecf20Sopenharmony_ci u32 LO2; /* 2nd LO register value */ 15168c2ecf20Sopenharmony_ci u32 Num2; /* Numerator for LO2 reg. value */ 15178c2ecf20Sopenharmony_ci u32 ofLO1, ofLO2; /* last time's LO frequencies */ 15188c2ecf20Sopenharmony_ci u8 fiffc = 0x80; /* FIFF center freq from tuner */ 15198c2ecf20Sopenharmony_ci u32 fiffof; /* Offset from FIFF center freq */ 15208c2ecf20Sopenharmony_ci const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */ 15218c2ecf20Sopenharmony_ci u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */ 15228c2ecf20Sopenharmony_ci u8 val; 15238c2ecf20Sopenharmony_ci u32 RFBand; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci dprintk(2, "\n"); 15268c2ecf20Sopenharmony_ci /* Check the input and output frequency ranges */ 15278c2ecf20Sopenharmony_ci if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ)) 15288c2ecf20Sopenharmony_ci return -EINVAL; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ) 15318c2ecf20Sopenharmony_ci || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ)) 15328c2ecf20Sopenharmony_ci return -EINVAL; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* 15358c2ecf20Sopenharmony_ci * Save original LO1 and LO2 register values 15368c2ecf20Sopenharmony_ci */ 15378c2ecf20Sopenharmony_ci ofLO1 = state->AS_Data.f_LO1; 15388c2ecf20Sopenharmony_ci ofLO2 = state->AS_Data.f_LO2; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci /* 15418c2ecf20Sopenharmony_ci * Find and set RF Band setting 15428c2ecf20Sopenharmony_ci */ 15438c2ecf20Sopenharmony_ci if (state->ctfilt_sw == 1) { 15448c2ecf20Sopenharmony_ci val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08); 15458c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_CTUNE_CTRL] != val) { 15468c2ecf20Sopenharmony_ci status |= 15478c2ecf20Sopenharmony_ci mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val); 15488c2ecf20Sopenharmony_ci } 15498c2ecf20Sopenharmony_ci val = state->reg[MT2063_REG_CTUNE_OV]; 15508c2ecf20Sopenharmony_ci RFBand = FindClearTuneFilter(state, f_in); 15518c2ecf20Sopenharmony_ci state->reg[MT2063_REG_CTUNE_OV] = 15528c2ecf20Sopenharmony_ci (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F) 15538c2ecf20Sopenharmony_ci | RFBand); 15548c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_CTUNE_OV] != val) { 15558c2ecf20Sopenharmony_ci status |= 15568c2ecf20Sopenharmony_ci mt2063_setreg(state, MT2063_REG_CTUNE_OV, val); 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci /* 15618c2ecf20Sopenharmony_ci * Read the FIFF Center Frequency from the tuner 15628c2ecf20Sopenharmony_ci */ 15638c2ecf20Sopenharmony_ci if (status >= 0) { 15648c2ecf20Sopenharmony_ci status |= 15658c2ecf20Sopenharmony_ci mt2063_read(state, 15668c2ecf20Sopenharmony_ci MT2063_REG_FIFFC, 15678c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_FIFFC], 1); 15688c2ecf20Sopenharmony_ci fiffc = state->reg[MT2063_REG_FIFFC]; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci /* 15718c2ecf20Sopenharmony_ci * Assign in the requested values 15728c2ecf20Sopenharmony_ci */ 15738c2ecf20Sopenharmony_ci state->AS_Data.f_in = f_in; 15748c2ecf20Sopenharmony_ci /* Request a 1st IF such that LO1 is on a step size */ 15758c2ecf20Sopenharmony_ci state->AS_Data.f_if1_Request = 15768c2ecf20Sopenharmony_ci MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in, 15778c2ecf20Sopenharmony_ci state->AS_Data.f_LO1_Step, 15788c2ecf20Sopenharmony_ci state->AS_Data.f_ref) - f_in; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* 15818c2ecf20Sopenharmony_ci * Calculate frequency settings. f_IF1_FREQ + f_in is the 15828c2ecf20Sopenharmony_ci * desired LO1 frequency 15838c2ecf20Sopenharmony_ci */ 15848c2ecf20Sopenharmony_ci MT2063_ResetExclZones(&state->AS_Data); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci state->AS_Data.f_LO1 = 15898c2ecf20Sopenharmony_ci MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step, 15908c2ecf20Sopenharmony_ci state->AS_Data.f_ref); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci state->AS_Data.f_LO2 = 15938c2ecf20Sopenharmony_ci MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, 15948c2ecf20Sopenharmony_ci state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* 15978c2ecf20Sopenharmony_ci * Check for any LO spurs in the output bandwidth and adjust 15988c2ecf20Sopenharmony_ci * the LO settings to avoid them if needed 15998c2ecf20Sopenharmony_ci */ 16008c2ecf20Sopenharmony_ci status |= MT2063_AvoidSpurs(&state->AS_Data); 16018c2ecf20Sopenharmony_ci /* 16028c2ecf20Sopenharmony_ci * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values. 16038c2ecf20Sopenharmony_ci * Recalculate the LO frequencies and the values to be placed 16048c2ecf20Sopenharmony_ci * in the tuning registers. 16058c2ecf20Sopenharmony_ci */ 16068c2ecf20Sopenharmony_ci state->AS_Data.f_LO1 = 16078c2ecf20Sopenharmony_ci MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1, 16088c2ecf20Sopenharmony_ci state->AS_Data.f_LO1_Step, state->AS_Data.f_ref); 16098c2ecf20Sopenharmony_ci state->AS_Data.f_LO2 = 16108c2ecf20Sopenharmony_ci MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, 16118c2ecf20Sopenharmony_ci state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); 16128c2ecf20Sopenharmony_ci state->AS_Data.f_LO2 = 16138c2ecf20Sopenharmony_ci MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2, 16148c2ecf20Sopenharmony_ci state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci /* 16178c2ecf20Sopenharmony_ci * Check the upconverter and downconverter frequency ranges 16188c2ecf20Sopenharmony_ci */ 16198c2ecf20Sopenharmony_ci if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ) 16208c2ecf20Sopenharmony_ci || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ)) 16218c2ecf20Sopenharmony_ci status |= MT2063_UPC_RANGE; 16228c2ecf20Sopenharmony_ci if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ) 16238c2ecf20Sopenharmony_ci || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ)) 16248c2ecf20Sopenharmony_ci status |= MT2063_DNC_RANGE; 16258c2ecf20Sopenharmony_ci /* LO2 Lock bit was in a different place for B0 version */ 16268c2ecf20Sopenharmony_ci if (state->tuner_id == MT2063_B0) 16278c2ecf20Sopenharmony_ci LO2LK = 0x40; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci /* 16308c2ecf20Sopenharmony_ci * If we have the same LO frequencies and we're already locked, 16318c2ecf20Sopenharmony_ci * then skip re-programming the LO registers. 16328c2ecf20Sopenharmony_ci */ 16338c2ecf20Sopenharmony_ci if ((ofLO1 != state->AS_Data.f_LO1) 16348c2ecf20Sopenharmony_ci || (ofLO2 != state->AS_Data.f_LO2) 16358c2ecf20Sopenharmony_ci || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) != 16368c2ecf20Sopenharmony_ci (LO1LK | LO2LK))) { 16378c2ecf20Sopenharmony_ci /* 16388c2ecf20Sopenharmony_ci * Calculate the FIFFOF register value 16398c2ecf20Sopenharmony_ci * 16408c2ecf20Sopenharmony_ci * IF1_Actual 16418c2ecf20Sopenharmony_ci * FIFFOF = ------------ - 8 * FIFFC - 4992 16428c2ecf20Sopenharmony_ci * f_ref/64 16438c2ecf20Sopenharmony_ci */ 16448c2ecf20Sopenharmony_ci fiffof = 16458c2ecf20Sopenharmony_ci (state->AS_Data.f_LO1 - 16468c2ecf20Sopenharmony_ci f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc - 16478c2ecf20Sopenharmony_ci 4992; 16488c2ecf20Sopenharmony_ci if (fiffof > 0xFF) 16498c2ecf20Sopenharmony_ci fiffof = 0xFF; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci /* 16528c2ecf20Sopenharmony_ci * Place all of the calculated values into the local tuner 16538c2ecf20Sopenharmony_ci * register fields. 16548c2ecf20Sopenharmony_ci */ 16558c2ecf20Sopenharmony_ci if (status >= 0) { 16568c2ecf20Sopenharmony_ci state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */ 16578c2ecf20Sopenharmony_ci state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */ 16588c2ecf20Sopenharmony_ci state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */ 16598c2ecf20Sopenharmony_ci |(Num2 >> 12)); /* NUM2q (hi) */ 16608c2ecf20Sopenharmony_ci state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */ 16618c2ecf20Sopenharmony_ci state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */ 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci /* 16648c2ecf20Sopenharmony_ci * Now write out the computed register values 16658c2ecf20Sopenharmony_ci * IMPORTANT: There is a required order for writing 16668c2ecf20Sopenharmony_ci * (0x05 must follow all the others). 16678c2ecf20Sopenharmony_ci */ 16688c2ecf20Sopenharmony_ci status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */ 16698c2ecf20Sopenharmony_ci if (state->tuner_id == MT2063_B0) { 16708c2ecf20Sopenharmony_ci /* Re-write the one-shot bits to trigger the tune operation */ 16718c2ecf20Sopenharmony_ci status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */ 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci /* Write out the FIFF offset only if it's changing */ 16748c2ecf20Sopenharmony_ci if (state->reg[MT2063_REG_FIFF_OFFSET] != 16758c2ecf20Sopenharmony_ci (u8) fiffof) { 16768c2ecf20Sopenharmony_ci state->reg[MT2063_REG_FIFF_OFFSET] = 16778c2ecf20Sopenharmony_ci (u8) fiffof; 16788c2ecf20Sopenharmony_ci status |= 16798c2ecf20Sopenharmony_ci mt2063_write(state, 16808c2ecf20Sopenharmony_ci MT2063_REG_FIFF_OFFSET, 16818c2ecf20Sopenharmony_ci &state-> 16828c2ecf20Sopenharmony_ci reg[MT2063_REG_FIFF_OFFSET], 16838c2ecf20Sopenharmony_ci 1); 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci /* 16888c2ecf20Sopenharmony_ci * Check for LO's locking 16898c2ecf20Sopenharmony_ci */ 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (status < 0) 16928c2ecf20Sopenharmony_ci return status; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci status = mt2063_lockStatus(state); 16958c2ecf20Sopenharmony_ci if (status < 0) 16968c2ecf20Sopenharmony_ci return status; 16978c2ecf20Sopenharmony_ci if (!status) 16988c2ecf20Sopenharmony_ci return -EINVAL; /* Couldn't lock */ 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci /* 17018c2ecf20Sopenharmony_ci * If we locked OK, assign calculated data to mt2063_state structure 17028c2ecf20Sopenharmony_ci */ 17038c2ecf20Sopenharmony_ci state->f_IF1_actual = state->AS_Data.f_LO1 - f_in; 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci return status; 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_cistatic const u8 MT2063B0_defaults[] = { 17108c2ecf20Sopenharmony_ci /* Reg, Value */ 17118c2ecf20Sopenharmony_ci 0x19, 0x05, 17128c2ecf20Sopenharmony_ci 0x1B, 0x1D, 17138c2ecf20Sopenharmony_ci 0x1C, 0x1F, 17148c2ecf20Sopenharmony_ci 0x1D, 0x0F, 17158c2ecf20Sopenharmony_ci 0x1E, 0x3F, 17168c2ecf20Sopenharmony_ci 0x1F, 0x0F, 17178c2ecf20Sopenharmony_ci 0x20, 0x3F, 17188c2ecf20Sopenharmony_ci 0x22, 0x21, 17198c2ecf20Sopenharmony_ci 0x23, 0x3F, 17208c2ecf20Sopenharmony_ci 0x24, 0x20, 17218c2ecf20Sopenharmony_ci 0x25, 0x3F, 17228c2ecf20Sopenharmony_ci 0x27, 0xEE, 17238c2ecf20Sopenharmony_ci 0x2C, 0x27, /* bit at 0x20 is cleared below */ 17248c2ecf20Sopenharmony_ci 0x30, 0x03, 17258c2ecf20Sopenharmony_ci 0x2C, 0x07, /* bit at 0x20 is cleared here */ 17268c2ecf20Sopenharmony_ci 0x2D, 0x87, 17278c2ecf20Sopenharmony_ci 0x2E, 0xAA, 17288c2ecf20Sopenharmony_ci 0x28, 0xE1, /* Set the FIFCrst bit here */ 17298c2ecf20Sopenharmony_ci 0x28, 0xE0, /* Clear the FIFCrst bit here */ 17308c2ecf20Sopenharmony_ci 0x00 17318c2ecf20Sopenharmony_ci}; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ 17348c2ecf20Sopenharmony_cistatic const u8 MT2063B1_defaults[] = { 17358c2ecf20Sopenharmony_ci /* Reg, Value */ 17368c2ecf20Sopenharmony_ci 0x05, 0xF0, 17378c2ecf20Sopenharmony_ci 0x11, 0x10, /* New Enable AFCsd */ 17388c2ecf20Sopenharmony_ci 0x19, 0x05, 17398c2ecf20Sopenharmony_ci 0x1A, 0x6C, 17408c2ecf20Sopenharmony_ci 0x1B, 0x24, 17418c2ecf20Sopenharmony_ci 0x1C, 0x28, 17428c2ecf20Sopenharmony_ci 0x1D, 0x8F, 17438c2ecf20Sopenharmony_ci 0x1E, 0x14, 17448c2ecf20Sopenharmony_ci 0x1F, 0x8F, 17458c2ecf20Sopenharmony_ci 0x20, 0x57, 17468c2ecf20Sopenharmony_ci 0x22, 0x21, /* New - ver 1.03 */ 17478c2ecf20Sopenharmony_ci 0x23, 0x3C, /* New - ver 1.10 */ 17488c2ecf20Sopenharmony_ci 0x24, 0x20, /* New - ver 1.03 */ 17498c2ecf20Sopenharmony_ci 0x2C, 0x24, /* bit at 0x20 is cleared below */ 17508c2ecf20Sopenharmony_ci 0x2D, 0x87, /* FIFFQ=0 */ 17518c2ecf20Sopenharmony_ci 0x2F, 0xF3, 17528c2ecf20Sopenharmony_ci 0x30, 0x0C, /* New - ver 1.11 */ 17538c2ecf20Sopenharmony_ci 0x31, 0x1B, /* New - ver 1.11 */ 17548c2ecf20Sopenharmony_ci 0x2C, 0x04, /* bit at 0x20 is cleared here */ 17558c2ecf20Sopenharmony_ci 0x28, 0xE1, /* Set the FIFCrst bit here */ 17568c2ecf20Sopenharmony_ci 0x28, 0xE0, /* Clear the FIFCrst bit here */ 17578c2ecf20Sopenharmony_ci 0x00 17588c2ecf20Sopenharmony_ci}; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ 17618c2ecf20Sopenharmony_cistatic const u8 MT2063B3_defaults[] = { 17628c2ecf20Sopenharmony_ci /* Reg, Value */ 17638c2ecf20Sopenharmony_ci 0x05, 0xF0, 17648c2ecf20Sopenharmony_ci 0x19, 0x3D, 17658c2ecf20Sopenharmony_ci 0x2C, 0x24, /* bit at 0x20 is cleared below */ 17668c2ecf20Sopenharmony_ci 0x2C, 0x04, /* bit at 0x20 is cleared here */ 17678c2ecf20Sopenharmony_ci 0x28, 0xE1, /* Set the FIFCrst bit here */ 17688c2ecf20Sopenharmony_ci 0x28, 0xE0, /* Clear the FIFCrst bit here */ 17698c2ecf20Sopenharmony_ci 0x00 17708c2ecf20Sopenharmony_ci}; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_cistatic int mt2063_init(struct dvb_frontend *fe) 17738c2ecf20Sopenharmony_ci{ 17748c2ecf20Sopenharmony_ci int status; 17758c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 17768c2ecf20Sopenharmony_ci u8 all_resets = 0xF0; /* reset/load bits */ 17778c2ecf20Sopenharmony_ci const u8 *def = NULL; 17788c2ecf20Sopenharmony_ci char *step; 17798c2ecf20Sopenharmony_ci u32 FCRUN; 17808c2ecf20Sopenharmony_ci s32 maxReads; 17818c2ecf20Sopenharmony_ci u32 fcu_osc; 17828c2ecf20Sopenharmony_ci u32 i; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci dprintk(2, "\n"); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci state->rcvr_mode = MT2063_CABLE_QAM; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci /* Read the Part/Rev code from the tuner */ 17898c2ecf20Sopenharmony_ci status = mt2063_read(state, MT2063_REG_PART_REV, 17908c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_PART_REV], 1); 17918c2ecf20Sopenharmony_ci if (status < 0) { 17928c2ecf20Sopenharmony_ci printk(KERN_ERR "Can't read mt2063 part ID\n"); 17938c2ecf20Sopenharmony_ci return status; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci /* Check the part/rev code */ 17978c2ecf20Sopenharmony_ci switch (state->reg[MT2063_REG_PART_REV]) { 17988c2ecf20Sopenharmony_ci case MT2063_B0: 17998c2ecf20Sopenharmony_ci step = "B0"; 18008c2ecf20Sopenharmony_ci break; 18018c2ecf20Sopenharmony_ci case MT2063_B1: 18028c2ecf20Sopenharmony_ci step = "B1"; 18038c2ecf20Sopenharmony_ci break; 18048c2ecf20Sopenharmony_ci case MT2063_B2: 18058c2ecf20Sopenharmony_ci step = "B2"; 18068c2ecf20Sopenharmony_ci break; 18078c2ecf20Sopenharmony_ci case MT2063_B3: 18088c2ecf20Sopenharmony_ci step = "B3"; 18098c2ecf20Sopenharmony_ci break; 18108c2ecf20Sopenharmony_ci default: 18118c2ecf20Sopenharmony_ci printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n", 18128c2ecf20Sopenharmony_ci state->reg[MT2063_REG_PART_REV]); 18138c2ecf20Sopenharmony_ci return -ENODEV; /* Wrong tuner Part/Rev code */ 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* Check the 2nd byte of the Part/Rev code from the tuner */ 18178c2ecf20Sopenharmony_ci status = mt2063_read(state, MT2063_REG_RSVD_3B, 18188c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_RSVD_3B], 1); 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci /* b7 != 0 ==> NOT MT2063 */ 18218c2ecf20Sopenharmony_ci if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) { 18228c2ecf20Sopenharmony_ci printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n", 18238c2ecf20Sopenharmony_ci state->reg[MT2063_REG_PART_REV], 18248c2ecf20Sopenharmony_ci state->reg[MT2063_REG_RSVD_3B]); 18258c2ecf20Sopenharmony_ci return -ENODEV; /* Wrong tuner Part/Rev code */ 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci /* Reset the tuner */ 18318c2ecf20Sopenharmony_ci status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1); 18328c2ecf20Sopenharmony_ci if (status < 0) 18338c2ecf20Sopenharmony_ci return status; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci /* change all of the default values that vary from the HW reset values */ 18368c2ecf20Sopenharmony_ci /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */ 18378c2ecf20Sopenharmony_ci switch (state->reg[MT2063_REG_PART_REV]) { 18388c2ecf20Sopenharmony_ci case MT2063_B3: 18398c2ecf20Sopenharmony_ci def = MT2063B3_defaults; 18408c2ecf20Sopenharmony_ci break; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci case MT2063_B1: 18438c2ecf20Sopenharmony_ci def = MT2063B1_defaults; 18448c2ecf20Sopenharmony_ci break; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci case MT2063_B0: 18478c2ecf20Sopenharmony_ci def = MT2063B0_defaults; 18488c2ecf20Sopenharmony_ci break; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci default: 18518c2ecf20Sopenharmony_ci return -ENODEV; 18528c2ecf20Sopenharmony_ci break; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci while (status >= 0 && *def) { 18568c2ecf20Sopenharmony_ci u8 reg = *def++; 18578c2ecf20Sopenharmony_ci u8 val = *def++; 18588c2ecf20Sopenharmony_ci status = mt2063_write(state, reg, &val, 1); 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci if (status < 0) 18618c2ecf20Sopenharmony_ci return status; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci /* Wait for FIFF location to complete. */ 18648c2ecf20Sopenharmony_ci FCRUN = 1; 18658c2ecf20Sopenharmony_ci maxReads = 10; 18668c2ecf20Sopenharmony_ci while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) { 18678c2ecf20Sopenharmony_ci msleep(2); 18688c2ecf20Sopenharmony_ci status = mt2063_read(state, 18698c2ecf20Sopenharmony_ci MT2063_REG_XO_STATUS, 18708c2ecf20Sopenharmony_ci &state-> 18718c2ecf20Sopenharmony_ci reg[MT2063_REG_XO_STATUS], 1); 18728c2ecf20Sopenharmony_ci FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci if (FCRUN != 0 || status < 0) 18768c2ecf20Sopenharmony_ci return -ENODEV; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci status = mt2063_read(state, 18798c2ecf20Sopenharmony_ci MT2063_REG_FIFFC, 18808c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_FIFFC], 1); 18818c2ecf20Sopenharmony_ci if (status < 0) 18828c2ecf20Sopenharmony_ci return status; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci /* Read back all the registers from the tuner */ 18858c2ecf20Sopenharmony_ci status = mt2063_read(state, 18868c2ecf20Sopenharmony_ci MT2063_REG_PART_REV, 18878c2ecf20Sopenharmony_ci state->reg, MT2063_REG_END_REGS); 18888c2ecf20Sopenharmony_ci if (status < 0) 18898c2ecf20Sopenharmony_ci return status; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci /* Initialize the tuner state. */ 18928c2ecf20Sopenharmony_ci state->tuner_id = state->reg[MT2063_REG_PART_REV]; 18938c2ecf20Sopenharmony_ci state->AS_Data.f_ref = MT2063_REF_FREQ; 18948c2ecf20Sopenharmony_ci state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) * 18958c2ecf20Sopenharmony_ci ((u32) state->reg[MT2063_REG_FIFFC] + 640); 18968c2ecf20Sopenharmony_ci state->AS_Data.f_if1_bw = MT2063_IF1_BW; 18978c2ecf20Sopenharmony_ci state->AS_Data.f_out = 43750000UL; 18988c2ecf20Sopenharmony_ci state->AS_Data.f_out_bw = 6750000UL; 18998c2ecf20Sopenharmony_ci state->AS_Data.f_zif_bw = MT2063_ZIF_BW; 19008c2ecf20Sopenharmony_ci state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64; 19018c2ecf20Sopenharmony_ci state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE; 19028c2ecf20Sopenharmony_ci state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1; 19038c2ecf20Sopenharmony_ci state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2; 19048c2ecf20Sopenharmony_ci state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP; 19058c2ecf20Sopenharmony_ci state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center; 19068c2ecf20Sopenharmony_ci state->AS_Data.f_LO1 = 2181000000UL; 19078c2ecf20Sopenharmony_ci state->AS_Data.f_LO2 = 1486249786UL; 19088c2ecf20Sopenharmony_ci state->f_IF1_actual = state->AS_Data.f_if1_Center; 19098c2ecf20Sopenharmony_ci state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual; 19108c2ecf20Sopenharmony_ci state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID; 19118c2ecf20Sopenharmony_ci state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID; 19128c2ecf20Sopenharmony_ci state->num_regs = MT2063_REG_END_REGS; 19138c2ecf20Sopenharmony_ci state->AS_Data.avoidDECT = MT2063_AVOID_BOTH; 19148c2ecf20Sopenharmony_ci state->ctfilt_sw = 0; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci state->CTFiltMax[0] = 69230000; 19178c2ecf20Sopenharmony_ci state->CTFiltMax[1] = 105770000; 19188c2ecf20Sopenharmony_ci state->CTFiltMax[2] = 140350000; 19198c2ecf20Sopenharmony_ci state->CTFiltMax[3] = 177110000; 19208c2ecf20Sopenharmony_ci state->CTFiltMax[4] = 212860000; 19218c2ecf20Sopenharmony_ci state->CTFiltMax[5] = 241130000; 19228c2ecf20Sopenharmony_ci state->CTFiltMax[6] = 274370000; 19238c2ecf20Sopenharmony_ci state->CTFiltMax[7] = 309820000; 19248c2ecf20Sopenharmony_ci state->CTFiltMax[8] = 342450000; 19258c2ecf20Sopenharmony_ci state->CTFiltMax[9] = 378870000; 19268c2ecf20Sopenharmony_ci state->CTFiltMax[10] = 416210000; 19278c2ecf20Sopenharmony_ci state->CTFiltMax[11] = 456500000; 19288c2ecf20Sopenharmony_ci state->CTFiltMax[12] = 495790000; 19298c2ecf20Sopenharmony_ci state->CTFiltMax[13] = 534530000; 19308c2ecf20Sopenharmony_ci state->CTFiltMax[14] = 572610000; 19318c2ecf20Sopenharmony_ci state->CTFiltMax[15] = 598970000; 19328c2ecf20Sopenharmony_ci state->CTFiltMax[16] = 635910000; 19338c2ecf20Sopenharmony_ci state->CTFiltMax[17] = 672130000; 19348c2ecf20Sopenharmony_ci state->CTFiltMax[18] = 714840000; 19358c2ecf20Sopenharmony_ci state->CTFiltMax[19] = 739660000; 19368c2ecf20Sopenharmony_ci state->CTFiltMax[20] = 770410000; 19378c2ecf20Sopenharmony_ci state->CTFiltMax[21] = 814660000; 19388c2ecf20Sopenharmony_ci state->CTFiltMax[22] = 846950000; 19398c2ecf20Sopenharmony_ci state->CTFiltMax[23] = 867820000; 19408c2ecf20Sopenharmony_ci state->CTFiltMax[24] = 915980000; 19418c2ecf20Sopenharmony_ci state->CTFiltMax[25] = 947450000; 19428c2ecf20Sopenharmony_ci state->CTFiltMax[26] = 983110000; 19438c2ecf20Sopenharmony_ci state->CTFiltMax[27] = 1021630000; 19448c2ecf20Sopenharmony_ci state->CTFiltMax[28] = 1061870000; 19458c2ecf20Sopenharmony_ci state->CTFiltMax[29] = 1098330000; 19468c2ecf20Sopenharmony_ci state->CTFiltMax[30] = 1138990000; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci /* 19498c2ecf20Sopenharmony_ci ** Fetch the FCU osc value and use it and the fRef value to 19508c2ecf20Sopenharmony_ci ** scale all of the Band Max values 19518c2ecf20Sopenharmony_ci */ 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A; 19548c2ecf20Sopenharmony_ci status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, 19558c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_CTUNE_CTRL], 1); 19568c2ecf20Sopenharmony_ci if (status < 0) 19578c2ecf20Sopenharmony_ci return status; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci /* Read the ClearTune filter calibration value */ 19608c2ecf20Sopenharmony_ci status = mt2063_read(state, MT2063_REG_FIFFC, 19618c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_FIFFC], 1); 19628c2ecf20Sopenharmony_ci if (status < 0) 19638c2ecf20Sopenharmony_ci return status; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci fcu_osc = state->reg[MT2063_REG_FIFFC]; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci state->reg[MT2063_REG_CTUNE_CTRL] = 0x00; 19688c2ecf20Sopenharmony_ci status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, 19698c2ecf20Sopenharmony_ci &state->reg[MT2063_REG_CTUNE_CTRL], 1); 19708c2ecf20Sopenharmony_ci if (status < 0) 19718c2ecf20Sopenharmony_ci return status; 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci /* Adjust each of the values in the ClearTune filter cross-over table */ 19748c2ecf20Sopenharmony_ci for (i = 0; i < 31; i++) 19758c2ecf20Sopenharmony_ci state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci status = MT2063_SoftwareShutdown(state, 1); 19788c2ecf20Sopenharmony_ci if (status < 0) 19798c2ecf20Sopenharmony_ci return status; 19808c2ecf20Sopenharmony_ci status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); 19818c2ecf20Sopenharmony_ci if (status < 0) 19828c2ecf20Sopenharmony_ci return status; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci state->init = true; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci return 0; 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_cistatic int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) 19908c2ecf20Sopenharmony_ci{ 19918c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 19928c2ecf20Sopenharmony_ci int status; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci dprintk(2, "\n"); 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (!state->init) 19978c2ecf20Sopenharmony_ci return -ENODEV; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci *tuner_status = 0; 20008c2ecf20Sopenharmony_ci status = mt2063_lockStatus(state); 20018c2ecf20Sopenharmony_ci if (status < 0) 20028c2ecf20Sopenharmony_ci return status; 20038c2ecf20Sopenharmony_ci if (status) 20048c2ecf20Sopenharmony_ci *tuner_status = TUNER_STATUS_LOCKED; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci dprintk(1, "Tuner status: %d", *tuner_status); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci return 0; 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_cistatic void mt2063_release(struct dvb_frontend *fe) 20128c2ecf20Sopenharmony_ci{ 20138c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci dprintk(2, "\n"); 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci fe->tuner_priv = NULL; 20188c2ecf20Sopenharmony_ci kfree(state); 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_cistatic int mt2063_set_analog_params(struct dvb_frontend *fe, 20228c2ecf20Sopenharmony_ci struct analog_parameters *params) 20238c2ecf20Sopenharmony_ci{ 20248c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 20258c2ecf20Sopenharmony_ci s32 pict_car; 20268c2ecf20Sopenharmony_ci s32 pict2chanb_vsb; 20278c2ecf20Sopenharmony_ci s32 ch_bw; 20288c2ecf20Sopenharmony_ci s32 if_mid; 20298c2ecf20Sopenharmony_ci s32 rcvr_mode; 20308c2ecf20Sopenharmony_ci int status; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci dprintk(2, "\n"); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci if (!state->init) { 20358c2ecf20Sopenharmony_ci status = mt2063_init(fe); 20368c2ecf20Sopenharmony_ci if (status < 0) 20378c2ecf20Sopenharmony_ci return status; 20388c2ecf20Sopenharmony_ci } 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci switch (params->mode) { 20418c2ecf20Sopenharmony_ci case V4L2_TUNER_RADIO: 20428c2ecf20Sopenharmony_ci pict_car = 38900000; 20438c2ecf20Sopenharmony_ci ch_bw = 8000000; 20448c2ecf20Sopenharmony_ci pict2chanb_vsb = -(ch_bw / 2); 20458c2ecf20Sopenharmony_ci rcvr_mode = MT2063_OFFAIR_ANALOG; 20468c2ecf20Sopenharmony_ci break; 20478c2ecf20Sopenharmony_ci case V4L2_TUNER_ANALOG_TV: 20488c2ecf20Sopenharmony_ci rcvr_mode = MT2063_CABLE_ANALOG; 20498c2ecf20Sopenharmony_ci if (params->std & ~V4L2_STD_MN) { 20508c2ecf20Sopenharmony_ci pict_car = 38900000; 20518c2ecf20Sopenharmony_ci ch_bw = 6000000; 20528c2ecf20Sopenharmony_ci pict2chanb_vsb = -1250000; 20538c2ecf20Sopenharmony_ci } else if (params->std & V4L2_STD_PAL_G) { 20548c2ecf20Sopenharmony_ci pict_car = 38900000; 20558c2ecf20Sopenharmony_ci ch_bw = 7000000; 20568c2ecf20Sopenharmony_ci pict2chanb_vsb = -1250000; 20578c2ecf20Sopenharmony_ci } else { /* PAL/SECAM standards */ 20588c2ecf20Sopenharmony_ci pict_car = 38900000; 20598c2ecf20Sopenharmony_ci ch_bw = 8000000; 20608c2ecf20Sopenharmony_ci pict2chanb_vsb = -1250000; 20618c2ecf20Sopenharmony_ci } 20628c2ecf20Sopenharmony_ci break; 20638c2ecf20Sopenharmony_ci default: 20648c2ecf20Sopenharmony_ci return -EINVAL; 20658c2ecf20Sopenharmony_ci } 20668c2ecf20Sopenharmony_ci if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ 20698c2ecf20Sopenharmony_ci state->AS_Data.f_out = if_mid; 20708c2ecf20Sopenharmony_ci state->AS_Data.f_out_bw = ch_bw + 750000; 20718c2ecf20Sopenharmony_ci status = MT2063_SetReceiverMode(state, rcvr_mode); 20728c2ecf20Sopenharmony_ci if (status < 0) 20738c2ecf20Sopenharmony_ci return status; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", 20768c2ecf20Sopenharmony_ci params->frequency, ch_bw, pict2chanb_vsb); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2)))); 20798c2ecf20Sopenharmony_ci if (status < 0) 20808c2ecf20Sopenharmony_ci return status; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci state->frequency = params->frequency; 20838c2ecf20Sopenharmony_ci return 0; 20848c2ecf20Sopenharmony_ci} 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci/* 20878c2ecf20Sopenharmony_ci * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. 20888c2ecf20Sopenharmony_ci * So, the amount of the needed bandwidth is given by: 20898c2ecf20Sopenharmony_ci * Bw = Symbol_rate * (1 + 0.15) 20908c2ecf20Sopenharmony_ci * As such, the maximum symbol rate supported by 6 MHz is given by: 20918c2ecf20Sopenharmony_ci * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds 20928c2ecf20Sopenharmony_ci */ 20938c2ecf20Sopenharmony_ci#define MAX_SYMBOL_RATE_6MHz 5217391 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic int mt2063_set_params(struct dvb_frontend *fe) 20968c2ecf20Sopenharmony_ci{ 20978c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 20988c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 20998c2ecf20Sopenharmony_ci int status; 21008c2ecf20Sopenharmony_ci s32 pict_car; 21018c2ecf20Sopenharmony_ci s32 pict2chanb_vsb; 21028c2ecf20Sopenharmony_ci s32 ch_bw; 21038c2ecf20Sopenharmony_ci s32 if_mid; 21048c2ecf20Sopenharmony_ci s32 rcvr_mode; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci if (!state->init) { 21078c2ecf20Sopenharmony_ci status = mt2063_init(fe); 21088c2ecf20Sopenharmony_ci if (status < 0) 21098c2ecf20Sopenharmony_ci return status; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci dprintk(2, "\n"); 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci if (c->bandwidth_hz == 0) 21158c2ecf20Sopenharmony_ci return -EINVAL; 21168c2ecf20Sopenharmony_ci if (c->bandwidth_hz <= 6000000) 21178c2ecf20Sopenharmony_ci ch_bw = 6000000; 21188c2ecf20Sopenharmony_ci else if (c->bandwidth_hz <= 7000000) 21198c2ecf20Sopenharmony_ci ch_bw = 7000000; 21208c2ecf20Sopenharmony_ci else 21218c2ecf20Sopenharmony_ci ch_bw = 8000000; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci switch (c->delivery_system) { 21248c2ecf20Sopenharmony_ci case SYS_DVBT: 21258c2ecf20Sopenharmony_ci rcvr_mode = MT2063_OFFAIR_COFDM; 21268c2ecf20Sopenharmony_ci pict_car = 36125000; 21278c2ecf20Sopenharmony_ci pict2chanb_vsb = -(ch_bw / 2); 21288c2ecf20Sopenharmony_ci break; 21298c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_A: 21308c2ecf20Sopenharmony_ci case SYS_DVBC_ANNEX_C: 21318c2ecf20Sopenharmony_ci rcvr_mode = MT2063_CABLE_QAM; 21328c2ecf20Sopenharmony_ci pict_car = 36125000; 21338c2ecf20Sopenharmony_ci pict2chanb_vsb = -(ch_bw / 2); 21348c2ecf20Sopenharmony_ci break; 21358c2ecf20Sopenharmony_ci default: 21368c2ecf20Sopenharmony_ci return -EINVAL; 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ 21418c2ecf20Sopenharmony_ci state->AS_Data.f_out = if_mid; 21428c2ecf20Sopenharmony_ci state->AS_Data.f_out_bw = ch_bw + 750000; 21438c2ecf20Sopenharmony_ci status = MT2063_SetReceiverMode(state, rcvr_mode); 21448c2ecf20Sopenharmony_ci if (status < 0) 21458c2ecf20Sopenharmony_ci return status; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", 21488c2ecf20Sopenharmony_ci c->frequency, ch_bw, pict2chanb_vsb); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2)))); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci if (status < 0) 21538c2ecf20Sopenharmony_ci return status; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci state->frequency = c->frequency; 21568c2ecf20Sopenharmony_ci return 0; 21578c2ecf20Sopenharmony_ci} 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_cistatic int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq) 21608c2ecf20Sopenharmony_ci{ 21618c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci dprintk(2, "\n"); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci if (!state->init) 21668c2ecf20Sopenharmony_ci return -ENODEV; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci *freq = state->AS_Data.f_out; 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci dprintk(1, "IF frequency: %d\n", *freq); 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci return 0; 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_cistatic int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) 21768c2ecf20Sopenharmony_ci{ 21778c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci dprintk(2, "\n"); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci if (!state->init) 21828c2ecf20Sopenharmony_ci return -ENODEV; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci *bw = state->AS_Data.f_out_bw - 750000; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci dprintk(1, "bandwidth: %d\n", *bw); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci return 0; 21898c2ecf20Sopenharmony_ci} 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops mt2063_ops = { 21928c2ecf20Sopenharmony_ci .info = { 21938c2ecf20Sopenharmony_ci .name = "MT2063 Silicon Tuner", 21948c2ecf20Sopenharmony_ci .frequency_min_hz = 45 * MHz, 21958c2ecf20Sopenharmony_ci .frequency_max_hz = 865 * MHz, 21968c2ecf20Sopenharmony_ci }, 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci .init = mt2063_init, 21998c2ecf20Sopenharmony_ci .sleep = MT2063_Sleep, 22008c2ecf20Sopenharmony_ci .get_status = mt2063_get_status, 22018c2ecf20Sopenharmony_ci .set_analog_params = mt2063_set_analog_params, 22028c2ecf20Sopenharmony_ci .set_params = mt2063_set_params, 22038c2ecf20Sopenharmony_ci .get_if_frequency = mt2063_get_if_frequency, 22048c2ecf20Sopenharmony_ci .get_bandwidth = mt2063_get_bandwidth, 22058c2ecf20Sopenharmony_ci .release = mt2063_release, 22068c2ecf20Sopenharmony_ci}; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_cistruct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, 22098c2ecf20Sopenharmony_ci struct mt2063_config *config, 22108c2ecf20Sopenharmony_ci struct i2c_adapter *i2c) 22118c2ecf20Sopenharmony_ci{ 22128c2ecf20Sopenharmony_ci struct mt2063_state *state = NULL; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci dprintk(2, "\n"); 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); 22178c2ecf20Sopenharmony_ci if (!state) 22188c2ecf20Sopenharmony_ci return NULL; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci state->config = config; 22218c2ecf20Sopenharmony_ci state->i2c = i2c; 22228c2ecf20Sopenharmony_ci state->frontend = fe; 22238c2ecf20Sopenharmony_ci state->reference = config->refclock / 1000; /* kHz */ 22248c2ecf20Sopenharmony_ci fe->tuner_priv = state; 22258c2ecf20Sopenharmony_ci fe->ops.tuner_ops = mt2063_ops; 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Attaching MT2063\n", __func__); 22288c2ecf20Sopenharmony_ci return fe; 22298c2ecf20Sopenharmony_ci} 22308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt2063_attach); 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci#if 0 22338c2ecf20Sopenharmony_ci/* 22348c2ecf20Sopenharmony_ci * Ancillary routines visible outside mt2063 22358c2ecf20Sopenharmony_ci * FIXME: Remove them in favor of using standard tuner callbacks 22368c2ecf20Sopenharmony_ci */ 22378c2ecf20Sopenharmony_cistatic int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) 22388c2ecf20Sopenharmony_ci{ 22398c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 22408c2ecf20Sopenharmony_ci int err = 0; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci dprintk(2, "\n"); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci err = MT2063_SoftwareShutdown(state, 1); 22458c2ecf20Sopenharmony_ci if (err < 0) 22468c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci return err; 22498c2ecf20Sopenharmony_ci} 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_cistatic int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) 22528c2ecf20Sopenharmony_ci{ 22538c2ecf20Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 22548c2ecf20Sopenharmony_ci int err = 0; 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci dprintk(2, "\n"); 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); 22598c2ecf20Sopenharmony_ci if (err < 0) 22608c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Invalid parameter\n", __func__); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci return err; 22638c2ecf20Sopenharmony_ci} 22648c2ecf20Sopenharmony_ci#endif 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab"); 22678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MT2063 Silicon tuner"); 22688c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2269