162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for mt2063 Micronas tuner 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2011 Mauro Carvalho Chehab 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This driver came from a driver originally written by: 862306a36Sopenharmony_ci * Henry Wang <Henry.wang@AzureWave.com> 962306a36Sopenharmony_ci * Made publicly available by Terratec, at: 1062306a36Sopenharmony_ci * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/videodev2.h> 1862306a36Sopenharmony_ci#include <linux/gcd.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "mt2063.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic unsigned int debug; 2362306a36Sopenharmony_cimodule_param(debug, int, 0644); 2462306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Set Verbosity level"); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define dprintk(level, fmt, arg...) do { \ 2762306a36Sopenharmony_ciif (debug >= level) \ 2862306a36Sopenharmony_ci printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \ 2962306a36Sopenharmony_ci} while (0) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* positive error codes used internally */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Info: Unavoidable LO-related spur may be present in the output */ 3562306a36Sopenharmony_ci#define MT2063_SPUR_PRESENT_ERR (0x00800000) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */ 3862306a36Sopenharmony_ci#define MT2063_SPUR_CNT_MASK (0x001f0000) 3962306a36Sopenharmony_ci#define MT2063_SPUR_SHIFT (16) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */ 4262306a36Sopenharmony_ci#define MT2063_UPC_RANGE (0x04000000) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */ 4562306a36Sopenharmony_ci#define MT2063_DNC_RANGE (0x08000000) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * Constant defining the version of the following structure 4962306a36Sopenharmony_ci * and therefore the API for this code. 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * When compiling the tuner driver, the preprocessor will 5262306a36Sopenharmony_ci * check against this version number to make sure that 5362306a36Sopenharmony_ci * it matches the version that the tuner driver knows about. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* DECT Frequency Avoidance */ 5762306a36Sopenharmony_ci#define MT2063_DECT_AVOID_US_FREQS 0x00000001 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cienum MT2063_DECT_Avoid_Type { 6662306a36Sopenharmony_ci MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */ 6762306a36Sopenharmony_ci MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */ 6862306a36Sopenharmony_ci MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */ 6962306a36Sopenharmony_ci MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */ 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define MT2063_MAX_ZONES 48 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistruct MT2063_ExclZone_t { 7562306a36Sopenharmony_ci u32 min_; 7662306a36Sopenharmony_ci u32 max_; 7762306a36Sopenharmony_ci struct MT2063_ExclZone_t *next_; 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * Structure of data needed for Spur Avoidance 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_cistruct MT2063_AvoidSpursData_t { 8462306a36Sopenharmony_ci u32 f_ref; 8562306a36Sopenharmony_ci u32 f_in; 8662306a36Sopenharmony_ci u32 f_LO1; 8762306a36Sopenharmony_ci u32 f_if1_Center; 8862306a36Sopenharmony_ci u32 f_if1_Request; 8962306a36Sopenharmony_ci u32 f_if1_bw; 9062306a36Sopenharmony_ci u32 f_LO2; 9162306a36Sopenharmony_ci u32 f_out; 9262306a36Sopenharmony_ci u32 f_out_bw; 9362306a36Sopenharmony_ci u32 f_LO1_Step; 9462306a36Sopenharmony_ci u32 f_LO2_Step; 9562306a36Sopenharmony_ci u32 f_LO1_FracN_Avoid; 9662306a36Sopenharmony_ci u32 f_LO2_FracN_Avoid; 9762306a36Sopenharmony_ci u32 f_zif_bw; 9862306a36Sopenharmony_ci u32 f_min_LO_Separation; 9962306a36Sopenharmony_ci u32 maxH1; 10062306a36Sopenharmony_ci u32 maxH2; 10162306a36Sopenharmony_ci enum MT2063_DECT_Avoid_Type avoidDECT; 10262306a36Sopenharmony_ci u32 bSpurPresent; 10362306a36Sopenharmony_ci u32 bSpurAvoided; 10462306a36Sopenharmony_ci u32 nSpursFound; 10562306a36Sopenharmony_ci u32 nZones; 10662306a36Sopenharmony_ci struct MT2063_ExclZone_t *freeZones; 10762306a36Sopenharmony_ci struct MT2063_ExclZone_t *usedZones; 10862306a36Sopenharmony_ci struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES]; 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * Parameter for function MT2063_SetPowerMask that specifies the power down 11362306a36Sopenharmony_ci * of various sections of the MT2063. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cienum MT2063_Mask_Bits { 11662306a36Sopenharmony_ci MT2063_REG_SD = 0x0040, /* Shutdown regulator */ 11762306a36Sopenharmony_ci MT2063_SRO_SD = 0x0020, /* Shutdown SRO */ 11862306a36Sopenharmony_ci MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */ 11962306a36Sopenharmony_ci MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */ 12062306a36Sopenharmony_ci MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */ 12162306a36Sopenharmony_ci MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */ 12262306a36Sopenharmony_ci MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */ 12362306a36Sopenharmony_ci MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */ 12462306a36Sopenharmony_ci MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */ 12562306a36Sopenharmony_ci MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */ 12662306a36Sopenharmony_ci MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */ 12762306a36Sopenharmony_ci MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */ 12862306a36Sopenharmony_ci MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */ 12962306a36Sopenharmony_ci MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */ 13062306a36Sopenharmony_ci MT2063_NONE_SD = 0x0000 /* No shutdown bits */ 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * Possible values for MT2063_DNC_OUTPUT 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cienum MT2063_DNC_Output_Enable { 13762306a36Sopenharmony_ci MT2063_DNC_NONE = 0, 13862306a36Sopenharmony_ci MT2063_DNC_1, 13962306a36Sopenharmony_ci MT2063_DNC_2, 14062306a36Sopenharmony_ci MT2063_DNC_BOTH 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * Two-wire serial bus subaddresses of the tuner registers. 14562306a36Sopenharmony_ci * Also known as the tuner's register addresses. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_cienum MT2063_Register_Offsets { 14862306a36Sopenharmony_ci MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */ 14962306a36Sopenharmony_ci MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */ 15062306a36Sopenharmony_ci MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */ 15162306a36Sopenharmony_ci MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */ 15262306a36Sopenharmony_ci MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */ 15362306a36Sopenharmony_ci MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */ 15462306a36Sopenharmony_ci MT2063_REG_RSVD_06, /* 0x06: Reserved */ 15562306a36Sopenharmony_ci MT2063_REG_LO_STATUS, /* 0x07: LO Status */ 15662306a36Sopenharmony_ci MT2063_REG_FIFFC, /* 0x08: FIFF Center */ 15762306a36Sopenharmony_ci MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */ 15862306a36Sopenharmony_ci MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */ 15962306a36Sopenharmony_ci MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */ 16062306a36Sopenharmony_ci MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */ 16162306a36Sopenharmony_ci MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */ 16262306a36Sopenharmony_ci MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */ 16362306a36Sopenharmony_ci MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */ 16462306a36Sopenharmony_ci MT2063_REG_RSVD_10, /* 0x10: Reserved */ 16562306a36Sopenharmony_ci MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */ 16662306a36Sopenharmony_ci MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */ 16762306a36Sopenharmony_ci MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */ 16862306a36Sopenharmony_ci MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */ 16962306a36Sopenharmony_ci MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */ 17062306a36Sopenharmony_ci MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */ 17162306a36Sopenharmony_ci MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */ 17262306a36Sopenharmony_ci MT2063_REG_RF_OV, /* 0x18: RF Attn Override */ 17362306a36Sopenharmony_ci MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */ 17462306a36Sopenharmony_ci MT2063_REG_LNA_TGT, /* 0x1A: Reserved */ 17562306a36Sopenharmony_ci MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */ 17662306a36Sopenharmony_ci MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */ 17762306a36Sopenharmony_ci MT2063_REG_RSVD_1D, /* 0x1D: Reserved */ 17862306a36Sopenharmony_ci MT2063_REG_RSVD_1E, /* 0x1E: Reserved */ 17962306a36Sopenharmony_ci MT2063_REG_RSVD_1F, /* 0x1F: Reserved */ 18062306a36Sopenharmony_ci MT2063_REG_RSVD_20, /* 0x20: Reserved */ 18162306a36Sopenharmony_ci MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */ 18262306a36Sopenharmony_ci MT2063_REG_RSVD_22, /* 0x22: Reserved */ 18362306a36Sopenharmony_ci MT2063_REG_RSVD_23, /* 0x23: Reserved */ 18462306a36Sopenharmony_ci MT2063_REG_RSVD_24, /* 0x24: Reserved */ 18562306a36Sopenharmony_ci MT2063_REG_RSVD_25, /* 0x25: Reserved */ 18662306a36Sopenharmony_ci MT2063_REG_RSVD_26, /* 0x26: Reserved */ 18762306a36Sopenharmony_ci MT2063_REG_RSVD_27, /* 0x27: Reserved */ 18862306a36Sopenharmony_ci MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */ 18962306a36Sopenharmony_ci MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */ 19062306a36Sopenharmony_ci MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */ 19162306a36Sopenharmony_ci MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */ 19262306a36Sopenharmony_ci MT2063_REG_CTRL_2C, /* 0x2C: Reserved */ 19362306a36Sopenharmony_ci MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */ 19462306a36Sopenharmony_ci MT2063_REG_RSVD_2E, /* 0x2E: Reserved */ 19562306a36Sopenharmony_ci MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */ 19662306a36Sopenharmony_ci MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */ 19762306a36Sopenharmony_ci MT2063_REG_RSVD_31, /* 0x31: Reserved */ 19862306a36Sopenharmony_ci MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */ 19962306a36Sopenharmony_ci MT2063_REG_RSVD_33, /* 0x33: Reserved */ 20062306a36Sopenharmony_ci MT2063_REG_RSVD_34, /* 0x34: Reserved */ 20162306a36Sopenharmony_ci MT2063_REG_RSVD_35, /* 0x35: Reserved */ 20262306a36Sopenharmony_ci MT2063_REG_RSVD_36, /* 0x36: Reserved */ 20362306a36Sopenharmony_ci MT2063_REG_RSVD_37, /* 0x37: Reserved */ 20462306a36Sopenharmony_ci MT2063_REG_RSVD_38, /* 0x38: Reserved */ 20562306a36Sopenharmony_ci MT2063_REG_RSVD_39, /* 0x39: Reserved */ 20662306a36Sopenharmony_ci MT2063_REG_RSVD_3A, /* 0x3A: Reserved */ 20762306a36Sopenharmony_ci MT2063_REG_RSVD_3B, /* 0x3B: Reserved */ 20862306a36Sopenharmony_ci MT2063_REG_RSVD_3C, /* 0x3C: Reserved */ 20962306a36Sopenharmony_ci MT2063_REG_END_REGS 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistruct mt2063_state { 21362306a36Sopenharmony_ci struct i2c_adapter *i2c; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci bool init; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci const struct mt2063_config *config; 21862306a36Sopenharmony_ci struct dvb_tuner_ops ops; 21962306a36Sopenharmony_ci struct dvb_frontend *frontend; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci u32 frequency; 22262306a36Sopenharmony_ci u32 srate; 22362306a36Sopenharmony_ci u32 bandwidth; 22462306a36Sopenharmony_ci u32 reference; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci u32 tuner_id; 22762306a36Sopenharmony_ci struct MT2063_AvoidSpursData_t AS_Data; 22862306a36Sopenharmony_ci u32 f_IF1_actual; 22962306a36Sopenharmony_ci u32 rcvr_mode; 23062306a36Sopenharmony_ci u32 ctfilt_sw; 23162306a36Sopenharmony_ci u32 CTFiltMax[31]; 23262306a36Sopenharmony_ci u32 num_regs; 23362306a36Sopenharmony_ci u8 reg[MT2063_REG_END_REGS]; 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* 23762306a36Sopenharmony_ci * mt2063_write - Write data into the I2C bus 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_cistatic int mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct dvb_frontend *fe = state->frontend; 24262306a36Sopenharmony_ci int ret; 24362306a36Sopenharmony_ci u8 buf[60]; 24462306a36Sopenharmony_ci struct i2c_msg msg = { 24562306a36Sopenharmony_ci .addr = state->config->tuner_address, 24662306a36Sopenharmony_ci .flags = 0, 24762306a36Sopenharmony_ci .buf = buf, 24862306a36Sopenharmony_ci .len = len + 1 24962306a36Sopenharmony_ci }; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci dprintk(2, "\n"); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci msg.buf[0] = reg; 25462306a36Sopenharmony_ci memcpy(msg.buf + 1, data, len); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 25762306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 25862306a36Sopenharmony_ci ret = i2c_transfer(state->i2c, &msg, 1); 25962306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 26062306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (ret < 0) 26362306a36Sopenharmony_ci printk(KERN_ERR "%s error ret=%d\n", __func__, ret); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* 26962306a36Sopenharmony_ci * mt2063_write - Write register data into the I2C bus, caching the value 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_cistatic int mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci int status; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci dprintk(2, "\n"); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (reg >= MT2063_REG_END_REGS) 27862306a36Sopenharmony_ci return -ERANGE; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci status = mt2063_write(state, reg, &val, 1); 28162306a36Sopenharmony_ci if (status < 0) 28262306a36Sopenharmony_ci return status; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci state->reg[reg] = val; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* 29062306a36Sopenharmony_ci * mt2063_read - Read data from the I2C bus 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_cistatic int mt2063_read(struct mt2063_state *state, 29362306a36Sopenharmony_ci u8 subAddress, u8 *pData, u32 cnt) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci int status = 0; /* Status to be returned */ 29662306a36Sopenharmony_ci struct dvb_frontend *fe = state->frontend; 29762306a36Sopenharmony_ci u32 i = 0; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 30262306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 30562306a36Sopenharmony_ci u8 b0[] = { subAddress + i }; 30662306a36Sopenharmony_ci struct i2c_msg msg[] = { 30762306a36Sopenharmony_ci { 30862306a36Sopenharmony_ci .addr = state->config->tuner_address, 30962306a36Sopenharmony_ci .flags = 0, 31062306a36Sopenharmony_ci .buf = b0, 31162306a36Sopenharmony_ci .len = 1 31262306a36Sopenharmony_ci }, { 31362306a36Sopenharmony_ci .addr = state->config->tuner_address, 31462306a36Sopenharmony_ci .flags = I2C_M_RD, 31562306a36Sopenharmony_ci .buf = pData + i, 31662306a36Sopenharmony_ci .len = 1 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci }; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci status = i2c_transfer(state->i2c, msg, 2); 32162306a36Sopenharmony_ci dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n", 32262306a36Sopenharmony_ci subAddress + i, status, *(pData + i)); 32362306a36Sopenharmony_ci if (status < 0) 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 32762306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 0); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (status < 0) 33062306a36Sopenharmony_ci printk(KERN_ERR "Can't read from address 0x%02x,\n", 33162306a36Sopenharmony_ci subAddress + i); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return status; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/* 33762306a36Sopenharmony_ci * FIXME: Is this really needed? 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_cistatic int MT2063_Sleep(struct dvb_frontend *fe) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci /* 34262306a36Sopenharmony_ci * ToDo: Add code here to implement a OS blocking 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci msleep(100); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* 35062306a36Sopenharmony_ci * Microtune spur avoidance 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/* Implement ceiling, floor functions. */ 35462306a36Sopenharmony_ci#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0)) 35562306a36Sopenharmony_ci#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d)) 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistruct MT2063_FIFZone_t { 35862306a36Sopenharmony_ci s32 min_; 35962306a36Sopenharmony_ci s32 max_; 36062306a36Sopenharmony_ci}; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t 36362306a36Sopenharmony_ci *pAS_Info, 36462306a36Sopenharmony_ci struct MT2063_ExclZone_t *pPrevNode) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct MT2063_ExclZone_t *pNode; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci dprintk(2, "\n"); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Check for a node in the free list */ 37162306a36Sopenharmony_ci if (pAS_Info->freeZones != NULL) { 37262306a36Sopenharmony_ci /* Use one from the free list */ 37362306a36Sopenharmony_ci pNode = pAS_Info->freeZones; 37462306a36Sopenharmony_ci pAS_Info->freeZones = pNode->next_; 37562306a36Sopenharmony_ci } else { 37662306a36Sopenharmony_ci /* Grab a node from the array */ 37762306a36Sopenharmony_ci pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones]; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (pPrevNode != NULL) { 38162306a36Sopenharmony_ci pNode->next_ = pPrevNode->next_; 38262306a36Sopenharmony_ci pPrevNode->next_ = pNode; 38362306a36Sopenharmony_ci } else { /* insert at the beginning of the list */ 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci pNode->next_ = pAS_Info->usedZones; 38662306a36Sopenharmony_ci pAS_Info->usedZones = pNode; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci pAS_Info->nZones++; 39062306a36Sopenharmony_ci return pNode; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t 39462306a36Sopenharmony_ci *pAS_Info, 39562306a36Sopenharmony_ci struct MT2063_ExclZone_t *pPrevNode, 39662306a36Sopenharmony_ci struct MT2063_ExclZone_t 39762306a36Sopenharmony_ci *pNodeToRemove) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci dprintk(2, "\n"); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Make previous node point to the subsequent node */ 40462306a36Sopenharmony_ci if (pPrevNode != NULL) 40562306a36Sopenharmony_ci pPrevNode->next_ = pNext; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Add pNodeToRemove to the beginning of the freeZones */ 40862306a36Sopenharmony_ci pNodeToRemove->next_ = pAS_Info->freeZones; 40962306a36Sopenharmony_ci pAS_Info->freeZones = pNodeToRemove; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Decrement node count */ 41262306a36Sopenharmony_ci pAS_Info->nZones--; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return pNext; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* 41862306a36Sopenharmony_ci * MT_AddExclZone() 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * Add (and merge) an exclusion zone into the list. 42162306a36Sopenharmony_ci * If the range (f_min, f_max) is totally outside the 42262306a36Sopenharmony_ci * 1st IF BW, ignore the entry. 42362306a36Sopenharmony_ci * If the range (f_min, f_max) is negative, ignore the entry. 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_cistatic void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, 42662306a36Sopenharmony_ci u32 f_min, u32 f_max) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; 42962306a36Sopenharmony_ci struct MT2063_ExclZone_t *pPrev = NULL; 43062306a36Sopenharmony_ci struct MT2063_ExclZone_t *pNext = NULL; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci dprintk(2, "\n"); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Check to see if this overlaps the 1st IF filter */ 43562306a36Sopenharmony_ci if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2))) 43662306a36Sopenharmony_ci && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2))) 43762306a36Sopenharmony_ci && (f_min < f_max)) { 43862306a36Sopenharmony_ci /* 43962306a36Sopenharmony_ci * 1 2 3 4 5 6 44062306a36Sopenharmony_ci * 44162306a36Sopenharmony_ci * New entry: |---| |--| |--| |-| |---| |--| 44262306a36Sopenharmony_ci * or or or or or 44362306a36Sopenharmony_ci * Existing: |--| |--| |--| |---| |-| |--| 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* Check for our place in the list */ 44762306a36Sopenharmony_ci while ((pNode != NULL) && (pNode->max_ < f_min)) { 44862306a36Sopenharmony_ci pPrev = pNode; 44962306a36Sopenharmony_ci pNode = pNode->next_; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if ((pNode != NULL) && (pNode->min_ < f_max)) { 45362306a36Sopenharmony_ci /* Combine me with pNode */ 45462306a36Sopenharmony_ci if (f_min < pNode->min_) 45562306a36Sopenharmony_ci pNode->min_ = f_min; 45662306a36Sopenharmony_ci if (f_max > pNode->max_) 45762306a36Sopenharmony_ci pNode->max_ = f_max; 45862306a36Sopenharmony_ci } else { 45962306a36Sopenharmony_ci pNode = InsertNode(pAS_Info, pPrev); 46062306a36Sopenharmony_ci pNode->min_ = f_min; 46162306a36Sopenharmony_ci pNode->max_ = f_max; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* Look for merging possibilities */ 46562306a36Sopenharmony_ci pNext = pNode->next_; 46662306a36Sopenharmony_ci while ((pNext != NULL) && (pNext->min_ < pNode->max_)) { 46762306a36Sopenharmony_ci if (pNext->max_ > pNode->max_) 46862306a36Sopenharmony_ci pNode->max_ = pNext->max_; 46962306a36Sopenharmony_ci /* Remove pNext, return ptr to pNext->next */ 47062306a36Sopenharmony_ci pNext = RemoveNode(pAS_Info, pNode, pNext); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/* 47662306a36Sopenharmony_ci * Reset all exclusion zones. 47762306a36Sopenharmony_ci * Add zones to protect the PLL FracN regions near zero 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_cistatic void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci u32 center; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci dprintk(2, "\n"); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci pAS_Info->nZones = 0; /* this clears the used list */ 48662306a36Sopenharmony_ci pAS_Info->usedZones = NULL; /* reset ptr */ 48762306a36Sopenharmony_ci pAS_Info->freeZones = NULL; /* reset ptr */ 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci center = 49062306a36Sopenharmony_ci pAS_Info->f_ref * 49162306a36Sopenharmony_ci ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 + 49262306a36Sopenharmony_ci pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in; 49362306a36Sopenharmony_ci while (center < 49462306a36Sopenharmony_ci pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + 49562306a36Sopenharmony_ci pAS_Info->f_LO1_FracN_Avoid) { 49662306a36Sopenharmony_ci /* Exclude LO1 FracN */ 49762306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 49862306a36Sopenharmony_ci center - pAS_Info->f_LO1_FracN_Avoid, 49962306a36Sopenharmony_ci center - 1); 50062306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, center + 1, 50162306a36Sopenharmony_ci center + pAS_Info->f_LO1_FracN_Avoid); 50262306a36Sopenharmony_ci center += pAS_Info->f_ref; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci center = 50662306a36Sopenharmony_ci pAS_Info->f_ref * 50762306a36Sopenharmony_ci ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 - 50862306a36Sopenharmony_ci pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out; 50962306a36Sopenharmony_ci while (center < 51062306a36Sopenharmony_ci pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + 51162306a36Sopenharmony_ci pAS_Info->f_LO2_FracN_Avoid) { 51262306a36Sopenharmony_ci /* Exclude LO2 FracN */ 51362306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 51462306a36Sopenharmony_ci center - pAS_Info->f_LO2_FracN_Avoid, 51562306a36Sopenharmony_ci center - 1); 51662306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, center + 1, 51762306a36Sopenharmony_ci center + pAS_Info->f_LO2_FracN_Avoid); 51862306a36Sopenharmony_ci center += pAS_Info->f_ref; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { 52262306a36Sopenharmony_ci /* Exclude LO1 values that conflict with DECT channels */ 52362306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */ 52462306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */ 52562306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */ 52662306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */ 52762306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */ 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { 53162306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */ 53262306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */ 53362306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */ 53462306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */ 53562306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */ 53662306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */ 53762306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */ 53862306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */ 53962306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */ 54062306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */ 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/* 54562306a36Sopenharmony_ci * MT_ChooseFirstIF - Choose the best available 1st IF 54662306a36Sopenharmony_ci * If f_Desired is not excluded, choose that first. 54762306a36Sopenharmony_ci * Otherwise, return the value closest to f_Center that is 54862306a36Sopenharmony_ci * not excluded 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_cistatic u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci /* 55362306a36Sopenharmony_ci * Update "f_Desired" to be the nearest "combinational-multiple" of 55462306a36Sopenharmony_ci * "f_LO1_Step". 55562306a36Sopenharmony_ci * The resulting number, F_LO1 must be a multiple of f_LO1_Step. 55662306a36Sopenharmony_ci * And F_LO1 is the arithmetic sum of f_in + f_Center. 55762306a36Sopenharmony_ci * Neither f_in, nor f_Center must be a multiple of f_LO1_Step. 55862306a36Sopenharmony_ci * However, the sum must be. 55962306a36Sopenharmony_ci */ 56062306a36Sopenharmony_ci const u32 f_Desired = 56162306a36Sopenharmony_ci pAS_Info->f_LO1_Step * 56262306a36Sopenharmony_ci ((pAS_Info->f_if1_Request + pAS_Info->f_in + 56362306a36Sopenharmony_ci pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) - 56462306a36Sopenharmony_ci pAS_Info->f_in; 56562306a36Sopenharmony_ci const u32 f_Step = 56662306a36Sopenharmony_ci (pAS_Info->f_LO1_Step > 56762306a36Sopenharmony_ci pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info-> 56862306a36Sopenharmony_ci f_LO2_Step; 56962306a36Sopenharmony_ci u32 f_Center; 57062306a36Sopenharmony_ci s32 i; 57162306a36Sopenharmony_ci s32 j = 0; 57262306a36Sopenharmony_ci u32 bDesiredExcluded = 0; 57362306a36Sopenharmony_ci u32 bZeroExcluded = 0; 57462306a36Sopenharmony_ci s32 tmpMin, tmpMax; 57562306a36Sopenharmony_ci s32 bestDiff; 57662306a36Sopenharmony_ci struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; 57762306a36Sopenharmony_ci struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES]; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci dprintk(2, "\n"); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (pAS_Info->nZones == 0) 58262306a36Sopenharmony_ci return f_Desired; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* 58562306a36Sopenharmony_ci * f_Center needs to be an integer multiple of f_Step away 58662306a36Sopenharmony_ci * from f_Desired 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ci if (pAS_Info->f_if1_Center > f_Desired) 58962306a36Sopenharmony_ci f_Center = 59062306a36Sopenharmony_ci f_Desired + 59162306a36Sopenharmony_ci f_Step * 59262306a36Sopenharmony_ci ((pAS_Info->f_if1_Center - f_Desired + 59362306a36Sopenharmony_ci f_Step / 2) / f_Step); 59462306a36Sopenharmony_ci else 59562306a36Sopenharmony_ci f_Center = 59662306a36Sopenharmony_ci f_Desired - 59762306a36Sopenharmony_ci f_Step * 59862306a36Sopenharmony_ci ((f_Desired - pAS_Info->f_if1_Center + 59962306a36Sopenharmony_ci f_Step / 2) / f_Step); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* 60262306a36Sopenharmony_ci * Take MT_ExclZones, center around f_Center and change the 60362306a36Sopenharmony_ci * resolution to f_Step 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci while (pNode != NULL) { 60662306a36Sopenharmony_ci /* floor function */ 60762306a36Sopenharmony_ci tmpMin = 60862306a36Sopenharmony_ci floor((s32) (pNode->min_ - f_Center), (s32) f_Step); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* ceil function */ 61162306a36Sopenharmony_ci tmpMax = 61262306a36Sopenharmony_ci ceil((s32) (pNode->max_ - f_Center), (s32) f_Step); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired)) 61562306a36Sopenharmony_ci bDesiredExcluded = 1; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if ((tmpMin < 0) && (tmpMax > 0)) 61862306a36Sopenharmony_ci bZeroExcluded = 1; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* See if this zone overlaps the previous */ 62162306a36Sopenharmony_ci if ((j > 0) && (tmpMin < zones[j - 1].max_)) 62262306a36Sopenharmony_ci zones[j - 1].max_ = tmpMax; 62362306a36Sopenharmony_ci else { 62462306a36Sopenharmony_ci /* Add new zone */ 62562306a36Sopenharmony_ci zones[j].min_ = tmpMin; 62662306a36Sopenharmony_ci zones[j].max_ = tmpMax; 62762306a36Sopenharmony_ci j++; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci pNode = pNode->next_; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* 63362306a36Sopenharmony_ci * If the desired is okay, return with it 63462306a36Sopenharmony_ci */ 63562306a36Sopenharmony_ci if (bDesiredExcluded == 0) 63662306a36Sopenharmony_ci return f_Desired; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* 63962306a36Sopenharmony_ci * If the desired is excluded and the center is okay, return with it 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ci if (bZeroExcluded == 0) 64262306a36Sopenharmony_ci return f_Center; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Find the value closest to 0 (f_Center) */ 64562306a36Sopenharmony_ci bestDiff = zones[0].min_; 64662306a36Sopenharmony_ci for (i = 0; i < j; i++) { 64762306a36Sopenharmony_ci if (abs(zones[i].min_) < abs(bestDiff)) 64862306a36Sopenharmony_ci bestDiff = zones[i].min_; 64962306a36Sopenharmony_ci if (abs(zones[i].max_) < abs(bestDiff)) 65062306a36Sopenharmony_ci bestDiff = zones[i].max_; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (bestDiff < 0) 65462306a36Sopenharmony_ci return f_Center - ((u32) (-bestDiff) * f_Step); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return f_Center + (bestDiff * f_Step); 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/** 66062306a36Sopenharmony_ci * IsSpurInBand() - Checks to see if a spur will be present within the IF's 66162306a36Sopenharmony_ci * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) 66262306a36Sopenharmony_ci * 66362306a36Sopenharmony_ci * ma mb mc md 66462306a36Sopenharmony_ci * <--+-+-+-------------------+-------------------+-+-+--> 66562306a36Sopenharmony_ci * | ^ 0 ^ | 66662306a36Sopenharmony_ci * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ 66762306a36Sopenharmony_ci * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 66862306a36Sopenharmony_ci * 66962306a36Sopenharmony_ci * Note that some equations are doubled to prevent round-off 67062306a36Sopenharmony_ci * problems when calculating fIFBW/2 67162306a36Sopenharmony_ci * 67262306a36Sopenharmony_ci * @pAS_Info: Avoid Spurs information block 67362306a36Sopenharmony_ci * @fm: If spur, amount f_IF1 has to move negative 67462306a36Sopenharmony_ci * @fp: If spur, amount f_IF1 has to move positive 67562306a36Sopenharmony_ci * 67662306a36Sopenharmony_ci * Returns 1 if an LO spur would be present, otherwise 0. 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_cistatic u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, 67962306a36Sopenharmony_ci u32 *fm, u32 * fp) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci /* 68262306a36Sopenharmony_ci ** Calculate LO frequency settings. 68362306a36Sopenharmony_ci */ 68462306a36Sopenharmony_ci u32 n, n0; 68562306a36Sopenharmony_ci const u32 f_LO1 = pAS_Info->f_LO1; 68662306a36Sopenharmony_ci const u32 f_LO2 = pAS_Info->f_LO2; 68762306a36Sopenharmony_ci const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2; 68862306a36Sopenharmony_ci const u32 c = d - pAS_Info->f_out_bw; 68962306a36Sopenharmony_ci const u32 f = pAS_Info->f_zif_bw / 2; 69062306a36Sopenharmony_ci const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1; 69162306a36Sopenharmony_ci s32 f_nsLO1, f_nsLO2; 69262306a36Sopenharmony_ci s32 f_Spur; 69362306a36Sopenharmony_ci u32 ma, mb, mc, md, me, mf; 69462306a36Sopenharmony_ci u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci dprintk(2, "\n"); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci *fm = 0; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* 70162306a36Sopenharmony_ci ** For each edge (d, c & f), calculate a scale, based on the gcd 70262306a36Sopenharmony_ci ** of f_LO1, f_LO2 and the edge value. Use the larger of this 70362306a36Sopenharmony_ci ** gcd-based scale factor or f_Scale. 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci lo_gcd = gcd(f_LO1, f_LO2); 70662306a36Sopenharmony_ci gd_Scale = max((u32) gcd(lo_gcd, d), f_Scale); 70762306a36Sopenharmony_ci hgds = gd_Scale / 2; 70862306a36Sopenharmony_ci gc_Scale = max((u32) gcd(lo_gcd, c), f_Scale); 70962306a36Sopenharmony_ci hgcs = gc_Scale / 2; 71062306a36Sopenharmony_ci gf_Scale = max((u32) gcd(lo_gcd, f), f_Scale); 71162306a36Sopenharmony_ci hgfs = gf_Scale / 2; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */ 71662306a36Sopenharmony_ci for (n = n0; n <= pAS_Info->maxH1; ++n) { 71762306a36Sopenharmony_ci md = (n * ((f_LO1 + hgds) / gd_Scale) - 71862306a36Sopenharmony_ci ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */ 72162306a36Sopenharmony_ci if (md >= pAS_Info->maxH1) 72262306a36Sopenharmony_ci break; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci ma = (n * ((f_LO1 + hgds) / gd_Scale) + 72562306a36Sopenharmony_ci ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */ 72862306a36Sopenharmony_ci if (md == ma) 72962306a36Sopenharmony_ci continue; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci mc = (n * ((f_LO1 + hgcs) / gc_Scale) - 73262306a36Sopenharmony_ci ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); 73362306a36Sopenharmony_ci if (mc != md) { 73462306a36Sopenharmony_ci f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale)); 73562306a36Sopenharmony_ci f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale)); 73662306a36Sopenharmony_ci f_Spur = 73762306a36Sopenharmony_ci (gc_Scale * (f_nsLO1 - f_nsLO2)) + 73862306a36Sopenharmony_ci n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci *fp = ((f_Spur - (s32) c) / (mc - n)) + 1; 74162306a36Sopenharmony_ci *fm = (((s32) d - f_Spur) / (mc - n)) + 1; 74262306a36Sopenharmony_ci return 1; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* Location of Zero-IF-spur to be checked */ 74662306a36Sopenharmony_ci me = (n * ((f_LO1 + hgfs) / gf_Scale) + 74762306a36Sopenharmony_ci ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); 74862306a36Sopenharmony_ci mf = (n * ((f_LO1 + hgfs) / gf_Scale) - 74962306a36Sopenharmony_ci ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); 75062306a36Sopenharmony_ci if (me != mf) { 75162306a36Sopenharmony_ci f_nsLO1 = n * (f_LO1 / gf_Scale); 75262306a36Sopenharmony_ci f_nsLO2 = me * (f_LO2 / gf_Scale); 75362306a36Sopenharmony_ci f_Spur = 75462306a36Sopenharmony_ci (gf_Scale * (f_nsLO1 - f_nsLO2)) + 75562306a36Sopenharmony_ci n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci *fp = ((f_Spur + (s32) f) / (me - n)) + 1; 75862306a36Sopenharmony_ci *fm = (((s32) f - f_Spur) / (me - n)) + 1; 75962306a36Sopenharmony_ci return 1; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci mb = (n * ((f_LO1 + hgcs) / gc_Scale) + 76362306a36Sopenharmony_ci ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); 76462306a36Sopenharmony_ci if (ma != mb) { 76562306a36Sopenharmony_ci f_nsLO1 = n * (f_LO1 / gc_Scale); 76662306a36Sopenharmony_ci f_nsLO2 = ma * (f_LO2 / gc_Scale); 76762306a36Sopenharmony_ci f_Spur = 76862306a36Sopenharmony_ci (gc_Scale * (f_nsLO1 - f_nsLO2)) + 76962306a36Sopenharmony_ci n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci *fp = (((s32) d + f_Spur) / (ma - n)) + 1; 77262306a36Sopenharmony_ci *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1; 77362306a36Sopenharmony_ci return 1; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* No spurs found */ 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci/* 78262306a36Sopenharmony_ci * MT_AvoidSpurs() - Main entry point to avoid spurs. 78362306a36Sopenharmony_ci * Checks for existing spurs in present LO1, LO2 freqs 78462306a36Sopenharmony_ci * and if present, chooses spur-free LO1, LO2 combination 78562306a36Sopenharmony_ci * that tunes the same input/output frequencies. 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_cistatic u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci int status = 0; 79062306a36Sopenharmony_ci u32 fm, fp; /* restricted range on LO's */ 79162306a36Sopenharmony_ci pAS_Info->bSpurAvoided = 0; 79262306a36Sopenharmony_ci pAS_Info->nSpursFound = 0; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci dprintk(2, "\n"); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (pAS_Info->maxH1 == 0) 79762306a36Sopenharmony_ci return 0; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* 80062306a36Sopenharmony_ci * Avoid LO Generated Spurs 80162306a36Sopenharmony_ci * 80262306a36Sopenharmony_ci * Make sure that have no LO-related spurs within the IF output 80362306a36Sopenharmony_ci * bandwidth. 80462306a36Sopenharmony_ci * 80562306a36Sopenharmony_ci * If there is an LO spur in this band, start at the current IF1 frequency 80662306a36Sopenharmony_ci * and work out until we find a spur-free frequency or run up against the 80762306a36Sopenharmony_ci * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they 80862306a36Sopenharmony_ci * will be unchanged if a spur-free setting is not found. 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_ci pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); 81162306a36Sopenharmony_ci if (pAS_Info->bSpurPresent) { 81262306a36Sopenharmony_ci u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */ 81362306a36Sopenharmony_ci u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */ 81462306a36Sopenharmony_ci u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */ 81562306a36Sopenharmony_ci u32 delta_IF1; 81662306a36Sopenharmony_ci u32 new_IF1; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* 81962306a36Sopenharmony_ci ** Spur was found, attempt to find a spur-free 1st IF 82062306a36Sopenharmony_ci */ 82162306a36Sopenharmony_ci do { 82262306a36Sopenharmony_ci pAS_Info->nSpursFound++; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci /* Raise f_IF1_upper, if needed */ 82562306a36Sopenharmony_ci MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* Choose next IF1 that is closest to f_IF1_CENTER */ 82862306a36Sopenharmony_ci new_IF1 = MT2063_ChooseFirstIF(pAS_Info); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (new_IF1 > zfIF1) { 83162306a36Sopenharmony_ci pAS_Info->f_LO1 += (new_IF1 - zfIF1); 83262306a36Sopenharmony_ci pAS_Info->f_LO2 += (new_IF1 - zfIF1); 83362306a36Sopenharmony_ci } else { 83462306a36Sopenharmony_ci pAS_Info->f_LO1 -= (zfIF1 - new_IF1); 83562306a36Sopenharmony_ci pAS_Info->f_LO2 -= (zfIF1 - new_IF1); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci zfIF1 = new_IF1; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (zfIF1 > pAS_Info->f_if1_Center) 84062306a36Sopenharmony_ci delta_IF1 = zfIF1 - pAS_Info->f_if1_Center; 84162306a36Sopenharmony_ci else 84262306a36Sopenharmony_ci delta_IF1 = pAS_Info->f_if1_Center - zfIF1; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); 84562306a36Sopenharmony_ci /* 84662306a36Sopenharmony_ci * Continue while the new 1st IF is still within the 1st IF bandwidth 84762306a36Sopenharmony_ci * and there is a spur in the band (again) 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_ci } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* 85262306a36Sopenharmony_ci * Use the LO-spur free values found. If the search went all 85362306a36Sopenharmony_ci * the way to the 1st IF band edge and always found spurs, just 85462306a36Sopenharmony_ci * leave the original choice. It's as "good" as any other. 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ci if (pAS_Info->bSpurPresent == 1) { 85762306a36Sopenharmony_ci status |= MT2063_SPUR_PRESENT_ERR; 85862306a36Sopenharmony_ci pAS_Info->f_LO1 = zfLO1; 85962306a36Sopenharmony_ci pAS_Info->f_LO2 = zfLO2; 86062306a36Sopenharmony_ci } else 86162306a36Sopenharmony_ci pAS_Info->bSpurAvoided = 1; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci status |= 86562306a36Sopenharmony_ci ((pAS_Info-> 86662306a36Sopenharmony_ci nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci return status; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci/* 87262306a36Sopenharmony_ci * Constants used by the tuning algorithm 87362306a36Sopenharmony_ci */ 87462306a36Sopenharmony_ci#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */ 87562306a36Sopenharmony_ci#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */ 87662306a36Sopenharmony_ci#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */ 87762306a36Sopenharmony_ci#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */ 87862306a36Sopenharmony_ci#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */ 87962306a36Sopenharmony_ci#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */ 88062306a36Sopenharmony_ci#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */ 88162306a36Sopenharmony_ci#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */ 88262306a36Sopenharmony_ci#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */ 88362306a36Sopenharmony_ci#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */ 88462306a36Sopenharmony_ci#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */ 88562306a36Sopenharmony_ci#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */ 88662306a36Sopenharmony_ci#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */ 88762306a36Sopenharmony_ci#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */ 88862306a36Sopenharmony_ci#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */ 88962306a36Sopenharmony_ci#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */ 89062306a36Sopenharmony_ci#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */ 89162306a36Sopenharmony_ci#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */ 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci/* 89462306a36Sopenharmony_ci * Define the supported Part/Rev codes for the MT2063 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci#define MT2063_B0 (0x9B) 89762306a36Sopenharmony_ci#define MT2063_B1 (0x9C) 89862306a36Sopenharmony_ci#define MT2063_B2 (0x9D) 89962306a36Sopenharmony_ci#define MT2063_B3 (0x9E) 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci/** 90262306a36Sopenharmony_ci * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked 90362306a36Sopenharmony_ci * 90462306a36Sopenharmony_ci * @state: struct mt2063_state pointer 90562306a36Sopenharmony_ci * 90662306a36Sopenharmony_ci * This function returns 0, if no lock, 1 if locked and a value < 1 if error 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_cistatic int mt2063_lockStatus(struct mt2063_state *state) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ 91162306a36Sopenharmony_ci const u32 nPollRate = 2; /* poll status bits every 2 ms */ 91262306a36Sopenharmony_ci const u32 nMaxLoops = nMaxWait / nPollRate; 91362306a36Sopenharmony_ci const u8 LO1LK = 0x80; 91462306a36Sopenharmony_ci u8 LO2LK = 0x08; 91562306a36Sopenharmony_ci int status; 91662306a36Sopenharmony_ci u32 nDelays = 0; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci dprintk(2, "\n"); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* LO2 Lock bit was in a different place for B0 version */ 92162306a36Sopenharmony_ci if (state->tuner_id == MT2063_B0) 92262306a36Sopenharmony_ci LO2LK = 0x40; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci do { 92562306a36Sopenharmony_ci status = mt2063_read(state, MT2063_REG_LO_STATUS, 92662306a36Sopenharmony_ci &state->reg[MT2063_REG_LO_STATUS], 1); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (status < 0) 92962306a36Sopenharmony_ci return status; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) == 93262306a36Sopenharmony_ci (LO1LK | LO2LK)) { 93362306a36Sopenharmony_ci return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci msleep(nPollRate); /* Wait between retries */ 93662306a36Sopenharmony_ci } while (++nDelays < nMaxLoops); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* 93962306a36Sopenharmony_ci * Got no lock or partial lock 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_ci return 0; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci/* 94562306a36Sopenharmony_ci * Constants for setting receiver modes. 94662306a36Sopenharmony_ci * (6 modes defined at this time, enumerated by mt2063_delivery_sys) 94762306a36Sopenharmony_ci * (DNC1GC & DNC2GC are the values, which are used, when the specific 94862306a36Sopenharmony_ci * DNC Output is selected, the other is always off) 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * enum mt2063_delivery_sys 95162306a36Sopenharmony_ci * -------------+---------------------------------------------- 95262306a36Sopenharmony_ci * Mode 0 : | MT2063_CABLE_QAM 95362306a36Sopenharmony_ci * Mode 1 : | MT2063_CABLE_ANALOG 95462306a36Sopenharmony_ci * Mode 2 : | MT2063_OFFAIR_COFDM 95562306a36Sopenharmony_ci * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS 95662306a36Sopenharmony_ci * Mode 4 : | MT2063_OFFAIR_ANALOG 95762306a36Sopenharmony_ci * Mode 5 : | MT2063_OFFAIR_8VSB 95862306a36Sopenharmony_ci * --------------+---------------------------------------------- 95962306a36Sopenharmony_ci * 96062306a36Sopenharmony_ci * |<---------- Mode -------------->| 96162306a36Sopenharmony_ci * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | 96262306a36Sopenharmony_ci * ------------+-----+-----+-----+-----+-----+-----+ 96362306a36Sopenharmony_ci * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF 96462306a36Sopenharmony_ci * LNARin | 0 | 0 | 3 | 3 | 3 | 3 96562306a36Sopenharmony_ci * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 96662306a36Sopenharmony_ci * FIFFq | 0 | 0 | 0 | 0 | 0 | 0 96762306a36Sopenharmony_ci * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 96862306a36Sopenharmony_ci * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 96962306a36Sopenharmony_ci * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 97062306a36Sopenharmony_ci * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 97162306a36Sopenharmony_ci * LNA Target | 44 | 43 | 43 | 43 | 43 | 43 97262306a36Sopenharmony_ci * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 97362306a36Sopenharmony_ci * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 97462306a36Sopenharmony_ci * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 97562306a36Sopenharmony_ci * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 97662306a36Sopenharmony_ci * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 97762306a36Sopenharmony_ci * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 97862306a36Sopenharmony_ci */ 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cienum mt2063_delivery_sys { 98162306a36Sopenharmony_ci MT2063_CABLE_QAM = 0, 98262306a36Sopenharmony_ci MT2063_CABLE_ANALOG, 98362306a36Sopenharmony_ci MT2063_OFFAIR_COFDM, 98462306a36Sopenharmony_ci MT2063_OFFAIR_COFDM_SAWLESS, 98562306a36Sopenharmony_ci MT2063_OFFAIR_ANALOG, 98662306a36Sopenharmony_ci MT2063_OFFAIR_8VSB, 98762306a36Sopenharmony_ci MT2063_NUM_RCVR_MODES 98862306a36Sopenharmony_ci}; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic const char *mt2063_mode_name[] = { 99162306a36Sopenharmony_ci [MT2063_CABLE_QAM] = "digital cable", 99262306a36Sopenharmony_ci [MT2063_CABLE_ANALOG] = "analog cable", 99362306a36Sopenharmony_ci [MT2063_OFFAIR_COFDM] = "digital offair", 99462306a36Sopenharmony_ci [MT2063_OFFAIR_COFDM_SAWLESS] = "digital offair without SAW", 99562306a36Sopenharmony_ci [MT2063_OFFAIR_ANALOG] = "analog offair", 99662306a36Sopenharmony_ci [MT2063_OFFAIR_8VSB] = "analog offair 8vsb", 99762306a36Sopenharmony_ci}; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 }; 100062306a36Sopenharmony_cistatic const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 }; 100162306a36Sopenharmony_cistatic const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 }; 100262306a36Sopenharmony_cistatic const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 }; 100362306a36Sopenharmony_cistatic const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 }; 100462306a36Sopenharmony_cistatic const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 }; 100562306a36Sopenharmony_cistatic const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 }; 100662306a36Sopenharmony_cistatic const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 }; 100762306a36Sopenharmony_cistatic const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; 100862306a36Sopenharmony_cistatic const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 }; 100962306a36Sopenharmony_cistatic const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 }; 101062306a36Sopenharmony_cistatic const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; 101162306a36Sopenharmony_cistatic const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 }; 101262306a36Sopenharmony_cistatic const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 }; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci/* 101562306a36Sopenharmony_ci * mt2063_set_dnc_output_enable() 101662306a36Sopenharmony_ci */ 101762306a36Sopenharmony_cistatic u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, 101862306a36Sopenharmony_ci enum MT2063_DNC_Output_Enable *pValue) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci dprintk(2, "\n"); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */ 102362306a36Sopenharmony_ci if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ 102462306a36Sopenharmony_ci *pValue = MT2063_DNC_NONE; 102562306a36Sopenharmony_ci else 102662306a36Sopenharmony_ci *pValue = MT2063_DNC_2; 102762306a36Sopenharmony_ci } else { /* DNC1 is on */ 102862306a36Sopenharmony_ci if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ 102962306a36Sopenharmony_ci *pValue = MT2063_DNC_1; 103062306a36Sopenharmony_ci else 103162306a36Sopenharmony_ci *pValue = MT2063_DNC_BOTH; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci return 0; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci/* 103762306a36Sopenharmony_ci * mt2063_set_dnc_output_enable() 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_cistatic u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, 104062306a36Sopenharmony_ci enum MT2063_DNC_Output_Enable nValue) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci int status = 0; /* Status to be returned */ 104362306a36Sopenharmony_ci u8 val = 0; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci dprintk(2, "\n"); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* selects, which DNC output is used */ 104862306a36Sopenharmony_ci switch (nValue) { 104962306a36Sopenharmony_ci case MT2063_DNC_NONE: 105062306a36Sopenharmony_ci val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ 105162306a36Sopenharmony_ci if (state->reg[MT2063_REG_DNC_GAIN] != 105262306a36Sopenharmony_ci val) 105362306a36Sopenharmony_ci status |= 105462306a36Sopenharmony_ci mt2063_setreg(state, 105562306a36Sopenharmony_ci MT2063_REG_DNC_GAIN, 105662306a36Sopenharmony_ci val); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ 105962306a36Sopenharmony_ci if (state->reg[MT2063_REG_VGA_GAIN] != 106062306a36Sopenharmony_ci val) 106162306a36Sopenharmony_ci status |= 106262306a36Sopenharmony_ci mt2063_setreg(state, 106362306a36Sopenharmony_ci MT2063_REG_VGA_GAIN, 106462306a36Sopenharmony_ci val); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ 106762306a36Sopenharmony_ci if (state->reg[MT2063_REG_RSVD_20] != 106862306a36Sopenharmony_ci val) 106962306a36Sopenharmony_ci status |= 107062306a36Sopenharmony_ci mt2063_setreg(state, 107162306a36Sopenharmony_ci MT2063_REG_RSVD_20, 107262306a36Sopenharmony_ci val); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci break; 107562306a36Sopenharmony_ci case MT2063_DNC_1: 107662306a36Sopenharmony_ci val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ 107762306a36Sopenharmony_ci if (state->reg[MT2063_REG_DNC_GAIN] != 107862306a36Sopenharmony_ci val) 107962306a36Sopenharmony_ci status |= 108062306a36Sopenharmony_ci mt2063_setreg(state, 108162306a36Sopenharmony_ci MT2063_REG_DNC_GAIN, 108262306a36Sopenharmony_ci val); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ 108562306a36Sopenharmony_ci if (state->reg[MT2063_REG_VGA_GAIN] != 108662306a36Sopenharmony_ci val) 108762306a36Sopenharmony_ci status |= 108862306a36Sopenharmony_ci mt2063_setreg(state, 108962306a36Sopenharmony_ci MT2063_REG_VGA_GAIN, 109062306a36Sopenharmony_ci val); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ 109362306a36Sopenharmony_ci if (state->reg[MT2063_REG_RSVD_20] != 109462306a36Sopenharmony_ci val) 109562306a36Sopenharmony_ci status |= 109662306a36Sopenharmony_ci mt2063_setreg(state, 109762306a36Sopenharmony_ci MT2063_REG_RSVD_20, 109862306a36Sopenharmony_ci val); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci break; 110162306a36Sopenharmony_ci case MT2063_DNC_2: 110262306a36Sopenharmony_ci val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ 110362306a36Sopenharmony_ci if (state->reg[MT2063_REG_DNC_GAIN] != 110462306a36Sopenharmony_ci val) 110562306a36Sopenharmony_ci status |= 110662306a36Sopenharmony_ci mt2063_setreg(state, 110762306a36Sopenharmony_ci MT2063_REG_DNC_GAIN, 110862306a36Sopenharmony_ci val); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ 111162306a36Sopenharmony_ci if (state->reg[MT2063_REG_VGA_GAIN] != 111262306a36Sopenharmony_ci val) 111362306a36Sopenharmony_ci status |= 111462306a36Sopenharmony_ci mt2063_setreg(state, 111562306a36Sopenharmony_ci MT2063_REG_VGA_GAIN, 111662306a36Sopenharmony_ci val); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ 111962306a36Sopenharmony_ci if (state->reg[MT2063_REG_RSVD_20] != 112062306a36Sopenharmony_ci val) 112162306a36Sopenharmony_ci status |= 112262306a36Sopenharmony_ci mt2063_setreg(state, 112362306a36Sopenharmony_ci MT2063_REG_RSVD_20, 112462306a36Sopenharmony_ci val); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci break; 112762306a36Sopenharmony_ci case MT2063_DNC_BOTH: 112862306a36Sopenharmony_ci val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ 112962306a36Sopenharmony_ci if (state->reg[MT2063_REG_DNC_GAIN] != 113062306a36Sopenharmony_ci val) 113162306a36Sopenharmony_ci status |= 113262306a36Sopenharmony_ci mt2063_setreg(state, 113362306a36Sopenharmony_ci MT2063_REG_DNC_GAIN, 113462306a36Sopenharmony_ci val); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ 113762306a36Sopenharmony_ci if (state->reg[MT2063_REG_VGA_GAIN] != 113862306a36Sopenharmony_ci val) 113962306a36Sopenharmony_ci status |= 114062306a36Sopenharmony_ci mt2063_setreg(state, 114162306a36Sopenharmony_ci MT2063_REG_VGA_GAIN, 114262306a36Sopenharmony_ci val); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ 114562306a36Sopenharmony_ci if (state->reg[MT2063_REG_RSVD_20] != 114662306a36Sopenharmony_ci val) 114762306a36Sopenharmony_ci status |= 114862306a36Sopenharmony_ci mt2063_setreg(state, 114962306a36Sopenharmony_ci MT2063_REG_RSVD_20, 115062306a36Sopenharmony_ci val); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci default: 115462306a36Sopenharmony_ci break; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci return status; 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci/* 116162306a36Sopenharmony_ci * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with 116262306a36Sopenharmony_ci * the selected enum mt2063_delivery_sys type. 116362306a36Sopenharmony_ci * 116462306a36Sopenharmony_ci * (DNC1GC & DNC2GC are the values, which are used, when the specific 116562306a36Sopenharmony_ci * DNC Output is selected, the other is always off) 116662306a36Sopenharmony_ci * 116762306a36Sopenharmony_ci * @state: ptr to mt2063_state structure 116862306a36Sopenharmony_ci * @Mode: desired receiver delivery system 116962306a36Sopenharmony_ci * 117062306a36Sopenharmony_ci * Note: Register cache must be valid for it to work 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_cistatic u32 MT2063_SetReceiverMode(struct mt2063_state *state, 117462306a36Sopenharmony_ci enum mt2063_delivery_sys Mode) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci int status = 0; /* Status to be returned */ 117762306a36Sopenharmony_ci u8 val; 117862306a36Sopenharmony_ci u32 longval; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci dprintk(2, "\n"); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (Mode >= MT2063_NUM_RCVR_MODES) 118362306a36Sopenharmony_ci status = -ERANGE; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci /* RFAGCen */ 118662306a36Sopenharmony_ci if (status >= 0) { 118762306a36Sopenharmony_ci val = 118862306a36Sopenharmony_ci (state-> 118962306a36Sopenharmony_ci reg[MT2063_REG_PD1_TGT] & ~0x40) | (RFAGCEN[Mode] 119062306a36Sopenharmony_ci ? 0x40 : 119162306a36Sopenharmony_ci 0x00); 119262306a36Sopenharmony_ci if (state->reg[MT2063_REG_PD1_TGT] != val) 119362306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci /* LNARin */ 119762306a36Sopenharmony_ci if (status >= 0) { 119862306a36Sopenharmony_ci u8 val = (state->reg[MT2063_REG_CTRL_2C] & ~0x03) | 119962306a36Sopenharmony_ci (LNARIN[Mode] & 0x03); 120062306a36Sopenharmony_ci if (state->reg[MT2063_REG_CTRL_2C] != val) 120162306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* FIFFQEN and FIFFQ */ 120562306a36Sopenharmony_ci if (status >= 0) { 120662306a36Sopenharmony_ci val = 120762306a36Sopenharmony_ci (state-> 120862306a36Sopenharmony_ci reg[MT2063_REG_FIFF_CTRL2] & ~0xF0) | 120962306a36Sopenharmony_ci (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); 121062306a36Sopenharmony_ci if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { 121162306a36Sopenharmony_ci status |= 121262306a36Sopenharmony_ci mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); 121362306a36Sopenharmony_ci /* trigger FIFF calibration, needed after changing FIFFQ */ 121462306a36Sopenharmony_ci val = 121562306a36Sopenharmony_ci (state->reg[MT2063_REG_FIFF_CTRL] | 0x01); 121662306a36Sopenharmony_ci status |= 121762306a36Sopenharmony_ci mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); 121862306a36Sopenharmony_ci val = 121962306a36Sopenharmony_ci (state-> 122062306a36Sopenharmony_ci reg[MT2063_REG_FIFF_CTRL] & ~0x01); 122162306a36Sopenharmony_ci status |= 122262306a36Sopenharmony_ci mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* DNC1GC & DNC2GC */ 122762306a36Sopenharmony_ci status |= mt2063_get_dnc_output_enable(state, &longval); 122862306a36Sopenharmony_ci status |= mt2063_set_dnc_output_enable(state, longval); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci /* acLNAmax */ 123162306a36Sopenharmony_ci if (status >= 0) { 123262306a36Sopenharmony_ci u8 val = (state->reg[MT2063_REG_LNA_OV] & ~0x1F) | 123362306a36Sopenharmony_ci (ACLNAMAX[Mode] & 0x1F); 123462306a36Sopenharmony_ci if (state->reg[MT2063_REG_LNA_OV] != val) 123562306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci /* LNATGT */ 123962306a36Sopenharmony_ci if (status >= 0) { 124062306a36Sopenharmony_ci u8 val = (state->reg[MT2063_REG_LNA_TGT] & ~0x3F) | 124162306a36Sopenharmony_ci (LNATGT[Mode] & 0x3F); 124262306a36Sopenharmony_ci if (state->reg[MT2063_REG_LNA_TGT] != val) 124362306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci /* ACRF */ 124762306a36Sopenharmony_ci if (status >= 0) { 124862306a36Sopenharmony_ci u8 val = (state->reg[MT2063_REG_RF_OV] & ~0x1F) | 124962306a36Sopenharmony_ci (ACRFMAX[Mode] & 0x1F); 125062306a36Sopenharmony_ci if (state->reg[MT2063_REG_RF_OV] != val) 125162306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci /* PD1TGT */ 125562306a36Sopenharmony_ci if (status >= 0) { 125662306a36Sopenharmony_ci u8 val = (state->reg[MT2063_REG_PD1_TGT] & ~0x3F) | 125762306a36Sopenharmony_ci (PD1TGT[Mode] & 0x3F); 125862306a36Sopenharmony_ci if (state->reg[MT2063_REG_PD1_TGT] != val) 125962306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* FIFATN */ 126362306a36Sopenharmony_ci if (status >= 0) { 126462306a36Sopenharmony_ci u8 val = ACFIFMAX[Mode]; 126562306a36Sopenharmony_ci if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) 126662306a36Sopenharmony_ci val = 5; 126762306a36Sopenharmony_ci val = (state->reg[MT2063_REG_FIF_OV] & ~0x1F) | 126862306a36Sopenharmony_ci (val & 0x1F); 126962306a36Sopenharmony_ci if (state->reg[MT2063_REG_FIF_OV] != val) 127062306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci /* PD2TGT */ 127462306a36Sopenharmony_ci if (status >= 0) { 127562306a36Sopenharmony_ci u8 val = (state->reg[MT2063_REG_PD2_TGT] & ~0x3F) | 127662306a36Sopenharmony_ci (PD2TGT[Mode] & 0x3F); 127762306a36Sopenharmony_ci if (state->reg[MT2063_REG_PD2_TGT] != val) 127862306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci /* Ignore ATN Overload */ 128262306a36Sopenharmony_ci if (status >= 0) { 128362306a36Sopenharmony_ci val = (state->reg[MT2063_REG_LNA_TGT] & ~0x80) | 128462306a36Sopenharmony_ci (RFOVDIS[Mode] ? 0x80 : 0x00); 128562306a36Sopenharmony_ci if (state->reg[MT2063_REG_LNA_TGT] != val) 128662306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* Ignore FIF Overload */ 129062306a36Sopenharmony_ci if (status >= 0) { 129162306a36Sopenharmony_ci val = (state->reg[MT2063_REG_PD1_TGT] & ~0x80) | 129262306a36Sopenharmony_ci (FIFOVDIS[Mode] ? 0x80 : 0x00); 129362306a36Sopenharmony_ci if (state->reg[MT2063_REG_PD1_TGT] != val) 129462306a36Sopenharmony_ci status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (status >= 0) { 129862306a36Sopenharmony_ci state->rcvr_mode = Mode; 129962306a36Sopenharmony_ci dprintk(1, "mt2063 mode changed to %s\n", 130062306a36Sopenharmony_ci mt2063_mode_name[state->rcvr_mode]); 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci return status; 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci/* 130762306a36Sopenharmony_ci * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various 130862306a36Sopenharmony_ci * sections of the MT2063 130962306a36Sopenharmony_ci * 131062306a36Sopenharmony_ci * @Bits: Mask bits to be cleared. 131162306a36Sopenharmony_ci * 131262306a36Sopenharmony_ci * See definition of MT2063_Mask_Bits type for description 131362306a36Sopenharmony_ci * of each of the power bits. 131462306a36Sopenharmony_ci */ 131562306a36Sopenharmony_cistatic u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, 131662306a36Sopenharmony_ci enum MT2063_Mask_Bits Bits) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci int status = 0; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci dprintk(2, "\n"); 132162306a36Sopenharmony_ci Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ 132262306a36Sopenharmony_ci if ((Bits & 0xFF00) != 0) { 132362306a36Sopenharmony_ci state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8); 132462306a36Sopenharmony_ci status |= 132562306a36Sopenharmony_ci mt2063_write(state, 132662306a36Sopenharmony_ci MT2063_REG_PWR_2, 132762306a36Sopenharmony_ci &state->reg[MT2063_REG_PWR_2], 1); 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci if ((Bits & 0xFF) != 0) { 133062306a36Sopenharmony_ci state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF); 133162306a36Sopenharmony_ci status |= 133262306a36Sopenharmony_ci mt2063_write(state, 133362306a36Sopenharmony_ci MT2063_REG_PWR_1, 133462306a36Sopenharmony_ci &state->reg[MT2063_REG_PWR_1], 1); 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci return status; 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci/* 134162306a36Sopenharmony_ci * MT2063_SoftwareShutdown() - Enables or disables software shutdown function. 134262306a36Sopenharmony_ci * When Shutdown is 1, any section whose power 134362306a36Sopenharmony_ci * mask is set will be shutdown. 134462306a36Sopenharmony_ci */ 134562306a36Sopenharmony_cistatic u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci int status; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci dprintk(2, "\n"); 135062306a36Sopenharmony_ci if (Shutdown == 1) 135162306a36Sopenharmony_ci state->reg[MT2063_REG_PWR_1] |= 0x04; 135262306a36Sopenharmony_ci else 135362306a36Sopenharmony_ci state->reg[MT2063_REG_PWR_1] &= ~0x04; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci status = mt2063_write(state, 135662306a36Sopenharmony_ci MT2063_REG_PWR_1, 135762306a36Sopenharmony_ci &state->reg[MT2063_REG_PWR_1], 1); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci if (Shutdown != 1) { 136062306a36Sopenharmony_ci state->reg[MT2063_REG_BYP_CTRL] = 136162306a36Sopenharmony_ci (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40; 136262306a36Sopenharmony_ci status |= 136362306a36Sopenharmony_ci mt2063_write(state, 136462306a36Sopenharmony_ci MT2063_REG_BYP_CTRL, 136562306a36Sopenharmony_ci &state->reg[MT2063_REG_BYP_CTRL], 136662306a36Sopenharmony_ci 1); 136762306a36Sopenharmony_ci state->reg[MT2063_REG_BYP_CTRL] = 136862306a36Sopenharmony_ci (state->reg[MT2063_REG_BYP_CTRL] & 0x9F); 136962306a36Sopenharmony_ci status |= 137062306a36Sopenharmony_ci mt2063_write(state, 137162306a36Sopenharmony_ci MT2063_REG_BYP_CTRL, 137262306a36Sopenharmony_ci &state->reg[MT2063_REG_BYP_CTRL], 137362306a36Sopenharmony_ci 1); 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci return status; 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) 138062306a36Sopenharmony_ci{ 138162306a36Sopenharmony_ci return f_ref * (f_LO / f_ref) 138262306a36Sopenharmony_ci + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step); 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci/** 138662306a36Sopenharmony_ci * MT2063_fLO_FractionalTerm - Calculates the portion contributed by FracN / denom. 138762306a36Sopenharmony_ci * This function preserves maximum precision without 138862306a36Sopenharmony_ci * risk of overflow. It accurately calculates 138962306a36Sopenharmony_ci * f_ref * num / denom to within 1 HZ with fixed math. 139062306a36Sopenharmony_ci * 139162306a36Sopenharmony_ci * @f_ref: SRO frequency. 139262306a36Sopenharmony_ci * @num: Fractional portion of the multiplier 139362306a36Sopenharmony_ci * @denom: denominator portion of the ratio 139462306a36Sopenharmony_ci * 139562306a36Sopenharmony_ci * This calculation handles f_ref as two separate 14-bit fields. 139662306a36Sopenharmony_ci * Therefore, a maximum value of 2^28-1 may safely be used for f_ref. 139762306a36Sopenharmony_ci * This is the genesis of the magic number "14" and the magic mask value of 139862306a36Sopenharmony_ci * 0x03FFF. 139962306a36Sopenharmony_ci * 140062306a36Sopenharmony_ci * This routine successfully handles denom values up to and including 2^18. 140162306a36Sopenharmony_ci * Returns: f_ref * num / denom 140262306a36Sopenharmony_ci */ 140362306a36Sopenharmony_cistatic u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci u32 t1 = (f_ref >> 14) * num; 140662306a36Sopenharmony_ci u32 term1 = t1 / denom; 140762306a36Sopenharmony_ci u32 loss = t1 % denom; 140862306a36Sopenharmony_ci u32 term2 = 140962306a36Sopenharmony_ci (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom; 141062306a36Sopenharmony_ci return (term1 << 14) + term2; 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci/* 141462306a36Sopenharmony_ci * MT2063_CalcLO1Mult - Calculates Integer divider value and the numerator 141562306a36Sopenharmony_ci * value for a FracN PLL. 141662306a36Sopenharmony_ci * 141762306a36Sopenharmony_ci * This function assumes that the f_LO and f_Ref are 141862306a36Sopenharmony_ci * evenly divisible by f_LO_Step. 141962306a36Sopenharmony_ci * 142062306a36Sopenharmony_ci * @Div: OUTPUT: Whole number portion of the multiplier 142162306a36Sopenharmony_ci * @FracN: OUTPUT: Fractional portion of the multiplier 142262306a36Sopenharmony_ci * @f_LO: desired LO frequency. 142362306a36Sopenharmony_ci * @f_LO_Step: Minimum step size for the LO (in Hz). 142462306a36Sopenharmony_ci * @f_Ref: SRO frequency. 142562306a36Sopenharmony_ci * @f_Avoid: Range of PLL frequencies to avoid near integer multiples 142662306a36Sopenharmony_ci * of f_Ref (in Hz). 142762306a36Sopenharmony_ci * 142862306a36Sopenharmony_ci * Returns: Recalculated LO frequency. 142962306a36Sopenharmony_ci */ 143062306a36Sopenharmony_cistatic u32 MT2063_CalcLO1Mult(u32 *Div, 143162306a36Sopenharmony_ci u32 *FracN, 143262306a36Sopenharmony_ci u32 f_LO, 143362306a36Sopenharmony_ci u32 f_LO_Step, u32 f_Ref) 143462306a36Sopenharmony_ci{ 143562306a36Sopenharmony_ci /* Calculate the whole number portion of the divider */ 143662306a36Sopenharmony_ci *Div = f_LO / f_Ref; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci /* Calculate the numerator value (round to nearest f_LO_Step) */ 143962306a36Sopenharmony_ci *FracN = 144062306a36Sopenharmony_ci (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + 144162306a36Sopenharmony_ci (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64); 144462306a36Sopenharmony_ci} 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci/** 144762306a36Sopenharmony_ci * MT2063_CalcLO2Mult - Calculates Integer divider value and the numerator 144862306a36Sopenharmony_ci * value for a FracN PLL. 144962306a36Sopenharmony_ci * 145062306a36Sopenharmony_ci * This function assumes that the f_LO and f_Ref are 145162306a36Sopenharmony_ci * evenly divisible by f_LO_Step. 145262306a36Sopenharmony_ci * 145362306a36Sopenharmony_ci * @Div: OUTPUT: Whole number portion of the multiplier 145462306a36Sopenharmony_ci * @FracN: OUTPUT: Fractional portion of the multiplier 145562306a36Sopenharmony_ci * @f_LO: desired LO frequency. 145662306a36Sopenharmony_ci * @f_LO_Step: Minimum step size for the LO (in Hz). 145762306a36Sopenharmony_ci * @f_Ref: SRO frequency. 145862306a36Sopenharmony_ci * 145962306a36Sopenharmony_ci * Returns: Recalculated LO frequency. 146062306a36Sopenharmony_ci */ 146162306a36Sopenharmony_cistatic u32 MT2063_CalcLO2Mult(u32 *Div, 146262306a36Sopenharmony_ci u32 *FracN, 146362306a36Sopenharmony_ci u32 f_LO, 146462306a36Sopenharmony_ci u32 f_LO_Step, u32 f_Ref) 146562306a36Sopenharmony_ci{ 146662306a36Sopenharmony_ci /* Calculate the whole number portion of the divider */ 146762306a36Sopenharmony_ci *Div = f_LO / f_Ref; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci /* Calculate the numerator value (round to nearest f_LO_Step) */ 147062306a36Sopenharmony_ci *FracN = 147162306a36Sopenharmony_ci (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + 147262306a36Sopenharmony_ci (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 147562306a36Sopenharmony_ci 8191); 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci/* 147962306a36Sopenharmony_ci * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be 148062306a36Sopenharmony_ci * used for a given input frequency. 148162306a36Sopenharmony_ci * 148262306a36Sopenharmony_ci * @state: ptr to tuner data structure 148362306a36Sopenharmony_ci * @f_in: RF input center frequency (in Hz). 148462306a36Sopenharmony_ci * 148562306a36Sopenharmony_ci * Returns: ClearTune filter number (0-31) 148662306a36Sopenharmony_ci */ 148762306a36Sopenharmony_cistatic u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) 148862306a36Sopenharmony_ci{ 148962306a36Sopenharmony_ci u32 RFBand; 149062306a36Sopenharmony_ci u32 idx; /* index loop */ 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci /* 149362306a36Sopenharmony_ci ** Find RF Band setting 149462306a36Sopenharmony_ci */ 149562306a36Sopenharmony_ci RFBand = 31; /* def when f_in > all */ 149662306a36Sopenharmony_ci for (idx = 0; idx < 31; ++idx) { 149762306a36Sopenharmony_ci if (state->CTFiltMax[idx] >= f_in) { 149862306a36Sopenharmony_ci RFBand = idx; 149962306a36Sopenharmony_ci break; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci return RFBand; 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci/* 150662306a36Sopenharmony_ci * MT2063_Tune() - Change the tuner's tuned frequency to RFin. 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_cistatic u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) 150962306a36Sopenharmony_ci{ /* RF input center frequency */ 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci int status = 0; 151262306a36Sopenharmony_ci u32 LO1; /* 1st LO register value */ 151362306a36Sopenharmony_ci u32 Num1; /* Numerator for LO1 reg. value */ 151462306a36Sopenharmony_ci u32 f_IF1; /* 1st IF requested */ 151562306a36Sopenharmony_ci u32 LO2; /* 2nd LO register value */ 151662306a36Sopenharmony_ci u32 Num2; /* Numerator for LO2 reg. value */ 151762306a36Sopenharmony_ci u32 ofLO1, ofLO2; /* last time's LO frequencies */ 151862306a36Sopenharmony_ci u8 fiffc = 0x80; /* FIFF center freq from tuner */ 151962306a36Sopenharmony_ci u32 fiffof; /* Offset from FIFF center freq */ 152062306a36Sopenharmony_ci const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */ 152162306a36Sopenharmony_ci u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */ 152262306a36Sopenharmony_ci u8 val; 152362306a36Sopenharmony_ci u32 RFBand; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci dprintk(2, "\n"); 152662306a36Sopenharmony_ci /* Check the input and output frequency ranges */ 152762306a36Sopenharmony_ci if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ)) 152862306a36Sopenharmony_ci return -EINVAL; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ) 153162306a36Sopenharmony_ci || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ)) 153262306a36Sopenharmony_ci return -EINVAL; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* 153562306a36Sopenharmony_ci * Save original LO1 and LO2 register values 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_ci ofLO1 = state->AS_Data.f_LO1; 153862306a36Sopenharmony_ci ofLO2 = state->AS_Data.f_LO2; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci /* 154162306a36Sopenharmony_ci * Find and set RF Band setting 154262306a36Sopenharmony_ci */ 154362306a36Sopenharmony_ci if (state->ctfilt_sw == 1) { 154462306a36Sopenharmony_ci val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08); 154562306a36Sopenharmony_ci if (state->reg[MT2063_REG_CTUNE_CTRL] != val) { 154662306a36Sopenharmony_ci status |= 154762306a36Sopenharmony_ci mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val); 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci val = state->reg[MT2063_REG_CTUNE_OV]; 155062306a36Sopenharmony_ci RFBand = FindClearTuneFilter(state, f_in); 155162306a36Sopenharmony_ci state->reg[MT2063_REG_CTUNE_OV] = 155262306a36Sopenharmony_ci (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F) 155362306a36Sopenharmony_ci | RFBand); 155462306a36Sopenharmony_ci if (state->reg[MT2063_REG_CTUNE_OV] != val) { 155562306a36Sopenharmony_ci status |= 155662306a36Sopenharmony_ci mt2063_setreg(state, MT2063_REG_CTUNE_OV, val); 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci /* 156162306a36Sopenharmony_ci * Read the FIFF Center Frequency from the tuner 156262306a36Sopenharmony_ci */ 156362306a36Sopenharmony_ci if (status >= 0) { 156462306a36Sopenharmony_ci status |= 156562306a36Sopenharmony_ci mt2063_read(state, 156662306a36Sopenharmony_ci MT2063_REG_FIFFC, 156762306a36Sopenharmony_ci &state->reg[MT2063_REG_FIFFC], 1); 156862306a36Sopenharmony_ci fiffc = state->reg[MT2063_REG_FIFFC]; 156962306a36Sopenharmony_ci } 157062306a36Sopenharmony_ci /* 157162306a36Sopenharmony_ci * Assign in the requested values 157262306a36Sopenharmony_ci */ 157362306a36Sopenharmony_ci state->AS_Data.f_in = f_in; 157462306a36Sopenharmony_ci /* Request a 1st IF such that LO1 is on a step size */ 157562306a36Sopenharmony_ci state->AS_Data.f_if1_Request = 157662306a36Sopenharmony_ci MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in, 157762306a36Sopenharmony_ci state->AS_Data.f_LO1_Step, 157862306a36Sopenharmony_ci state->AS_Data.f_ref) - f_in; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* 158162306a36Sopenharmony_ci * Calculate frequency settings. f_IF1_FREQ + f_in is the 158262306a36Sopenharmony_ci * desired LO1 frequency 158362306a36Sopenharmony_ci */ 158462306a36Sopenharmony_ci MT2063_ResetExclZones(&state->AS_Data); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci state->AS_Data.f_LO1 = 158962306a36Sopenharmony_ci MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step, 159062306a36Sopenharmony_ci state->AS_Data.f_ref); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci state->AS_Data.f_LO2 = 159362306a36Sopenharmony_ci MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, 159462306a36Sopenharmony_ci state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci /* 159762306a36Sopenharmony_ci * Check for any LO spurs in the output bandwidth and adjust 159862306a36Sopenharmony_ci * the LO settings to avoid them if needed 159962306a36Sopenharmony_ci */ 160062306a36Sopenharmony_ci status |= MT2063_AvoidSpurs(&state->AS_Data); 160162306a36Sopenharmony_ci /* 160262306a36Sopenharmony_ci * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values. 160362306a36Sopenharmony_ci * Recalculate the LO frequencies and the values to be placed 160462306a36Sopenharmony_ci * in the tuning registers. 160562306a36Sopenharmony_ci */ 160662306a36Sopenharmony_ci state->AS_Data.f_LO1 = 160762306a36Sopenharmony_ci MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1, 160862306a36Sopenharmony_ci state->AS_Data.f_LO1_Step, state->AS_Data.f_ref); 160962306a36Sopenharmony_ci state->AS_Data.f_LO2 = 161062306a36Sopenharmony_ci MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, 161162306a36Sopenharmony_ci state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); 161262306a36Sopenharmony_ci state->AS_Data.f_LO2 = 161362306a36Sopenharmony_ci MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2, 161462306a36Sopenharmony_ci state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci /* 161762306a36Sopenharmony_ci * Check the upconverter and downconverter frequency ranges 161862306a36Sopenharmony_ci */ 161962306a36Sopenharmony_ci if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ) 162062306a36Sopenharmony_ci || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ)) 162162306a36Sopenharmony_ci status |= MT2063_UPC_RANGE; 162262306a36Sopenharmony_ci if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ) 162362306a36Sopenharmony_ci || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ)) 162462306a36Sopenharmony_ci status |= MT2063_DNC_RANGE; 162562306a36Sopenharmony_ci /* LO2 Lock bit was in a different place for B0 version */ 162662306a36Sopenharmony_ci if (state->tuner_id == MT2063_B0) 162762306a36Sopenharmony_ci LO2LK = 0x40; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci /* 163062306a36Sopenharmony_ci * If we have the same LO frequencies and we're already locked, 163162306a36Sopenharmony_ci * then skip re-programming the LO registers. 163262306a36Sopenharmony_ci */ 163362306a36Sopenharmony_ci if ((ofLO1 != state->AS_Data.f_LO1) 163462306a36Sopenharmony_ci || (ofLO2 != state->AS_Data.f_LO2) 163562306a36Sopenharmony_ci || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) != 163662306a36Sopenharmony_ci (LO1LK | LO2LK))) { 163762306a36Sopenharmony_ci /* 163862306a36Sopenharmony_ci * Calculate the FIFFOF register value 163962306a36Sopenharmony_ci * 164062306a36Sopenharmony_ci * IF1_Actual 164162306a36Sopenharmony_ci * FIFFOF = ------------ - 8 * FIFFC - 4992 164262306a36Sopenharmony_ci * f_ref/64 164362306a36Sopenharmony_ci */ 164462306a36Sopenharmony_ci fiffof = 164562306a36Sopenharmony_ci (state->AS_Data.f_LO1 - 164662306a36Sopenharmony_ci f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc - 164762306a36Sopenharmony_ci 4992; 164862306a36Sopenharmony_ci if (fiffof > 0xFF) 164962306a36Sopenharmony_ci fiffof = 0xFF; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci /* 165262306a36Sopenharmony_ci * Place all of the calculated values into the local tuner 165362306a36Sopenharmony_ci * register fields. 165462306a36Sopenharmony_ci */ 165562306a36Sopenharmony_ci if (status >= 0) { 165662306a36Sopenharmony_ci state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */ 165762306a36Sopenharmony_ci state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */ 165862306a36Sopenharmony_ci state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */ 165962306a36Sopenharmony_ci |(Num2 >> 12)); /* NUM2q (hi) */ 166062306a36Sopenharmony_ci state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */ 166162306a36Sopenharmony_ci state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */ 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci /* 166462306a36Sopenharmony_ci * Now write out the computed register values 166562306a36Sopenharmony_ci * IMPORTANT: There is a required order for writing 166662306a36Sopenharmony_ci * (0x05 must follow all the others). 166762306a36Sopenharmony_ci */ 166862306a36Sopenharmony_ci status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */ 166962306a36Sopenharmony_ci if (state->tuner_id == MT2063_B0) { 167062306a36Sopenharmony_ci /* Re-write the one-shot bits to trigger the tune operation */ 167162306a36Sopenharmony_ci status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */ 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci /* Write out the FIFF offset only if it's changing */ 167462306a36Sopenharmony_ci if (state->reg[MT2063_REG_FIFF_OFFSET] != 167562306a36Sopenharmony_ci (u8) fiffof) { 167662306a36Sopenharmony_ci state->reg[MT2063_REG_FIFF_OFFSET] = 167762306a36Sopenharmony_ci (u8) fiffof; 167862306a36Sopenharmony_ci status |= 167962306a36Sopenharmony_ci mt2063_write(state, 168062306a36Sopenharmony_ci MT2063_REG_FIFF_OFFSET, 168162306a36Sopenharmony_ci &state-> 168262306a36Sopenharmony_ci reg[MT2063_REG_FIFF_OFFSET], 168362306a36Sopenharmony_ci 1); 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci /* 168862306a36Sopenharmony_ci * Check for LO's locking 168962306a36Sopenharmony_ci */ 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci if (status < 0) 169262306a36Sopenharmony_ci return status; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci status = mt2063_lockStatus(state); 169562306a36Sopenharmony_ci if (status < 0) 169662306a36Sopenharmony_ci return status; 169762306a36Sopenharmony_ci if (!status) 169862306a36Sopenharmony_ci return -EINVAL; /* Couldn't lock */ 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci /* 170162306a36Sopenharmony_ci * If we locked OK, assign calculated data to mt2063_state structure 170262306a36Sopenharmony_ci */ 170362306a36Sopenharmony_ci state->f_IF1_actual = state->AS_Data.f_LO1 - f_in; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci return status; 170762306a36Sopenharmony_ci} 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_cistatic const u8 MT2063B0_defaults[] = { 171062306a36Sopenharmony_ci /* Reg, Value */ 171162306a36Sopenharmony_ci 0x19, 0x05, 171262306a36Sopenharmony_ci 0x1B, 0x1D, 171362306a36Sopenharmony_ci 0x1C, 0x1F, 171462306a36Sopenharmony_ci 0x1D, 0x0F, 171562306a36Sopenharmony_ci 0x1E, 0x3F, 171662306a36Sopenharmony_ci 0x1F, 0x0F, 171762306a36Sopenharmony_ci 0x20, 0x3F, 171862306a36Sopenharmony_ci 0x22, 0x21, 171962306a36Sopenharmony_ci 0x23, 0x3F, 172062306a36Sopenharmony_ci 0x24, 0x20, 172162306a36Sopenharmony_ci 0x25, 0x3F, 172262306a36Sopenharmony_ci 0x27, 0xEE, 172362306a36Sopenharmony_ci 0x2C, 0x27, /* bit at 0x20 is cleared below */ 172462306a36Sopenharmony_ci 0x30, 0x03, 172562306a36Sopenharmony_ci 0x2C, 0x07, /* bit at 0x20 is cleared here */ 172662306a36Sopenharmony_ci 0x2D, 0x87, 172762306a36Sopenharmony_ci 0x2E, 0xAA, 172862306a36Sopenharmony_ci 0x28, 0xE1, /* Set the FIFCrst bit here */ 172962306a36Sopenharmony_ci 0x28, 0xE0, /* Clear the FIFCrst bit here */ 173062306a36Sopenharmony_ci 0x00 173162306a36Sopenharmony_ci}; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ 173462306a36Sopenharmony_cistatic const u8 MT2063B1_defaults[] = { 173562306a36Sopenharmony_ci /* Reg, Value */ 173662306a36Sopenharmony_ci 0x05, 0xF0, 173762306a36Sopenharmony_ci 0x11, 0x10, /* New Enable AFCsd */ 173862306a36Sopenharmony_ci 0x19, 0x05, 173962306a36Sopenharmony_ci 0x1A, 0x6C, 174062306a36Sopenharmony_ci 0x1B, 0x24, 174162306a36Sopenharmony_ci 0x1C, 0x28, 174262306a36Sopenharmony_ci 0x1D, 0x8F, 174362306a36Sopenharmony_ci 0x1E, 0x14, 174462306a36Sopenharmony_ci 0x1F, 0x8F, 174562306a36Sopenharmony_ci 0x20, 0x57, 174662306a36Sopenharmony_ci 0x22, 0x21, /* New - ver 1.03 */ 174762306a36Sopenharmony_ci 0x23, 0x3C, /* New - ver 1.10 */ 174862306a36Sopenharmony_ci 0x24, 0x20, /* New - ver 1.03 */ 174962306a36Sopenharmony_ci 0x2C, 0x24, /* bit at 0x20 is cleared below */ 175062306a36Sopenharmony_ci 0x2D, 0x87, /* FIFFQ=0 */ 175162306a36Sopenharmony_ci 0x2F, 0xF3, 175262306a36Sopenharmony_ci 0x30, 0x0C, /* New - ver 1.11 */ 175362306a36Sopenharmony_ci 0x31, 0x1B, /* New - ver 1.11 */ 175462306a36Sopenharmony_ci 0x2C, 0x04, /* bit at 0x20 is cleared here */ 175562306a36Sopenharmony_ci 0x28, 0xE1, /* Set the FIFCrst bit here */ 175662306a36Sopenharmony_ci 0x28, 0xE0, /* Clear the FIFCrst bit here */ 175762306a36Sopenharmony_ci 0x00 175862306a36Sopenharmony_ci}; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ 176162306a36Sopenharmony_cistatic const u8 MT2063B3_defaults[] = { 176262306a36Sopenharmony_ci /* Reg, Value */ 176362306a36Sopenharmony_ci 0x05, 0xF0, 176462306a36Sopenharmony_ci 0x19, 0x3D, 176562306a36Sopenharmony_ci 0x2C, 0x24, /* bit at 0x20 is cleared below */ 176662306a36Sopenharmony_ci 0x2C, 0x04, /* bit at 0x20 is cleared here */ 176762306a36Sopenharmony_ci 0x28, 0xE1, /* Set the FIFCrst bit here */ 176862306a36Sopenharmony_ci 0x28, 0xE0, /* Clear the FIFCrst bit here */ 176962306a36Sopenharmony_ci 0x00 177062306a36Sopenharmony_ci}; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_cistatic int mt2063_init(struct dvb_frontend *fe) 177362306a36Sopenharmony_ci{ 177462306a36Sopenharmony_ci int status; 177562306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 177662306a36Sopenharmony_ci u8 all_resets = 0xF0; /* reset/load bits */ 177762306a36Sopenharmony_ci const u8 *def = NULL; 177862306a36Sopenharmony_ci char *step; 177962306a36Sopenharmony_ci u32 FCRUN; 178062306a36Sopenharmony_ci s32 maxReads; 178162306a36Sopenharmony_ci u32 fcu_osc; 178262306a36Sopenharmony_ci u32 i; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci dprintk(2, "\n"); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci state->rcvr_mode = MT2063_CABLE_QAM; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci /* Read the Part/Rev code from the tuner */ 178962306a36Sopenharmony_ci status = mt2063_read(state, MT2063_REG_PART_REV, 179062306a36Sopenharmony_ci &state->reg[MT2063_REG_PART_REV], 1); 179162306a36Sopenharmony_ci if (status < 0) { 179262306a36Sopenharmony_ci printk(KERN_ERR "Can't read mt2063 part ID\n"); 179362306a36Sopenharmony_ci return status; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci /* Check the part/rev code */ 179762306a36Sopenharmony_ci switch (state->reg[MT2063_REG_PART_REV]) { 179862306a36Sopenharmony_ci case MT2063_B0: 179962306a36Sopenharmony_ci step = "B0"; 180062306a36Sopenharmony_ci break; 180162306a36Sopenharmony_ci case MT2063_B1: 180262306a36Sopenharmony_ci step = "B1"; 180362306a36Sopenharmony_ci break; 180462306a36Sopenharmony_ci case MT2063_B2: 180562306a36Sopenharmony_ci step = "B2"; 180662306a36Sopenharmony_ci break; 180762306a36Sopenharmony_ci case MT2063_B3: 180862306a36Sopenharmony_ci step = "B3"; 180962306a36Sopenharmony_ci break; 181062306a36Sopenharmony_ci default: 181162306a36Sopenharmony_ci printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n", 181262306a36Sopenharmony_ci state->reg[MT2063_REG_PART_REV]); 181362306a36Sopenharmony_ci return -ENODEV; /* Wrong tuner Part/Rev code */ 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci /* Check the 2nd byte of the Part/Rev code from the tuner */ 181762306a36Sopenharmony_ci status = mt2063_read(state, MT2063_REG_RSVD_3B, 181862306a36Sopenharmony_ci &state->reg[MT2063_REG_RSVD_3B], 1); 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci /* b7 != 0 ==> NOT MT2063 */ 182162306a36Sopenharmony_ci if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) { 182262306a36Sopenharmony_ci printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n", 182362306a36Sopenharmony_ci state->reg[MT2063_REG_PART_REV], 182462306a36Sopenharmony_ci state->reg[MT2063_REG_RSVD_3B]); 182562306a36Sopenharmony_ci return -ENODEV; /* Wrong tuner Part/Rev code */ 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step); 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* Reset the tuner */ 183162306a36Sopenharmony_ci status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1); 183262306a36Sopenharmony_ci if (status < 0) 183362306a36Sopenharmony_ci return status; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci /* change all of the default values that vary from the HW reset values */ 183662306a36Sopenharmony_ci /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */ 183762306a36Sopenharmony_ci switch (state->reg[MT2063_REG_PART_REV]) { 183862306a36Sopenharmony_ci case MT2063_B3: 183962306a36Sopenharmony_ci def = MT2063B3_defaults; 184062306a36Sopenharmony_ci break; 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci case MT2063_B1: 184362306a36Sopenharmony_ci def = MT2063B1_defaults; 184462306a36Sopenharmony_ci break; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci case MT2063_B0: 184762306a36Sopenharmony_ci def = MT2063B0_defaults; 184862306a36Sopenharmony_ci break; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci default: 185162306a36Sopenharmony_ci return -ENODEV; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci while (status >= 0 && *def) { 185562306a36Sopenharmony_ci u8 reg = *def++; 185662306a36Sopenharmony_ci u8 val = *def++; 185762306a36Sopenharmony_ci status = mt2063_write(state, reg, &val, 1); 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci if (status < 0) 186062306a36Sopenharmony_ci return status; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci /* Wait for FIFF location to complete. */ 186362306a36Sopenharmony_ci FCRUN = 1; 186462306a36Sopenharmony_ci maxReads = 10; 186562306a36Sopenharmony_ci while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) { 186662306a36Sopenharmony_ci msleep(2); 186762306a36Sopenharmony_ci status = mt2063_read(state, 186862306a36Sopenharmony_ci MT2063_REG_XO_STATUS, 186962306a36Sopenharmony_ci &state-> 187062306a36Sopenharmony_ci reg[MT2063_REG_XO_STATUS], 1); 187162306a36Sopenharmony_ci FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci if (FCRUN != 0 || status < 0) 187562306a36Sopenharmony_ci return -ENODEV; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci status = mt2063_read(state, 187862306a36Sopenharmony_ci MT2063_REG_FIFFC, 187962306a36Sopenharmony_ci &state->reg[MT2063_REG_FIFFC], 1); 188062306a36Sopenharmony_ci if (status < 0) 188162306a36Sopenharmony_ci return status; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci /* Read back all the registers from the tuner */ 188462306a36Sopenharmony_ci status = mt2063_read(state, 188562306a36Sopenharmony_ci MT2063_REG_PART_REV, 188662306a36Sopenharmony_ci state->reg, MT2063_REG_END_REGS); 188762306a36Sopenharmony_ci if (status < 0) 188862306a36Sopenharmony_ci return status; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci /* Initialize the tuner state. */ 189162306a36Sopenharmony_ci state->tuner_id = state->reg[MT2063_REG_PART_REV]; 189262306a36Sopenharmony_ci state->AS_Data.f_ref = MT2063_REF_FREQ; 189362306a36Sopenharmony_ci state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) * 189462306a36Sopenharmony_ci ((u32) state->reg[MT2063_REG_FIFFC] + 640); 189562306a36Sopenharmony_ci state->AS_Data.f_if1_bw = MT2063_IF1_BW; 189662306a36Sopenharmony_ci state->AS_Data.f_out = 43750000UL; 189762306a36Sopenharmony_ci state->AS_Data.f_out_bw = 6750000UL; 189862306a36Sopenharmony_ci state->AS_Data.f_zif_bw = MT2063_ZIF_BW; 189962306a36Sopenharmony_ci state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64; 190062306a36Sopenharmony_ci state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE; 190162306a36Sopenharmony_ci state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1; 190262306a36Sopenharmony_ci state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2; 190362306a36Sopenharmony_ci state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP; 190462306a36Sopenharmony_ci state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center; 190562306a36Sopenharmony_ci state->AS_Data.f_LO1 = 2181000000UL; 190662306a36Sopenharmony_ci state->AS_Data.f_LO2 = 1486249786UL; 190762306a36Sopenharmony_ci state->f_IF1_actual = state->AS_Data.f_if1_Center; 190862306a36Sopenharmony_ci state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual; 190962306a36Sopenharmony_ci state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID; 191062306a36Sopenharmony_ci state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID; 191162306a36Sopenharmony_ci state->num_regs = MT2063_REG_END_REGS; 191262306a36Sopenharmony_ci state->AS_Data.avoidDECT = MT2063_AVOID_BOTH; 191362306a36Sopenharmony_ci state->ctfilt_sw = 0; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci state->CTFiltMax[0] = 69230000; 191662306a36Sopenharmony_ci state->CTFiltMax[1] = 105770000; 191762306a36Sopenharmony_ci state->CTFiltMax[2] = 140350000; 191862306a36Sopenharmony_ci state->CTFiltMax[3] = 177110000; 191962306a36Sopenharmony_ci state->CTFiltMax[4] = 212860000; 192062306a36Sopenharmony_ci state->CTFiltMax[5] = 241130000; 192162306a36Sopenharmony_ci state->CTFiltMax[6] = 274370000; 192262306a36Sopenharmony_ci state->CTFiltMax[7] = 309820000; 192362306a36Sopenharmony_ci state->CTFiltMax[8] = 342450000; 192462306a36Sopenharmony_ci state->CTFiltMax[9] = 378870000; 192562306a36Sopenharmony_ci state->CTFiltMax[10] = 416210000; 192662306a36Sopenharmony_ci state->CTFiltMax[11] = 456500000; 192762306a36Sopenharmony_ci state->CTFiltMax[12] = 495790000; 192862306a36Sopenharmony_ci state->CTFiltMax[13] = 534530000; 192962306a36Sopenharmony_ci state->CTFiltMax[14] = 572610000; 193062306a36Sopenharmony_ci state->CTFiltMax[15] = 598970000; 193162306a36Sopenharmony_ci state->CTFiltMax[16] = 635910000; 193262306a36Sopenharmony_ci state->CTFiltMax[17] = 672130000; 193362306a36Sopenharmony_ci state->CTFiltMax[18] = 714840000; 193462306a36Sopenharmony_ci state->CTFiltMax[19] = 739660000; 193562306a36Sopenharmony_ci state->CTFiltMax[20] = 770410000; 193662306a36Sopenharmony_ci state->CTFiltMax[21] = 814660000; 193762306a36Sopenharmony_ci state->CTFiltMax[22] = 846950000; 193862306a36Sopenharmony_ci state->CTFiltMax[23] = 867820000; 193962306a36Sopenharmony_ci state->CTFiltMax[24] = 915980000; 194062306a36Sopenharmony_ci state->CTFiltMax[25] = 947450000; 194162306a36Sopenharmony_ci state->CTFiltMax[26] = 983110000; 194262306a36Sopenharmony_ci state->CTFiltMax[27] = 1021630000; 194362306a36Sopenharmony_ci state->CTFiltMax[28] = 1061870000; 194462306a36Sopenharmony_ci state->CTFiltMax[29] = 1098330000; 194562306a36Sopenharmony_ci state->CTFiltMax[30] = 1138990000; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci /* 194862306a36Sopenharmony_ci ** Fetch the FCU osc value and use it and the fRef value to 194962306a36Sopenharmony_ci ** scale all of the Band Max values 195062306a36Sopenharmony_ci */ 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A; 195362306a36Sopenharmony_ci status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, 195462306a36Sopenharmony_ci &state->reg[MT2063_REG_CTUNE_CTRL], 1); 195562306a36Sopenharmony_ci if (status < 0) 195662306a36Sopenharmony_ci return status; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci /* Read the ClearTune filter calibration value */ 195962306a36Sopenharmony_ci status = mt2063_read(state, MT2063_REG_FIFFC, 196062306a36Sopenharmony_ci &state->reg[MT2063_REG_FIFFC], 1); 196162306a36Sopenharmony_ci if (status < 0) 196262306a36Sopenharmony_ci return status; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci fcu_osc = state->reg[MT2063_REG_FIFFC]; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci state->reg[MT2063_REG_CTUNE_CTRL] = 0x00; 196762306a36Sopenharmony_ci status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, 196862306a36Sopenharmony_ci &state->reg[MT2063_REG_CTUNE_CTRL], 1); 196962306a36Sopenharmony_ci if (status < 0) 197062306a36Sopenharmony_ci return status; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci /* Adjust each of the values in the ClearTune filter cross-over table */ 197362306a36Sopenharmony_ci for (i = 0; i < 31; i++) 197462306a36Sopenharmony_ci state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci status = MT2063_SoftwareShutdown(state, 1); 197762306a36Sopenharmony_ci if (status < 0) 197862306a36Sopenharmony_ci return status; 197962306a36Sopenharmony_ci status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); 198062306a36Sopenharmony_ci if (status < 0) 198162306a36Sopenharmony_ci return status; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci state->init = true; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci return 0; 198662306a36Sopenharmony_ci} 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_cistatic int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) 198962306a36Sopenharmony_ci{ 199062306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 199162306a36Sopenharmony_ci int status; 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci dprintk(2, "\n"); 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci if (!state->init) 199662306a36Sopenharmony_ci return -ENODEV; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci *tuner_status = 0; 199962306a36Sopenharmony_ci status = mt2063_lockStatus(state); 200062306a36Sopenharmony_ci if (status < 0) 200162306a36Sopenharmony_ci return status; 200262306a36Sopenharmony_ci if (status) 200362306a36Sopenharmony_ci *tuner_status = TUNER_STATUS_LOCKED; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci dprintk(1, "Tuner status: %d", *tuner_status); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci return 0; 200862306a36Sopenharmony_ci} 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_cistatic void mt2063_release(struct dvb_frontend *fe) 201162306a36Sopenharmony_ci{ 201262306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci dprintk(2, "\n"); 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci fe->tuner_priv = NULL; 201762306a36Sopenharmony_ci kfree(state); 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_cistatic int mt2063_set_analog_params(struct dvb_frontend *fe, 202162306a36Sopenharmony_ci struct analog_parameters *params) 202262306a36Sopenharmony_ci{ 202362306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 202462306a36Sopenharmony_ci s32 pict_car; 202562306a36Sopenharmony_ci s32 pict2chanb_vsb; 202662306a36Sopenharmony_ci s32 ch_bw; 202762306a36Sopenharmony_ci s32 if_mid; 202862306a36Sopenharmony_ci s32 rcvr_mode; 202962306a36Sopenharmony_ci int status; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci dprintk(2, "\n"); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci if (!state->init) { 203462306a36Sopenharmony_ci status = mt2063_init(fe); 203562306a36Sopenharmony_ci if (status < 0) 203662306a36Sopenharmony_ci return status; 203762306a36Sopenharmony_ci } 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci switch (params->mode) { 204062306a36Sopenharmony_ci case V4L2_TUNER_RADIO: 204162306a36Sopenharmony_ci pict_car = 38900000; 204262306a36Sopenharmony_ci ch_bw = 8000000; 204362306a36Sopenharmony_ci pict2chanb_vsb = -(ch_bw / 2); 204462306a36Sopenharmony_ci rcvr_mode = MT2063_OFFAIR_ANALOG; 204562306a36Sopenharmony_ci break; 204662306a36Sopenharmony_ci case V4L2_TUNER_ANALOG_TV: 204762306a36Sopenharmony_ci rcvr_mode = MT2063_CABLE_ANALOG; 204862306a36Sopenharmony_ci if (params->std & ~V4L2_STD_MN) { 204962306a36Sopenharmony_ci pict_car = 38900000; 205062306a36Sopenharmony_ci ch_bw = 6000000; 205162306a36Sopenharmony_ci pict2chanb_vsb = -1250000; 205262306a36Sopenharmony_ci } else if (params->std & V4L2_STD_PAL_G) { 205362306a36Sopenharmony_ci pict_car = 38900000; 205462306a36Sopenharmony_ci ch_bw = 7000000; 205562306a36Sopenharmony_ci pict2chanb_vsb = -1250000; 205662306a36Sopenharmony_ci } else { /* PAL/SECAM standards */ 205762306a36Sopenharmony_ci pict_car = 38900000; 205862306a36Sopenharmony_ci ch_bw = 8000000; 205962306a36Sopenharmony_ci pict2chanb_vsb = -1250000; 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci break; 206262306a36Sopenharmony_ci default: 206362306a36Sopenharmony_ci return -EINVAL; 206462306a36Sopenharmony_ci } 206562306a36Sopenharmony_ci if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ 206862306a36Sopenharmony_ci state->AS_Data.f_out = if_mid; 206962306a36Sopenharmony_ci state->AS_Data.f_out_bw = ch_bw + 750000; 207062306a36Sopenharmony_ci status = MT2063_SetReceiverMode(state, rcvr_mode); 207162306a36Sopenharmony_ci if (status < 0) 207262306a36Sopenharmony_ci return status; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", 207562306a36Sopenharmony_ci params->frequency, ch_bw, pict2chanb_vsb); 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2)))); 207862306a36Sopenharmony_ci if (status < 0) 207962306a36Sopenharmony_ci return status; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci state->frequency = params->frequency; 208262306a36Sopenharmony_ci return 0; 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci/* 208662306a36Sopenharmony_ci * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. 208762306a36Sopenharmony_ci * So, the amount of the needed bandwidth is given by: 208862306a36Sopenharmony_ci * Bw = Symbol_rate * (1 + 0.15) 208962306a36Sopenharmony_ci * As such, the maximum symbol rate supported by 6 MHz is given by: 209062306a36Sopenharmony_ci * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds 209162306a36Sopenharmony_ci */ 209262306a36Sopenharmony_ci#define MAX_SYMBOL_RATE_6MHz 5217391 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_cistatic int mt2063_set_params(struct dvb_frontend *fe) 209562306a36Sopenharmony_ci{ 209662306a36Sopenharmony_ci struct dtv_frontend_properties *c = &fe->dtv_property_cache; 209762306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 209862306a36Sopenharmony_ci int status; 209962306a36Sopenharmony_ci s32 pict_car; 210062306a36Sopenharmony_ci s32 pict2chanb_vsb; 210162306a36Sopenharmony_ci s32 ch_bw; 210262306a36Sopenharmony_ci s32 if_mid; 210362306a36Sopenharmony_ci s32 rcvr_mode; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (!state->init) { 210662306a36Sopenharmony_ci status = mt2063_init(fe); 210762306a36Sopenharmony_ci if (status < 0) 210862306a36Sopenharmony_ci return status; 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci dprintk(2, "\n"); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci if (c->bandwidth_hz == 0) 211462306a36Sopenharmony_ci return -EINVAL; 211562306a36Sopenharmony_ci if (c->bandwidth_hz <= 6000000) 211662306a36Sopenharmony_ci ch_bw = 6000000; 211762306a36Sopenharmony_ci else if (c->bandwidth_hz <= 7000000) 211862306a36Sopenharmony_ci ch_bw = 7000000; 211962306a36Sopenharmony_ci else 212062306a36Sopenharmony_ci ch_bw = 8000000; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci switch (c->delivery_system) { 212362306a36Sopenharmony_ci case SYS_DVBT: 212462306a36Sopenharmony_ci rcvr_mode = MT2063_OFFAIR_COFDM; 212562306a36Sopenharmony_ci pict_car = 36125000; 212662306a36Sopenharmony_ci pict2chanb_vsb = -(ch_bw / 2); 212762306a36Sopenharmony_ci break; 212862306a36Sopenharmony_ci case SYS_DVBC_ANNEX_A: 212962306a36Sopenharmony_ci case SYS_DVBC_ANNEX_C: 213062306a36Sopenharmony_ci rcvr_mode = MT2063_CABLE_QAM; 213162306a36Sopenharmony_ci pict_car = 36125000; 213262306a36Sopenharmony_ci pict2chanb_vsb = -(ch_bw / 2); 213362306a36Sopenharmony_ci break; 213462306a36Sopenharmony_ci default: 213562306a36Sopenharmony_ci return -EINVAL; 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ 214062306a36Sopenharmony_ci state->AS_Data.f_out = if_mid; 214162306a36Sopenharmony_ci state->AS_Data.f_out_bw = ch_bw + 750000; 214262306a36Sopenharmony_ci status = MT2063_SetReceiverMode(state, rcvr_mode); 214362306a36Sopenharmony_ci if (status < 0) 214462306a36Sopenharmony_ci return status; 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", 214762306a36Sopenharmony_ci c->frequency, ch_bw, pict2chanb_vsb); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2)))); 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci if (status < 0) 215262306a36Sopenharmony_ci return status; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci state->frequency = c->frequency; 215562306a36Sopenharmony_ci return 0; 215662306a36Sopenharmony_ci} 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_cistatic int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq) 215962306a36Sopenharmony_ci{ 216062306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci dprintk(2, "\n"); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci if (!state->init) 216562306a36Sopenharmony_ci return -ENODEV; 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci *freq = state->AS_Data.f_out; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci dprintk(1, "IF frequency: %d\n", *freq); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci return 0; 217262306a36Sopenharmony_ci} 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_cistatic int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) 217562306a36Sopenharmony_ci{ 217662306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci dprintk(2, "\n"); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci if (!state->init) 218162306a36Sopenharmony_ci return -ENODEV; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci *bw = state->AS_Data.f_out_bw - 750000; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci dprintk(1, "bandwidth: %d\n", *bw); 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci return 0; 218862306a36Sopenharmony_ci} 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_cistatic const struct dvb_tuner_ops mt2063_ops = { 219162306a36Sopenharmony_ci .info = { 219262306a36Sopenharmony_ci .name = "MT2063 Silicon Tuner", 219362306a36Sopenharmony_ci .frequency_min_hz = 45 * MHz, 219462306a36Sopenharmony_ci .frequency_max_hz = 865 * MHz, 219562306a36Sopenharmony_ci }, 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci .init = mt2063_init, 219862306a36Sopenharmony_ci .sleep = MT2063_Sleep, 219962306a36Sopenharmony_ci .get_status = mt2063_get_status, 220062306a36Sopenharmony_ci .set_analog_params = mt2063_set_analog_params, 220162306a36Sopenharmony_ci .set_params = mt2063_set_params, 220262306a36Sopenharmony_ci .get_if_frequency = mt2063_get_if_frequency, 220362306a36Sopenharmony_ci .get_bandwidth = mt2063_get_bandwidth, 220462306a36Sopenharmony_ci .release = mt2063_release, 220562306a36Sopenharmony_ci}; 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_cistruct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, 220862306a36Sopenharmony_ci struct mt2063_config *config, 220962306a36Sopenharmony_ci struct i2c_adapter *i2c) 221062306a36Sopenharmony_ci{ 221162306a36Sopenharmony_ci struct mt2063_state *state = NULL; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci dprintk(2, "\n"); 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); 221662306a36Sopenharmony_ci if (!state) 221762306a36Sopenharmony_ci return NULL; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci state->config = config; 222062306a36Sopenharmony_ci state->i2c = i2c; 222162306a36Sopenharmony_ci state->frontend = fe; 222262306a36Sopenharmony_ci state->reference = config->refclock / 1000; /* kHz */ 222362306a36Sopenharmony_ci fe->tuner_priv = state; 222462306a36Sopenharmony_ci fe->ops.tuner_ops = mt2063_ops; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci printk(KERN_INFO "%s: Attaching MT2063\n", __func__); 222762306a36Sopenharmony_ci return fe; 222862306a36Sopenharmony_ci} 222962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt2063_attach); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci#if 0 223262306a36Sopenharmony_ci/* 223362306a36Sopenharmony_ci * Ancillary routines visible outside mt2063 223462306a36Sopenharmony_ci * FIXME: Remove them in favor of using standard tuner callbacks 223562306a36Sopenharmony_ci */ 223662306a36Sopenharmony_cistatic int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) 223762306a36Sopenharmony_ci{ 223862306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 223962306a36Sopenharmony_ci int err = 0; 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci dprintk(2, "\n"); 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci err = MT2063_SoftwareShutdown(state, 1); 224462306a36Sopenharmony_ci if (err < 0) 224562306a36Sopenharmony_ci printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci return err; 224862306a36Sopenharmony_ci} 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_cistatic int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) 225162306a36Sopenharmony_ci{ 225262306a36Sopenharmony_ci struct mt2063_state *state = fe->tuner_priv; 225362306a36Sopenharmony_ci int err = 0; 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci dprintk(2, "\n"); 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); 225862306a36Sopenharmony_ci if (err < 0) 225962306a36Sopenharmony_ci printk(KERN_ERR "%s: Invalid parameter\n", __func__); 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci return err; 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci#endif 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab"); 226662306a36Sopenharmony_ciMODULE_DESCRIPTION("MT2063 Silicon tuner"); 226762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2268