blob: 92653a9ff3b0c1bab70f34f6e68ecd5d933210c5 [file] [log] [blame]
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001/*
2 * Driver for mt2063 Micronas tuner
3 *
4 * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com>
5 *
Mauro Carvalho Chehabd76f28f2011-07-21 17:36:20 -03006 * This driver came from a driver originally written by:
7 * Henry Wang <Henry.wang@AzureWave.com>
8 * Made publicly available by Terratec, at:
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03009 * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
Mauro Carvalho Chehabd76f28f2011-07-21 17:36:20 -030010 * The original driver's license is GPL, as declared with MODULE_LICENSE()
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -030011 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation under version 2 of the License.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 */
21
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -030022#include <linux/init.h>
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/string.h>
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -030026#include <linux/videodev2.h>
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -030027
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -030028#include "mt2063.h"
29
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -030030static unsigned int debug;
31module_param(debug, int, 0644);
32MODULE_PARM_DESC(debug, "Set Verbosity level");
33
34#define dprintk(level, fmt, arg...) do { \
35if (debug >= level) \
36 printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \
37} while (0)
38
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -030039
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -030040/* positive error codes used internally */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030041
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -030042/* Info: Unavoidable LO-related spur may be present in the output */
Mauro Carvalho Chehab29a0a4f2011-07-20 23:44:10 -030043#define MT2063_SPUR_PRESENT_ERR (0x00800000)
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030044
45/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */
46#define MT2063_SPUR_CNT_MASK (0x001f0000)
47#define MT2063_SPUR_SHIFT (16)
48
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030049/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
50#define MT2063_UPC_RANGE (0x04000000)
51
52/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
53#define MT2063_DNC_RANGE (0x08000000)
54
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030055/*
56 * Constant defining the version of the following structure
57 * and therefore the API for this code.
58 *
59 * When compiling the tuner driver, the preprocessor will
60 * check against this version number to make sure that
61 * it matches the version that the tuner driver knows about.
62 */
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030063
64/* DECT Frequency Avoidance */
65#define MT2063_DECT_AVOID_US_FREQS 0x00000001
66
67#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002
68
69#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
70
71#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
72
73enum MT2063_DECT_Avoid_Type {
74 MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */
75 MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */
76 MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */
77 MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */
78};
79
80#define MT2063_MAX_ZONES 48
81
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030082struct MT2063_ExclZone_t {
83 u32 min_;
84 u32 max_;
85 struct MT2063_ExclZone_t *next_;
86};
87
88/*
89 * Structure of data needed for Spur Avoidance
90 */
91struct MT2063_AvoidSpursData_t {
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -030092 u32 f_ref;
93 u32 f_in;
94 u32 f_LO1;
95 u32 f_if1_Center;
96 u32 f_if1_Request;
97 u32 f_if1_bw;
98 u32 f_LO2;
99 u32 f_out;
100 u32 f_out_bw;
101 u32 f_LO1_Step;
102 u32 f_LO2_Step;
103 u32 f_LO1_FracN_Avoid;
104 u32 f_LO2_FracN_Avoid;
105 u32 f_zif_bw;
106 u32 f_min_LO_Separation;
107 u32 maxH1;
108 u32 maxH2;
109 enum MT2063_DECT_Avoid_Type avoidDECT;
110 u32 bSpurPresent;
111 u32 bSpurAvoided;
112 u32 nSpursFound;
113 u32 nZones;
114 struct MT2063_ExclZone_t *freeZones;
115 struct MT2063_ExclZone_t *usedZones;
116 struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
117};
118
119/*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300120 * Parameter for function MT2063_SetPowerMask that specifies the power down
121 * of various sections of the MT2063.
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300122 */
123enum MT2063_Mask_Bits {
124 MT2063_REG_SD = 0x0040, /* Shutdown regulator */
125 MT2063_SRO_SD = 0x0020, /* Shutdown SRO */
126 MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */
127 MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */
128 MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */
129 MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */
130 MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */
131 MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */
132 MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */
133 MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */
134 MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */
135 MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */
136 MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */
137 MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */
138 MT2063_NONE_SD = 0x0000 /* No shutdown bits */
139};
140
141/*
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300142 * Possible values for MT2063_DNC_OUTPUT
143 */
144enum MT2063_DNC_Output_Enable {
145 MT2063_DNC_NONE = 0,
146 MT2063_DNC_1,
147 MT2063_DNC_2,
148 MT2063_DNC_BOTH
149};
150
151/*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300152 * Two-wire serial bus subaddresses of the tuner registers.
153 * Also known as the tuner's register addresses.
154 */
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300155enum MT2063_Register_Offsets {
156 MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */
157 MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */
158 MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */
159 MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */
160 MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */
161 MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */
162 MT2063_REG_RSVD_06, /* 0x06: Reserved */
163 MT2063_REG_LO_STATUS, /* 0x07: LO Status */
164 MT2063_REG_FIFFC, /* 0x08: FIFF Center */
165 MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */
166 MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */
167 MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */
168 MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */
169 MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */
170 MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */
171 MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */
172 MT2063_REG_RSVD_10, /* 0x10: Reserved */
173 MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */
174 MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */
175 MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */
176 MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */
177 MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */
178 MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */
179 MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */
180 MT2063_REG_RF_OV, /* 0x18: RF Attn Override */
181 MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */
182 MT2063_REG_LNA_TGT, /* 0x1A: Reserved */
183 MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */
184 MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */
185 MT2063_REG_RSVD_1D, /* 0x1D: Reserved */
186 MT2063_REG_RSVD_1E, /* 0x1E: Reserved */
187 MT2063_REG_RSVD_1F, /* 0x1F: Reserved */
188 MT2063_REG_RSVD_20, /* 0x20: Reserved */
189 MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */
190 MT2063_REG_RSVD_22, /* 0x22: Reserved */
191 MT2063_REG_RSVD_23, /* 0x23: Reserved */
192 MT2063_REG_RSVD_24, /* 0x24: Reserved */
193 MT2063_REG_RSVD_25, /* 0x25: Reserved */
194 MT2063_REG_RSVD_26, /* 0x26: Reserved */
195 MT2063_REG_RSVD_27, /* 0x27: Reserved */
196 MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */
197 MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */
198 MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */
199 MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */
200 MT2063_REG_CTRL_2C, /* 0x2C: Reserved */
201 MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */
202 MT2063_REG_RSVD_2E, /* 0x2E: Reserved */
203 MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */
204 MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */
205 MT2063_REG_RSVD_31, /* 0x31: Reserved */
206 MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */
207 MT2063_REG_RSVD_33, /* 0x33: Reserved */
208 MT2063_REG_RSVD_34, /* 0x34: Reserved */
209 MT2063_REG_RSVD_35, /* 0x35: Reserved */
210 MT2063_REG_RSVD_36, /* 0x36: Reserved */
211 MT2063_REG_RSVD_37, /* 0x37: Reserved */
212 MT2063_REG_RSVD_38, /* 0x38: Reserved */
213 MT2063_REG_RSVD_39, /* 0x39: Reserved */
214 MT2063_REG_RSVD_3A, /* 0x3A: Reserved */
215 MT2063_REG_RSVD_3B, /* 0x3B: Reserved */
216 MT2063_REG_RSVD_3C, /* 0x3C: Reserved */
217 MT2063_REG_END_REGS
218};
219
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300220struct mt2063_state {
221 struct i2c_adapter *i2c;
222
223 const struct mt2063_config *config;
224 struct dvb_tuner_ops ops;
225 struct dvb_frontend *frontend;
226 struct tuner_state status;
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300227
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300228 u32 frequency;
229 u32 srate;
230 u32 bandwidth;
231 u32 reference;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300232
233 u32 tuner_id;
234 struct MT2063_AvoidSpursData_t AS_Data;
235 u32 f_IF1_actual;
236 u32 rcvr_mode;
237 u32 ctfilt_sw;
238 u32 CTFiltMax[31];
239 u32 num_regs;
240 u8 reg[MT2063_REG_END_REGS];
Mauro Carvalho Chehab6d3d7482011-07-20 22:21:26 -0300241};
Mauro Carvalho Chehab0ff48432011-07-20 20:21:42 -0300242
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300243/*
244 * mt2063_write - Write data into the I2C bus
245 */
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300246static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300247{
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300248 struct dvb_frontend *fe = state->frontend;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300249 int ret;
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300250 u8 buf[60];
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300251 struct i2c_msg msg = {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300252 .addr = state->config->tuner_address,
253 .flags = 0,
254 .buf = buf,
255 .len = len + 1
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300256 };
257
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300258 dprintk(2, "\n");
259
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300260 msg.buf[0] = reg;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300261 memcpy(msg.buf + 1, data, len);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300262
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300263 if (fe->ops.i2c_gate_ctrl)
264 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300265 ret = i2c_transfer(state->i2c, &msg, 1);
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300266 if (fe->ops.i2c_gate_ctrl)
267 fe->ops.i2c_gate_ctrl(fe, 0);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300268
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300269 if (ret < 0)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300270 printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300271
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300272 return ret;
273}
274
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300275/*
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300276 * mt2063_write - Write register data into the I2C bus, caching the value
277 */
278static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
279{
280 u32 status;
281
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300282 dprintk(2, "\n");
283
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300284 if (reg >= MT2063_REG_END_REGS)
285 return -ERANGE;
286
287 status = mt2063_write(state, reg, &val, 1);
288 if (status < 0)
289 return status;
290
291 state->reg[reg] = val;
292
293 return 0;
294}
295
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300296/*
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300297 * mt2063_read - Read data from the I2C bus
298 */
299static u32 mt2063_read(struct mt2063_state *state,
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300300 u8 subAddress, u8 *pData, u32 cnt)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300301{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -0300302 u32 status = 0; /* Status to be returned */
303 struct dvb_frontend *fe = state->frontend;
304 u32 i = 0;
305
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300306 dprintk(2, "\n");
307
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300308 if (fe->ops.i2c_gate_ctrl)
309 fe->ops.i2c_gate_ctrl(fe, 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300310
311 for (i = 0; i < cnt; i++) {
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -0300312 int ret;
313 u8 b0[] = { subAddress + i };
314 struct i2c_msg msg[] = {
315 {
316 .addr = state->config->tuner_address,
317 .flags = I2C_M_RD,
318 .buf = b0,
319 .len = 1
320 }, {
321 .addr = state->config->tuner_address,
322 .flags = I2C_M_RD,
323 .buf = pData + 1,
324 .len = 1
325 }
326 };
327
328 ret = i2c_transfer(state->i2c, msg, 2);
329 if (ret < 0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300330 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300331 }
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300332 if (fe->ops.i2c_gate_ctrl)
333 fe->ops.i2c_gate_ctrl(fe, 0);
334
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300335 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300336}
337
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300338/*
339 * FIXME: Is this really needed?
340 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300341static int MT2063_Sleep(struct dvb_frontend *fe)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300342{
343 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300344 * ToDo: Add code here to implement a OS blocking
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300345 */
Mauro Carvalho Chehabf8676952011-07-20 22:00:30 -0300346 msleep(10);
347
348 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300349}
350
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300351/*
352 * Microtune spur avoidance
353 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300354
355/* Implement ceiling, floor functions. */
356#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300357#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300358
359struct MT2063_FIFZone_t {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300360 s32 min_;
361 s32 max_;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300362};
363
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300364static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
365 *pAS_Info,
366 struct MT2063_ExclZone_t *pPrevNode)
367{
368 struct MT2063_ExclZone_t *pNode;
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300369
370 dprintk(2, "\n");
371
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300372 /* Check for a node in the free list */
373 if (pAS_Info->freeZones != NULL) {
374 /* Use one from the free list */
375 pNode = pAS_Info->freeZones;
376 pAS_Info->freeZones = pNode->next_;
377 } else {
378 /* Grab a node from the array */
379 pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
380 }
381
382 if (pPrevNode != NULL) {
383 pNode->next_ = pPrevNode->next_;
384 pPrevNode->next_ = pNode;
385 } else { /* insert at the beginning of the list */
386
387 pNode->next_ = pAS_Info->usedZones;
388 pAS_Info->usedZones = pNode;
389 }
390
391 pAS_Info->nZones++;
392 return pNode;
393}
394
395static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
396 *pAS_Info,
397 struct MT2063_ExclZone_t *pPrevNode,
398 struct MT2063_ExclZone_t
399 *pNodeToRemove)
400{
401 struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
402
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300403 dprintk(2, "\n");
404
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300405 /* Make previous node point to the subsequent node */
406 if (pPrevNode != NULL)
407 pPrevNode->next_ = pNext;
408
409 /* Add pNodeToRemove to the beginning of the freeZones */
410 pNodeToRemove->next_ = pAS_Info->freeZones;
411 pAS_Info->freeZones = pNodeToRemove;
412
413 /* Decrement node count */
414 pAS_Info->nZones--;
415
416 return pNext;
417}
418
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300419/*
420 * MT_AddExclZone()
421 *
422 * Add (and merge) an exclusion zone into the list.
423 * If the range (f_min, f_max) is totally outside the
424 * 1st IF BW, ignore the entry.
425 * If the range (f_min, f_max) is negative, ignore the entry.
426 */
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300427static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300428 u32 f_min, u32 f_max)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300429{
430 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
431 struct MT2063_ExclZone_t *pPrev = NULL;
432 struct MT2063_ExclZone_t *pNext = NULL;
433
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300434 dprintk(2, "\n");
435
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300436 /* Check to see if this overlaps the 1st IF filter */
437 if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
438 && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
439 && (f_min < f_max)) {
440 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300441 * 1 2 3 4 5 6
442 *
443 * New entry: |---| |--| |--| |-| |---| |--|
444 * or or or or or
445 * Existing: |--| |--| |--| |---| |-| |--|
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300446 */
447
448 /* Check for our place in the list */
449 while ((pNode != NULL) && (pNode->max_ < f_min)) {
450 pPrev = pNode;
451 pNode = pNode->next_;
452 }
453
454 if ((pNode != NULL) && (pNode->min_ < f_max)) {
455 /* Combine me with pNode */
456 if (f_min < pNode->min_)
457 pNode->min_ = f_min;
458 if (f_max > pNode->max_)
459 pNode->max_ = f_max;
460 } else {
461 pNode = InsertNode(pAS_Info, pPrev);
462 pNode->min_ = f_min;
463 pNode->max_ = f_max;
464 }
465
466 /* Look for merging possibilities */
467 pNext = pNode->next_;
468 while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
469 if (pNext->max_ > pNode->max_)
470 pNode->max_ = pNext->max_;
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300471 /* Remove pNext, return ptr to pNext->next */
472 pNext = RemoveNode(pAS_Info, pNode, pNext);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300473 }
474 }
475}
476
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300477/*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300478 * Reset all exclusion zones.
479 * Add zones to protect the PLL FracN regions near zero
480 */
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300481static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
482{
483 u32 center;
484
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300485 dprintk(2, "\n");
486
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -0300487 pAS_Info->nZones = 0; /* this clears the used list */
488 pAS_Info->usedZones = NULL; /* reset ptr */
489 pAS_Info->freeZones = NULL; /* reset ptr */
490
491 center =
492 pAS_Info->f_ref *
493 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
494 pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
495 while (center <
496 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
497 pAS_Info->f_LO1_FracN_Avoid) {
498 /* Exclude LO1 FracN */
499 MT2063_AddExclZone(pAS_Info,
500 center - pAS_Info->f_LO1_FracN_Avoid,
501 center - 1);
502 MT2063_AddExclZone(pAS_Info, center + 1,
503 center + pAS_Info->f_LO1_FracN_Avoid);
504 center += pAS_Info->f_ref;
505 }
506
507 center =
508 pAS_Info->f_ref *
509 ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
510 pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
511 while (center <
512 pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
513 pAS_Info->f_LO2_FracN_Avoid) {
514 /* Exclude LO2 FracN */
515 MT2063_AddExclZone(pAS_Info,
516 center - pAS_Info->f_LO2_FracN_Avoid,
517 center - 1);
518 MT2063_AddExclZone(pAS_Info, center + 1,
519 center + pAS_Info->f_LO2_FracN_Avoid);
520 center += pAS_Info->f_ref;
521 }
522
523 if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
524 /* Exclude LO1 values that conflict with DECT channels */
525 MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
526 MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
527 MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
528 MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
529 MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
530 }
531
532 if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
533 MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
534 MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
535 MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
536 MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */
537 MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
538 MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
539 MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
540 MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
541 MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */
542 MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
543 }
544}
545
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300546/*
547 * MT_ChooseFirstIF - Choose the best available 1st IF
548 * If f_Desired is not excluded, choose that first.
549 * Otherwise, return the value closest to f_Center that is
550 * not excluded
551 */
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300552static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300553{
554 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300555 * Update "f_Desired" to be the nearest "combinational-multiple" of
556 * "f_LO1_Step".
557 * The resulting number, F_LO1 must be a multiple of f_LO1_Step.
558 * And F_LO1 is the arithmetic sum of f_in + f_Center.
559 * Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
560 * However, the sum must be.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300561 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300562 const u32 f_Desired =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300563 pAS_Info->f_LO1_Step *
564 ((pAS_Info->f_if1_Request + pAS_Info->f_in +
565 pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
566 pAS_Info->f_in;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300567 const u32 f_Step =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300568 (pAS_Info->f_LO1_Step >
569 pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
570 f_LO2_Step;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300571 u32 f_Center;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300572 s32 i;
573 s32 j = 0;
574 u32 bDesiredExcluded = 0;
575 u32 bZeroExcluded = 0;
576 s32 tmpMin, tmpMax;
577 s32 bestDiff;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300578 struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
579 struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
580
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300581 dprintk(2, "\n");
582
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300583 if (pAS_Info->nZones == 0)
584 return f_Desired;
585
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300586 /*
587 * f_Center needs to be an integer multiple of f_Step away
588 * from f_Desired
589 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300590 if (pAS_Info->f_if1_Center > f_Desired)
591 f_Center =
592 f_Desired +
593 f_Step *
594 ((pAS_Info->f_if1_Center - f_Desired +
595 f_Step / 2) / f_Step);
596 else
597 f_Center =
598 f_Desired -
599 f_Step *
600 ((f_Desired - pAS_Info->f_if1_Center +
601 f_Step / 2) / f_Step);
602
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300603 /*
604 * Take MT_ExclZones, center around f_Center and change the
605 * resolution to f_Step
606 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300607 while (pNode != NULL) {
608 /* floor function */
609 tmpMin =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300610 floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300611
612 /* ceil function */
613 tmpMax =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300614 ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300615
616 if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
617 bDesiredExcluded = 1;
618
619 if ((tmpMin < 0) && (tmpMax > 0))
620 bZeroExcluded = 1;
621
622 /* See if this zone overlaps the previous */
623 if ((j > 0) && (tmpMin < zones[j - 1].max_))
624 zones[j - 1].max_ = tmpMax;
625 else {
626 /* Add new zone */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300627 zones[j].min_ = tmpMin;
628 zones[j].max_ = tmpMax;
629 j++;
630 }
631 pNode = pNode->next_;
632 }
633
634 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300635 * If the desired is okay, return with it
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300636 */
637 if (bDesiredExcluded == 0)
638 return f_Desired;
639
640 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300641 * If the desired is excluded and the center is okay, return with it
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300642 */
643 if (bZeroExcluded == 0)
644 return f_Center;
645
646 /* Find the value closest to 0 (f_Center) */
647 bestDiff = zones[0].min_;
648 for (i = 0; i < j; i++) {
649 if (abs(zones[i].min_) < abs(bestDiff))
650 bestDiff = zones[i].min_;
651 if (abs(zones[i].max_) < abs(bestDiff))
652 bestDiff = zones[i].max_;
653 }
654
655 if (bestDiff < 0)
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300656 return f_Center - ((u32) (-bestDiff) * f_Step);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300657
658 return f_Center + (bestDiff * f_Step);
659}
660
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300661/**
662 * gcd() - Uses Euclid's algorithm
663 *
664 * @u, @v: Unsigned values whose GCD is desired.
665 *
666 * Returns THE greatest common divisor of u and v, if either value is 0,
667 * the other value is returned as the result.
668 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300669static u32 MT2063_gcd(u32 u, u32 v)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300670{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300671 u32 r;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300672
673 while (v != 0) {
674 r = u % v;
675 u = v;
676 v = r;
677 }
678
679 return u;
680}
681
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300682/**
683 * IsSpurInBand() - Checks to see if a spur will be present within the IF's
684 * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
685 *
686 * ma mb mc md
687 * <--+-+-+-------------------+-------------------+-+-+-->
688 * | ^ 0 ^ |
689 * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^
690 * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2
691 *
692 * Note that some equations are doubled to prevent round-off
693 * problems when calculating fIFBW/2
694 *
695 * @pAS_Info: Avoid Spurs information block
696 * @fm: If spur, amount f_IF1 has to move negative
697 * @fp: If spur, amount f_IF1 has to move positive
698 *
699 * Returns 1 if an LO spur would be present, otherwise 0.
700 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300701static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300702 u32 *fm, u32 * fp)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300703{
704 /*
705 ** Calculate LO frequency settings.
706 */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300707 u32 n, n0;
708 const u32 f_LO1 = pAS_Info->f_LO1;
709 const u32 f_LO2 = pAS_Info->f_LO2;
710 const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
711 const u32 c = d - pAS_Info->f_out_bw;
712 const u32 f = pAS_Info->f_zif_bw / 2;
Mauro Carvalho Chehabd0dcc2d2011-07-21 02:30:19 -0300713 const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300714 s32 f_nsLO1, f_nsLO2;
715 s32 f_Spur;
716 u32 ma, mb, mc, md, me, mf;
717 u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300718
719 dprintk(2, "\n");
720
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300721 *fm = 0;
722
723 /*
724 ** For each edge (d, c & f), calculate a scale, based on the gcd
725 ** of f_LO1, f_LO2 and the edge value. Use the larger of this
726 ** gcd-based scale factor or f_Scale.
727 */
728 lo_gcd = MT2063_gcd(f_LO1, f_LO2);
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300729 gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300730 hgds = gd_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300731 gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300732 hgcs = gc_Scale / 2;
Mauro Carvalho Chehabfd1126c2011-07-21 03:30:57 -0300733 gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300734 hgfs = gf_Scale / 2;
735
Mauro Carvalho Chehabe930b3a2011-07-21 03:02:16 -0300736 n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300737
738 /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */
739 for (n = n0; n <= pAS_Info->maxH1; ++n) {
740 md = (n * ((f_LO1 + hgds) / gd_Scale) -
741 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
742
743 /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */
744 if (md >= pAS_Info->maxH1)
745 break;
746
747 ma = (n * ((f_LO1 + hgds) / gd_Scale) +
748 ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
749
750 /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */
751 if (md == ma)
752 continue;
753
754 mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
755 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
756 if (mc != md) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300757 f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
758 f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300759 f_Spur =
760 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
761 n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
762
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300763 *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
764 *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300765 return 1;
766 }
767
768 /* Location of Zero-IF-spur to be checked */
769 me = (n * ((f_LO1 + hgfs) / gf_Scale) +
770 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
771 mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
772 ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
773 if (me != mf) {
774 f_nsLO1 = n * (f_LO1 / gf_Scale);
775 f_nsLO2 = me * (f_LO2 / gf_Scale);
776 f_Spur =
777 (gf_Scale * (f_nsLO1 - f_nsLO2)) +
778 n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
779
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300780 *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
781 *fm = (((s32) f - f_Spur) / (me - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300782 return 1;
783 }
784
785 mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
786 ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
787 if (ma != mb) {
788 f_nsLO1 = n * (f_LO1 / gc_Scale);
789 f_nsLO2 = ma * (f_LO2 / gc_Scale);
790 f_Spur =
791 (gc_Scale * (f_nsLO1 - f_nsLO2)) +
792 n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
793
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300794 *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
795 *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300796 return 1;
797 }
798 }
799
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300800 /* No spurs found */
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300801 return 0;
802}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300803
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300804/*
805 * MT_AvoidSpurs() - Main entry point to avoid spurs.
806 * Checks for existing spurs in present LO1, LO2 freqs
807 * and if present, chooses spur-free LO1, LO2 combination
808 * that tunes the same input/output frequencies.
809 */
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -0300810static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300811{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300812 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300813 u32 fm, fp; /* restricted range on LO's */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300814 pAS_Info->bSpurAvoided = 0;
815 pAS_Info->nSpursFound = 0;
816
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300817 dprintk(2, "\n");
818
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300819 if (pAS_Info->maxH1 == 0)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300820 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300821
822 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300823 * Avoid LO Generated Spurs
824 *
825 * Make sure that have no LO-related spurs within the IF output
826 * bandwidth.
827 *
828 * If there is an LO spur in this band, start at the current IF1 frequency
829 * and work out until we find a spur-free frequency or run up against the
830 * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they
831 * will be unchanged if a spur-free setting is not found.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300832 */
833 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
834 if (pAS_Info->bSpurPresent) {
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300835 u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */
836 u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */
837 u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */
838 u32 delta_IF1;
839 u32 new_IF1;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300840
841 /*
842 ** Spur was found, attempt to find a spur-free 1st IF
843 */
844 do {
845 pAS_Info->nSpursFound++;
846
847 /* Raise f_IF1_upper, if needed */
848 MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
849
850 /* Choose next IF1 that is closest to f_IF1_CENTER */
851 new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
852
853 if (new_IF1 > zfIF1) {
854 pAS_Info->f_LO1 += (new_IF1 - zfIF1);
855 pAS_Info->f_LO2 += (new_IF1 - zfIF1);
856 } else {
857 pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
858 pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
859 }
860 zfIF1 = new_IF1;
861
862 if (zfIF1 > pAS_Info->f_if1_Center)
863 delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
864 else
865 delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300866
867 pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300868 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300869 * Continue while the new 1st IF is still within the 1st IF bandwidth
870 * and there is a spur in the band (again)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300871 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300872 } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300873
874 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300875 * Use the LO-spur free values found. If the search went all
876 * the way to the 1st IF band edge and always found spurs, just
877 * leave the original choice. It's as "good" as any other.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300878 */
879 if (pAS_Info->bSpurPresent == 1) {
880 status |= MT2063_SPUR_PRESENT_ERR;
881 pAS_Info->f_LO1 = zfLO1;
882 pAS_Info->f_LO2 = zfLO2;
883 } else
884 pAS_Info->bSpurAvoided = 1;
885 }
886
887 status |=
888 ((pAS_Info->
889 nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
890
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300891 return status;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -0300892}
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300893
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300894/*
Mauro Carvalho Chehab66aea302011-07-21 03:57:10 -0300895 * Constants used by the tuning algorithm
896 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300897#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */
898#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */
899#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */
900#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */
901#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */
902#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */
903#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */
904#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */
905#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */
906#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */
907#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */
908#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */
909#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */
910#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */
911#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */
912#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */
913#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */
914#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */
915
916/*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -0300917 * Define the supported Part/Rev codes for the MT2063
918 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300919#define MT2063_B0 (0x9B)
920#define MT2063_B1 (0x9C)
921#define MT2063_B2 (0x9D)
922#define MT2063_B3 (0x9E)
923
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300924/**
925 * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
926 *
927 * @state: struct mt2063_state pointer
928 *
929 * This function returns 0, if no lock, 1 if locked and a value < 1 if error
930 */
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -0300931static unsigned int mt2063_lockStatus(struct mt2063_state *state)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300932{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300933 const u32 nMaxWait = 100; /* wait a maximum of 100 msec */
934 const u32 nPollRate = 2; /* poll status bits every 2 ms */
935 const u32 nMaxLoops = nMaxWait / nPollRate;
936 const u8 LO1LK = 0x80;
937 u8 LO2LK = 0x08;
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300938 u32 status;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -0300939 u32 nDelays = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300940
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -0300941 dprintk(2, "\n");
942
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300943 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -0300944 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300945 LO2LK = 0x40;
946
947 do {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300948 status = mt2063_read(state, MT2063_REG_LO_STATUS,
949 &state->reg[MT2063_REG_LO_STATUS], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300950
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -0300951 if (status < 0)
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300952 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300953
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -0300954 if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300955 (LO1LK | LO2LK)) {
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300956 return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300957 }
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -0300958 msleep(nPollRate); /* Wait between retries */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -0300959 } while (++nDelays < nMaxLoops);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300960
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -0300961 /*
962 * Got no lock or partial lock
963 */
964 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -0300965}
966
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -0300967/*
Mauro Carvalho Chehab8fdb2262011-07-21 17:20:49 -0300968 * Constants for setting receiver modes.
969 * (6 modes defined at this time, enumerated by mt2063_delivery_sys)
970 * (DNC1GC & DNC2GC are the values, which are used, when the specific
971 * DNC Output is selected, the other is always off)
972 *
973 * enum mt2063_delivery_sys
974 * -------------+----------------------------------------------
975 * Mode 0 : | MT2063_CABLE_QAM
976 * Mode 1 : | MT2063_CABLE_ANALOG
977 * Mode 2 : | MT2063_OFFAIR_COFDM
978 * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS
979 * Mode 4 : | MT2063_OFFAIR_ANALOG
980 * Mode 5 : | MT2063_OFFAIR_8VSB
981 * --------------+----------------------------------------------
982 *
983 * |<---------- Mode -------------->|
984 * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 |
985 * ------------+-----+-----+-----+-----+-----+-----+
986 * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF
987 * LNARin | 0 | 0 | 3 | 3 | 3 | 3
988 * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1
989 * FIFFq | 0 | 0 | 0 | 0 | 0 | 0
990 * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0
991 * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0
992 * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1
993 * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31
994 * LNA Target | 44 | 43 | 43 | 43 | 43 | 43
995 * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0
996 * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31
997 * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38
998 * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0
999 * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5
1000 * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42
1001 */
1002
1003enum mt2063_delivery_sys {
1004 MT2063_CABLE_QAM = 0, /* Digital cable */
1005 MT2063_CABLE_ANALOG, /* Analog cable */
1006 MT2063_OFFAIR_COFDM, /* Digital offair */
1007 MT2063_OFFAIR_COFDM_SAWLESS, /* Digital offair without SAW */
1008 MT2063_OFFAIR_ANALOG, /* Analog offair */
1009 MT2063_OFFAIR_8VSB, /* Analog offair */
1010 MT2063_NUM_RCVR_MODES
1011};
1012
1013static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 };
1014static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 };
1015static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 };
1016static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 };
1017static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 };
1018static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 };
1019static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 };
1020static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 };
1021static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1022static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 };
1023static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 };
1024static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 };
1025static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 };
1026static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 };
1027
1028/*
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001029 * mt2063_set_dnc_output_enable()
1030 */
1031static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001032 enum MT2063_DNC_Output_Enable *pValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001033{
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001034 dprintk(2, "\n");
1035
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001036 if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
1037 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1038 *pValue = MT2063_DNC_NONE;
1039 else
1040 *pValue = MT2063_DNC_2;
1041 } else { /* DNC1 is on */
1042 if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */
1043 *pValue = MT2063_DNC_1;
1044 else
1045 *pValue = MT2063_DNC_BOTH;
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001046 }
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001047 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001048}
1049
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001050/*
1051 * mt2063_set_dnc_output_enable()
1052 */
1053static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001054 enum MT2063_DNC_Output_Enable nValue)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001055{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001056 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001057 u8 val = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001058
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001059 dprintk(2, "\n");
1060
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001061 /* selects, which DNC output is used */
1062 switch (nValue) {
1063 case MT2063_DNC_NONE:
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001064 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1065 if (state->reg[MT2063_REG_DNC_GAIN] !=
1066 val)
1067 status |=
1068 mt2063_setreg(state,
1069 MT2063_REG_DNC_GAIN,
1070 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001071
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001072 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1073 if (state->reg[MT2063_REG_VGA_GAIN] !=
1074 val)
1075 status |=
1076 mt2063_setreg(state,
1077 MT2063_REG_VGA_GAIN,
1078 val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001079
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001080 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1081 if (state->reg[MT2063_REG_RSVD_20] !=
1082 val)
1083 status |=
1084 mt2063_setreg(state,
1085 MT2063_REG_RSVD_20,
1086 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001087
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001088 break;
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001089 case MT2063_DNC_1:
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001090 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1091 if (state->reg[MT2063_REG_DNC_GAIN] !=
1092 val)
1093 status |=
1094 mt2063_setreg(state,
1095 MT2063_REG_DNC_GAIN,
1096 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001097
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001098 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */
1099 if (state->reg[MT2063_REG_VGA_GAIN] !=
1100 val)
1101 status |=
1102 mt2063_setreg(state,
1103 MT2063_REG_VGA_GAIN,
1104 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001105
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001106 val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
1107 if (state->reg[MT2063_REG_RSVD_20] !=
1108 val)
1109 status |=
1110 mt2063_setreg(state,
1111 MT2063_REG_RSVD_20,
1112 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001113
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001114 break;
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001115 case MT2063_DNC_2:
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001116 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */
1117 if (state->reg[MT2063_REG_DNC_GAIN] !=
1118 val)
1119 status |=
1120 mt2063_setreg(state,
1121 MT2063_REG_DNC_GAIN,
1122 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001123
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001124 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1125 if (state->reg[MT2063_REG_VGA_GAIN] !=
1126 val)
1127 status |=
1128 mt2063_setreg(state,
1129 MT2063_REG_VGA_GAIN,
1130 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001131
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001132 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1133 if (state->reg[MT2063_REG_RSVD_20] !=
1134 val)
1135 status |=
1136 mt2063_setreg(state,
1137 MT2063_REG_RSVD_20,
1138 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001139
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001140 break;
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001141 case MT2063_DNC_BOTH:
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001142 val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */
1143 if (state->reg[MT2063_REG_DNC_GAIN] !=
1144 val)
1145 status |=
1146 mt2063_setreg(state,
1147 MT2063_REG_DNC_GAIN,
1148 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001149
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001150 val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */
1151 if (state->reg[MT2063_REG_VGA_GAIN] !=
1152 val)
1153 status |=
1154 mt2063_setreg(state,
1155 MT2063_REG_VGA_GAIN,
1156 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001157
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001158 val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */
1159 if (state->reg[MT2063_REG_RSVD_20] !=
1160 val)
1161 status |=
1162 mt2063_setreg(state,
1163 MT2063_REG_RSVD_20,
1164 val);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001165
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001166 break;
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001167 default:
1168 break;
1169 }
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001170
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001171 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001172}
1173
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001174/*
Mauro Carvalho Chehab8fdb2262011-07-21 17:20:49 -03001175 * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with
1176 * the selected enum mt2063_delivery_sys type.
1177 *
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001178 * (DNC1GC & DNC2GC are the values, which are used, when the specific
1179 * DNC Output is selected, the other is always off)
1180 *
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001181 * @state: ptr to mt2063_state structure
Mauro Carvalho Chehab8fdb2262011-07-21 17:20:49 -03001182 * @Mode: desired reciever delivery system
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001183 *
1184 * Note: Register cache must be valid for it to work
1185 */
1186
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001187static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
Mauro Carvalho Chehab8fdb2262011-07-21 17:20:49 -03001188 enum mt2063_delivery_sys Mode)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001189{
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001190 u32 status = 0; /* Status to be returned */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001191 u8 val;
1192 u32 longval;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001193
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001194 dprintk(2, "\n");
1195
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001196 if (Mode >= MT2063_NUM_RCVR_MODES)
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001197 status = -ERANGE;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001198
1199 /* RFAGCen */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001200 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001201 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001202 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001203 reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001204 ? 0x40 :
1205 0x00);
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001206 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001207 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001208 }
1209
1210 /* LNARin */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001211 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001212 u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001213 (LNARIN[Mode] & 0x03);
1214 if (state->reg[MT2063_REG_CTRL_2C] != val)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001215 status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001216 }
1217
1218 /* FIFFQEN and FIFFQ */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001219 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001220 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001221 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001222 reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001223 (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001224 if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001225 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001226 mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001227 /* trigger FIFF calibration, needed after changing FIFFQ */
1228 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001229 (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001230 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001231 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001232 val =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001233 (state->
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001234 reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001235 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001236 mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001237 }
1238 }
1239
1240 /* DNC1GC & DNC2GC */
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001241 status |= mt2063_get_dnc_output_enable(state, &longval);
1242 status |= mt2063_set_dnc_output_enable(state, longval);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001243
1244 /* acLNAmax */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001245 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001246 u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001247 (ACLNAMAX[Mode] & 0x1F);
1248 if (state->reg[MT2063_REG_LNA_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001249 status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001250 }
1251
1252 /* LNATGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001253 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001254 u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001255 (LNATGT[Mode] & 0x3F);
1256 if (state->reg[MT2063_REG_LNA_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001257 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001258 }
1259
1260 /* ACRF */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001261 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001262 u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
1263 (ACRFMAX[Mode] & 0x1F);
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001264 if (state->reg[MT2063_REG_RF_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001265 status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001266 }
1267
1268 /* PD1TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001269 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001270 u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001271 (PD1TGT[Mode] & 0x3F);
1272 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001273 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001274 }
1275
1276 /* FIFATN */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001277 if (status >= 0) {
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001278 u8 val = ACFIFMAX[Mode];
1279 if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
1280 val = 5;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001281 val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001282 (val & 0x1F);
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001283 if (state->reg[MT2063_REG_FIF_OV] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001284 status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001285 }
1286
1287 /* PD2TGT */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001288 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001289 u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
Mauro Carvalho Chehab4713e2252011-07-21 11:23:59 -03001290 (PD2TGT[Mode] & 0x3F);
1291 if (state->reg[MT2063_REG_PD2_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001292 status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001293 }
1294
1295 /* Ignore ATN Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001296 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001297 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
1298 (RFOVDIS[Mode] ? 0x80 : 0x00);
1299 if (state->reg[MT2063_REG_LNA_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001300 status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001301 }
1302
1303 /* Ignore FIF Overload */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001304 if (status >= 0) {
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001305 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
1306 (FIFOVDIS[Mode] ? 0x80 : 0x00);
1307 if (state->reg[MT2063_REG_PD1_TGT] != val)
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001308 status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001309 }
1310
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001311 if (status >= 0)
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001312 state->rcvr_mode = Mode;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001313
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001314 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001315}
1316
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001317/*
1318 * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various
1319 * sections of the MT2063
1320 *
1321 * @Bits: Mask bits to be cleared.
1322 *
1323 * See definition of MT2063_Mask_Bits type for description
1324 * of each of the power bits.
1325 */
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001326static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
1327 enum MT2063_Mask_Bits Bits)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001328{
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001329 u32 status = 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001330
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001331 dprintk(2, "\n");
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001332 Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */
1333 if ((Bits & 0xFF00) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001334 state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001335 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001336 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001337 MT2063_REG_PWR_2,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001338 &state->reg[MT2063_REG_PWR_2], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001339 }
1340 if ((Bits & 0xFF) != 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001341 state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001342 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001343 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001344 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001345 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001346 }
1347
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001348 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001349}
1350
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001351/*
1352 * MT2063_SoftwareShutdown() - Enables or disables software shutdown function.
1353 * When Shutdown is 1, any section whose power
1354 * mask is set will be shutdown.
1355 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001356static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001357{
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001358 u32 status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001359
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001360 dprintk(2, "\n");
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001361 if (Shutdown == 1)
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001362 state->reg[MT2063_REG_PWR_1] |= 0x04;
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001363 else
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001364 state->reg[MT2063_REG_PWR_1] &= ~0x04;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001365
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001366 status = mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001367 MT2063_REG_PWR_1,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001368 &state->reg[MT2063_REG_PWR_1], 1);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001369
1370 if (Shutdown != 1) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001371 state->reg[MT2063_REG_BYP_CTRL] =
1372 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001373 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001374 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001375 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001376 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001377 1);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001378 state->reg[MT2063_REG_BYP_CTRL] =
1379 (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001380 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001381 mt2063_write(state,
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001382 MT2063_REG_BYP_CTRL,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001383 &state->reg[MT2063_REG_BYP_CTRL],
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001384 1);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001385 }
1386
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001387 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001388}
1389
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001390static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001391{
1392 return f_ref * (f_LO / f_ref)
1393 + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
1394}
1395
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001396/**
1397 * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom.
1398 * This function preserves maximum precision without
1399 * risk of overflow. It accurately calculates
1400 * f_ref * num / denom to within 1 HZ with fixed math.
1401 *
1402 * @num : Fractional portion of the multiplier
1403 * @denom: denominator portion of the ratio
1404 * @f_Ref: SRO frequency.
1405 *
1406 * This calculation handles f_ref as two separate 14-bit fields.
1407 * Therefore, a maximum value of 2^28-1 may safely be used for f_ref.
1408 * This is the genesis of the magic number "14" and the magic mask value of
1409 * 0x03FFF.
1410 *
1411 * This routine successfully handles denom values up to and including 2^18.
1412 * Returns: f_ref * num / denom
1413 */
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001414static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001415{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001416 u32 t1 = (f_ref >> 14) * num;
1417 u32 term1 = t1 / denom;
1418 u32 loss = t1 % denom;
1419 u32 term2 =
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001420 (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001421 return (term1 << 14) + term2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001422}
1423
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001424/*
1425 * CalcLO1Mult()- Calculates Integer divider value and the numerator
1426 * value for a FracN PLL.
1427 *
1428 * This function assumes that the f_LO and f_Ref are
1429 * evenly divisible by f_LO_Step.
1430 *
1431 * @Div: OUTPUT: Whole number portion of the multiplier
1432 * @FracN: OUTPUT: Fractional portion of the multiplier
1433 * @f_LO: desired LO frequency.
1434 * @f_LO_Step: Minimum step size for the LO (in Hz).
1435 * @f_Ref: SRO frequency.
1436 * @f_Avoid: Range of PLL frequencies to avoid near integer multiples
1437 * of f_Ref (in Hz).
1438 *
1439 * Returns: Recalculated LO frequency.
1440 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001441static u32 MT2063_CalcLO1Mult(u32 *Div,
1442 u32 *FracN,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001443 u32 f_LO,
1444 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001445{
1446 /* Calculate the whole number portion of the divider */
1447 *Div = f_LO / f_Ref;
1448
1449 /* Calculate the numerator value (round to nearest f_LO_Step) */
1450 *FracN =
1451 (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1452 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1453
1454 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
1455}
1456
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001457/**
1458 * CalcLO2Mult() - Calculates Integer divider value and the numerator
1459 * value for a FracN PLL.
1460 *
1461 * This function assumes that the f_LO and f_Ref are
1462 * evenly divisible by f_LO_Step.
1463 *
1464 * @Div: OUTPUT: Whole number portion of the multiplier
1465 * @FracN: OUTPUT: Fractional portion of the multiplier
1466 * @f_LO: desired LO frequency.
1467 * @f_LO_Step: Minimum step size for the LO (in Hz).
1468 * @f_Ref: SRO frequency.
1469 * @f_Avoid: Range of PLL frequencies to avoid near
1470 * integer multiples of f_Ref (in Hz).
1471 *
1472 * Returns: Recalculated LO frequency.
1473 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001474static u32 MT2063_CalcLO2Mult(u32 *Div,
1475 u32 *FracN,
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001476 u32 f_LO,
1477 u32 f_LO_Step, u32 f_Ref)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001478{
1479 /* Calculate the whole number portion of the divider */
1480 *Div = f_LO / f_Ref;
1481
1482 /* Calculate the numerator value (round to nearest f_LO_Step) */
1483 *FracN =
1484 (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
1485 (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
1486
1487 return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
1488 8191);
1489}
1490
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001491/*
1492 * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be
1493 * used for a given input frequency.
1494 *
1495 * @state: ptr to tuner data structure
1496 * @f_in: RF input center frequency (in Hz).
1497 *
1498 * Returns: ClearTune filter number (0-31)
1499 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001500static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001501{
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001502 u32 RFBand;
1503 u32 idx; /* index loop */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001504
1505 /*
1506 ** Find RF Band setting
1507 */
1508 RFBand = 31; /* def when f_in > all */
1509 for (idx = 0; idx < 31; ++idx) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001510 if (state->CTFiltMax[idx] >= f_in) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001511 RFBand = idx;
1512 break;
1513 }
1514 }
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001515 return RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001516}
1517
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001518/*
1519 * MT2063_Tune() - Change the tuner's tuned frequency to RFin.
1520 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001521static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001522{ /* RF input center frequency */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001523
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001524 u32 status = 0;
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001525 u32 LO1; /* 1st LO register value */
1526 u32 Num1; /* Numerator for LO1 reg. value */
1527 u32 f_IF1; /* 1st IF requested */
1528 u32 LO2; /* 2nd LO register value */
1529 u32 Num2; /* Numerator for LO2 reg. value */
1530 u32 ofLO1, ofLO2; /* last time's LO frequencies */
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001531 u8 fiffc = 0x80; /* FIFF center freq from tuner */
1532 u32 fiffof; /* Offset from FIFF center freq */
1533 const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */
1534 u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */
1535 u8 val;
1536 u32 RFBand;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001537
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001538 dprintk(2, "\n");
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001539 /* Check the input and output frequency ranges */
1540 if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001541 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001542
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001543 if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
1544 || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001545 return -EINVAL;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001546
1547 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001548 * Save original LO1 and LO2 register values
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001549 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001550 ofLO1 = state->AS_Data.f_LO1;
Mauro Carvalho Chehabb5a91062011-07-22 17:07:17 -03001551 ofLO2 = state->AS_Data.f_LO2;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001552
1553 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001554 * Find and set RF Band setting
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001555 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001556 if (state->ctfilt_sw == 1) {
1557 val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
1558 if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001559 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001560 mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001561 }
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001562 val = state->reg[MT2063_REG_CTUNE_OV];
1563 RFBand = FindClearTuneFilter(state, f_in);
1564 state->reg[MT2063_REG_CTUNE_OV] =
1565 (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001566 | RFBand);
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001567 if (state->reg[MT2063_REG_CTUNE_OV] != val) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001568 status |=
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03001569 mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001570 }
1571 }
1572
1573 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001574 * Read the FIFF Center Frequency from the tuner
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001575 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001576 if (status >= 0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001577 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001578 mt2063_read(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001579 MT2063_REG_FIFFC,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001580 &state->reg[MT2063_REG_FIFFC], 1);
1581 fiffc = state->reg[MT2063_REG_FIFFC];
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001582 }
1583 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001584 * Assign in the requested values
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001585 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001586 state->AS_Data.f_in = f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001587 /* Request a 1st IF such that LO1 is on a step size */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001588 state->AS_Data.f_if1_Request =
1589 MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
1590 state->AS_Data.f_LO1_Step,
1591 state->AS_Data.f_ref) - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001592
1593 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001594 * Calculate frequency settings. f_IF1_FREQ + f_in is the
1595 * desired LO1 frequency
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001596 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001597 MT2063_ResetExclZones(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001598
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001599 f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001600
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001601 state->AS_Data.f_LO1 =
1602 MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
1603 state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001604
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001605 state->AS_Data.f_LO2 =
1606 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1607 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001608
1609 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001610 * Check for any LO spurs in the output bandwidth and adjust
1611 * the LO settings to avoid them if needed
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001612 */
Mauro Carvalho Chehabe3f94fb2011-07-21 13:41:29 -03001613 status |= MT2063_AvoidSpurs(&state->AS_Data);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001614 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001615 * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
1616 * Recalculate the LO frequencies and the values to be placed
1617 * in the tuning registers.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001618 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001619 state->AS_Data.f_LO1 =
1620 MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
1621 state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
1622 state->AS_Data.f_LO2 =
1623 MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
1624 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
1625 state->AS_Data.f_LO2 =
1626 MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
1627 state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001628
1629 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001630 * Check the upconverter and downconverter frequency ranges
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001631 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001632 if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
1633 || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001634 status |= MT2063_UPC_RANGE;
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001635 if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
1636 || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001637 status |= MT2063_DNC_RANGE;
1638 /* LO2 Lock bit was in a different place for B0 version */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001639 if (state->tuner_id == MT2063_B0)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001640 LO2LK = 0x40;
1641
1642 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001643 * If we have the same LO frequencies and we're already locked,
1644 * then skip re-programming the LO registers.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001645 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001646 if ((ofLO1 != state->AS_Data.f_LO1)
1647 || (ofLO2 != state->AS_Data.f_LO2)
1648 || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001649 (LO1LK | LO2LK))) {
1650 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001651 * Calculate the FIFFOF register value
1652 *
1653 * IF1_Actual
1654 * FIFFOF = ------------ - 8 * FIFFC - 4992
1655 * f_ref/64
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001656 */
1657 fiffof =
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001658 (state->AS_Data.f_LO1 -
1659 f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001660 4992;
1661 if (fiffof > 0xFF)
1662 fiffof = 0xFF;
1663
1664 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001665 * Place all of the calculated values into the local tuner
1666 * register fields.
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001667 */
Mauro Carvalho Chehabfdf77a42011-07-20 22:55:25 -03001668 if (status >= 0) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001669 state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */
1670 state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */
1671 state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001672 |(Num2 >> 12)); /* NUM2q (hi) */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001673 state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */
1674 state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001675
1676 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001677 * Now write out the computed register values
1678 * IMPORTANT: There is a required order for writing
1679 * (0x05 must follow all the others).
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001680 */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001681 status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001682 if (state->tuner_id == MT2063_B0) {
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001683 /* Re-write the one-shot bits to trigger the tune operation */
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001684 status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001685 }
1686 /* Write out the FIFF offset only if it's changing */
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001687 if (state->reg[MT2063_REG_FIFF_OFFSET] !=
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001688 (u8) fiffof) {
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001689 state->reg[MT2063_REG_FIFF_OFFSET] =
Mauro Carvalho Chehabcfde8922011-07-20 21:01:48 -03001690 (u8) fiffof;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001691 status |=
Mauro Carvalho Chehabe1de3d12011-07-21 02:46:49 -03001692 mt2063_write(state,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001693 MT2063_REG_FIFF_OFFSET,
Mauro Carvalho Chehabdcd52d22011-07-21 02:25:39 -03001694 &state->
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001695 reg[MT2063_REG_FIFF_OFFSET],
1696 1);
1697 }
1698 }
1699
1700 /*
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001701 * Check for LO's locking
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001702 */
1703
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001704 if (status < 0)
1705 return status;
1706
1707 status = mt2063_lockStatus(state);
1708 if (status < 0)
1709 return status;
1710 if (!status)
1711 return -EINVAL; /* Couldn't lock */
1712
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001713 /*
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001714 * If we locked OK, assign calculated data to mt2063_state structure
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001715 */
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001716 state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001717 }
1718
Mauro Carvalho Chehab31e67fa2011-07-21 10:30:11 -03001719 return status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001720}
1721
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001722static const u8 MT2063B0_defaults[] = {
1723 /* Reg, Value */
1724 0x19, 0x05,
1725 0x1B, 0x1D,
1726 0x1C, 0x1F,
1727 0x1D, 0x0F,
1728 0x1E, 0x3F,
1729 0x1F, 0x0F,
1730 0x20, 0x3F,
1731 0x22, 0x21,
1732 0x23, 0x3F,
1733 0x24, 0x20,
1734 0x25, 0x3F,
1735 0x27, 0xEE,
1736 0x2C, 0x27, /* bit at 0x20 is cleared below */
1737 0x30, 0x03,
1738 0x2C, 0x07, /* bit at 0x20 is cleared here */
1739 0x2D, 0x87,
1740 0x2E, 0xAA,
1741 0x28, 0xE1, /* Set the FIFCrst bit here */
1742 0x28, 0xE0, /* Clear the FIFCrst bit here */
1743 0x00
1744};
1745
1746/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
1747static const u8 MT2063B1_defaults[] = {
1748 /* Reg, Value */
1749 0x05, 0xF0,
1750 0x11, 0x10, /* New Enable AFCsd */
1751 0x19, 0x05,
1752 0x1A, 0x6C,
1753 0x1B, 0x24,
1754 0x1C, 0x28,
1755 0x1D, 0x8F,
1756 0x1E, 0x14,
1757 0x1F, 0x8F,
1758 0x20, 0x57,
1759 0x22, 0x21, /* New - ver 1.03 */
1760 0x23, 0x3C, /* New - ver 1.10 */
1761 0x24, 0x20, /* New - ver 1.03 */
1762 0x2C, 0x24, /* bit at 0x20 is cleared below */
1763 0x2D, 0x87, /* FIFFQ=0 */
1764 0x2F, 0xF3,
1765 0x30, 0x0C, /* New - ver 1.11 */
1766 0x31, 0x1B, /* New - ver 1.11 */
1767 0x2C, 0x04, /* bit at 0x20 is cleared here */
1768 0x28, 0xE1, /* Set the FIFCrst bit here */
1769 0x28, 0xE0, /* Clear the FIFCrst bit here */
1770 0x00
1771};
1772
1773/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
1774static const u8 MT2063B3_defaults[] = {
1775 /* Reg, Value */
1776 0x05, 0xF0,
1777 0x19, 0x3D,
1778 0x2C, 0x24, /* bit at 0x20 is cleared below */
1779 0x2C, 0x04, /* bit at 0x20 is cleared here */
1780 0x28, 0xE1, /* Set the FIFCrst bit here */
1781 0x28, 0xE0, /* Clear the FIFCrst bit here */
1782 0x00
1783};
1784
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001785static int mt2063_init(struct dvb_frontend *fe)
1786{
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001787 u32 status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001788 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001789 u8 all_resets = 0xF0; /* reset/load bits */
1790 const u8 *def = NULL;
1791 u32 FCRUN;
1792 s32 maxReads;
1793 u32 fcu_osc;
1794 u32 i;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001795
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001796 dprintk(2, "\n");
1797
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001798 state->rcvr_mode = MT2063_CABLE_QAM;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001799
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001800 /* Read the Part/Rev code from the tuner */
1801 status = mt2063_read(state, MT2063_REG_PART_REV, state->reg, 1);
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001802 if (status < 0) {
1803 printk(KERN_ERR "Can't read mt2063 part ID\n");
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001804 return status;
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001805 }
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001806
1807 /* Check the part/rev code */
1808 if (((state->reg[MT2063_REG_PART_REV] != MT2063_B0) /* MT2063 B0 */
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001809 && (state->reg[MT2063_REG_PART_REV] != MT2063_B1) /* MT2063 B1 */
1810 && (state->reg[MT2063_REG_PART_REV] != MT2063_B3))) /* MT2063 B3 */
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001811 return -ENODEV; /* Wrong tuner Part/Rev code */
1812
1813 /* Check the 2nd byte of the Part/Rev code from the tuner */
1814 status = mt2063_read(state, MT2063_REG_RSVD_3B,
1815 &state->reg[MT2063_REG_RSVD_3B], 1);
1816
1817 /* b7 != 0 ==> NOT MT2063 */
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001818 if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) {
1819 printk(KERN_ERR "Can't read mt2063 2nd part ID\n");
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001820 return -ENODEV; /* Wrong tuner Part/Rev code */
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001821 }
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001822
1823 /* Reset the tuner */
1824 status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
1825 if (status < 0)
1826 return status;
1827
1828 /* change all of the default values that vary from the HW reset values */
1829 /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
1830 switch (state->reg[MT2063_REG_PART_REV]) {
1831 case MT2063_B3:
1832 def = MT2063B3_defaults;
1833 break;
1834
1835 case MT2063_B1:
1836 def = MT2063B1_defaults;
1837 break;
1838
1839 case MT2063_B0:
1840 def = MT2063B0_defaults;
1841 break;
1842
1843 default:
1844 return -ENODEV;
1845 break;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001846 }
1847
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001848 while (status >= 0 && *def) {
1849 u8 reg = *def++;
1850 u8 val = *def++;
1851 status = mt2063_write(state, reg, &val, 1);
1852 }
1853 if (status < 0)
1854 return status;
1855
1856 /* Wait for FIFF location to complete. */
1857 FCRUN = 1;
1858 maxReads = 10;
1859 while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
1860 msleep(2);
1861 status = mt2063_read(state,
1862 MT2063_REG_XO_STATUS,
1863 &state->
1864 reg[MT2063_REG_XO_STATUS], 1);
1865 FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
1866 }
1867
1868 if (FCRUN != 0 || status < 0)
1869 return -ENODEV;
1870
1871 status = mt2063_read(state,
1872 MT2063_REG_FIFFC,
1873 &state->reg[MT2063_REG_FIFFC], 1);
1874 if (status < 0)
1875 return status;
1876
1877 /* Read back all the registers from the tuner */
1878 status = mt2063_read(state,
1879 MT2063_REG_PART_REV,
1880 state->reg, MT2063_REG_END_REGS);
1881 if (status < 0)
1882 return status;
1883
1884 /* Initialize the tuner state. */
1885 state->tuner_id = state->reg[MT2063_REG_PART_REV];
1886 state->AS_Data.f_ref = MT2063_REF_FREQ;
1887 state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
1888 ((u32) state->reg[MT2063_REG_FIFFC] + 640);
1889 state->AS_Data.f_if1_bw = MT2063_IF1_BW;
1890 state->AS_Data.f_out = 43750000UL;
1891 state->AS_Data.f_out_bw = 6750000UL;
1892 state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
1893 state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
1894 state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
1895 state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
1896 state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
1897 state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
1898 state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
1899 state->AS_Data.f_LO1 = 2181000000UL;
1900 state->AS_Data.f_LO2 = 1486249786UL;
1901 state->f_IF1_actual = state->AS_Data.f_if1_Center;
1902 state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
1903 state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
1904 state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
1905 state->num_regs = MT2063_REG_END_REGS;
1906 state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
1907 state->ctfilt_sw = 0;
1908
1909 state->CTFiltMax[0] = 69230000;
1910 state->CTFiltMax[1] = 105770000;
1911 state->CTFiltMax[2] = 140350000;
1912 state->CTFiltMax[3] = 177110000;
1913 state->CTFiltMax[4] = 212860000;
1914 state->CTFiltMax[5] = 241130000;
1915 state->CTFiltMax[6] = 274370000;
1916 state->CTFiltMax[7] = 309820000;
1917 state->CTFiltMax[8] = 342450000;
1918 state->CTFiltMax[9] = 378870000;
1919 state->CTFiltMax[10] = 416210000;
1920 state->CTFiltMax[11] = 456500000;
1921 state->CTFiltMax[12] = 495790000;
1922 state->CTFiltMax[13] = 534530000;
1923 state->CTFiltMax[14] = 572610000;
1924 state->CTFiltMax[15] = 598970000;
1925 state->CTFiltMax[16] = 635910000;
1926 state->CTFiltMax[17] = 672130000;
1927 state->CTFiltMax[18] = 714840000;
1928 state->CTFiltMax[19] = 739660000;
1929 state->CTFiltMax[20] = 770410000;
1930 state->CTFiltMax[21] = 814660000;
1931 state->CTFiltMax[22] = 846950000;
1932 state->CTFiltMax[23] = 867820000;
1933 state->CTFiltMax[24] = 915980000;
1934 state->CTFiltMax[25] = 947450000;
1935 state->CTFiltMax[26] = 983110000;
1936 state->CTFiltMax[27] = 1021630000;
1937 state->CTFiltMax[28] = 1061870000;
1938 state->CTFiltMax[29] = 1098330000;
1939 state->CTFiltMax[30] = 1138990000;
1940
1941 /*
1942 ** Fetch the FCU osc value and use it and the fRef value to
1943 ** scale all of the Band Max values
1944 */
1945
1946 state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
1947 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
1948 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
1949 if (status < 0)
1950 return status;
1951
1952 /* Read the ClearTune filter calibration value */
1953 status = mt2063_read(state, MT2063_REG_FIFFC,
1954 &state->reg[MT2063_REG_FIFFC], 1);
1955 if (status < 0)
1956 return status;
1957
1958 fcu_osc = state->reg[MT2063_REG_FIFFC];
1959
1960 state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
1961 status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
1962 &state->reg[MT2063_REG_CTUNE_CTRL], 1);
1963 if (status < 0)
1964 return status;
1965
1966 /* Adjust each of the values in the ClearTune filter cross-over table */
1967 for (i = 0; i < 31; i++)
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03001968 state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640);
Mauro Carvalho Chehab01e0daf2011-07-21 03:20:43 -03001969
1970 status = MT2063_SoftwareShutdown(state, 1);
1971 if (status < 0)
1972 return status;
1973 status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
1974 if (status < 0)
1975 return status;
1976
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001977 return 0;
1978}
1979
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03001980static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status)
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001981{
Mauro Carvalho Chehab51f0f7b2011-07-21 02:24:18 -03001982 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03001983 int status;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001984
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03001985 dprintk(2, "\n");
1986
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03001987 *tuner_status = 0;
1988 status = mt2063_lockStatus(state);
1989 if (status < 0)
1990 return status;
1991 if (status)
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03001992 *tuner_status = TUNER_STATUS_LOCKED;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001993
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03001994 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001995}
1996
1997static int mt2063_release(struct dvb_frontend *fe)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03001998{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03001999 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002000
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03002001 dprintk(2, "\n");
2002
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002003 fe->tuner_priv = NULL;
2004 kfree(state);
2005
2006 return 0;
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002007}
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002008
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002009static int mt2063_set_analog_params(struct dvb_frontend *fe,
2010 struct analog_parameters *params)
2011{
2012 struct mt2063_state *state = fe->tuner_priv;
Mauro Carvalho Chehab2e1d5882011-07-22 17:05:15 -03002013 s32 pict_car;
2014 s32 pict2chanb_vsb;
2015 s32 ch_bw;
2016 s32 if_mid;
2017 s32 rcvr_mode;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002018 int status;
2019
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03002020 dprintk(2, "\n");
2021
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002022 switch (params->mode) {
2023 case V4L2_TUNER_RADIO:
2024 pict_car = 38900000;
2025 ch_bw = 8000000;
2026 pict2chanb_vsb = -(ch_bw / 2);
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002027 rcvr_mode = MT2063_OFFAIR_ANALOG;
2028 break;
2029 case V4L2_TUNER_ANALOG_TV:
2030 rcvr_mode = MT2063_CABLE_ANALOG;
2031 if (params->std & ~V4L2_STD_MN) {
2032 pict_car = 38900000;
2033 ch_bw = 6000000;
2034 pict2chanb_vsb = -1250000;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002035 } else if (params->std & V4L2_STD_PAL_G) {
2036 pict_car = 38900000;
2037 ch_bw = 7000000;
2038 pict2chanb_vsb = -1250000;
Mauro Carvalho Chehab2e1d5882011-07-22 17:05:15 -03002039 } else { /* PAL/SECAM standards */
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002040 pict_car = 38900000;
2041 ch_bw = 8000000;
2042 pict2chanb_vsb = -1250000;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002043 }
2044 break;
Mauro Carvalho Chehab2e1d5882011-07-22 17:05:15 -03002045 default:
2046 return -EINVAL;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002047 }
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002048 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2049
2050 state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */
2051 state->AS_Data.f_out = if_mid;
2052 state->AS_Data.f_out_bw = ch_bw + 750000;
2053 status = MT2063_SetReceiverMode(state, rcvr_mode);
2054 if (status < 0)
2055 return status;
2056
2057 status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
2058 if (status < 0)
2059 return status;
2060
2061 state->frequency = params->frequency;
2062 return 0;
2063}
2064
2065/*
2066 * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
2067 * So, the amount of the needed bandwith is given by:
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03002068 * Bw = Symbol_rate * (1 + 0.15)
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002069 * As such, the maximum symbol rate supported by 6 MHz is given by:
2070 * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
2071 */
2072#define MAX_SYMBOL_RATE_6MHz 5217391
2073
Mauro Carvalho Chehab669b67d2012-01-04 22:29:32 -02002074static int mt2063_set_params(struct dvb_frontend *fe)
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002075{
Mauro Carvalho Chehab669b67d2012-01-04 22:29:32 -02002076 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002077 struct mt2063_state *state = fe->tuner_priv;
2078 int status;
Mauro Carvalho Chehab2e1d5882011-07-22 17:05:15 -03002079 s32 pict_car;
2080 s32 pict2chanb_vsb;
2081 s32 ch_bw;
2082 s32 if_mid;
2083 s32 rcvr_mode;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002084
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03002085 dprintk(2, "\n");
2086
Mauro Carvalho Chehab669b67d2012-01-04 22:29:32 -02002087 if (c->bandwidth_hz == 0)
2088 return -EINVAL;
2089 if (c->bandwidth_hz <= 6000000)
2090 ch_bw = 6000000;
2091 else if (c->bandwidth_hz <= 7000000)
2092 ch_bw = 7000000;
2093 else
2094 ch_bw = 8000000;
2095
2096 switch (c->delivery_system) {
2097 case SYS_DVBT:
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002098 rcvr_mode = MT2063_OFFAIR_COFDM;
2099 pict_car = 36125000;
2100 pict2chanb_vsb = -(ch_bw / 2);
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002101 break;
Mauro Carvalho Chehab669b67d2012-01-04 22:29:32 -02002102 case SYS_DVBC_ANNEX_A:
2103 case SYS_DVBC_ANNEX_C:
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002104 rcvr_mode = MT2063_CABLE_QAM;
2105 pict_car = 36125000;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002106 pict2chanb_vsb = -(ch_bw / 2);
2107 break;
2108 default:
2109 return -EINVAL;
2110 }
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002111 if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
2112
2113 state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */
2114 state->AS_Data.f_out = if_mid;
2115 state->AS_Data.f_out_bw = ch_bw + 750000;
2116 status = MT2063_SetReceiverMode(state, rcvr_mode);
2117 if (status < 0)
2118 return status;
2119
Mauro Carvalho Chehab669b67d2012-01-04 22:29:32 -02002120 status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2))));
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002121
2122 if (status < 0)
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03002123 return status;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002124
Mauro Carvalho Chehab669b67d2012-01-04 22:29:32 -02002125 state->frequency = c->frequency;
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002126 return 0;
2127}
2128
2129static int mt2063_get_frequency(struct dvb_frontend *fe, u32 *freq)
2130{
2131 struct mt2063_state *state = fe->tuner_priv;
2132
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03002133 dprintk(2, "\n");
2134
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002135 *freq = state->frequency;
2136 return 0;
2137}
2138
2139static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
2140{
2141 struct mt2063_state *state = fe->tuner_priv;
2142
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03002143 dprintk(2, "\n");
2144
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002145 *bw = state->AS_Data.f_out_bw - 750000;
2146 return 0;
2147}
2148
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002149static struct dvb_tuner_ops mt2063_ops = {
2150 .info = {
2151 .name = "MT2063 Silicon Tuner",
2152 .frequency_min = 45000000,
2153 .frequency_max = 850000000,
2154 .frequency_step = 0,
2155 },
2156
2157 .init = mt2063_init,
Mauro Carvalho Chehabbf975552011-07-20 21:43:30 -03002158 .sleep = MT2063_Sleep,
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002159 .get_status = mt2063_get_status,
Mauro Carvalho Chehab99ac5412011-07-21 15:46:49 -03002160 .set_analog_params = mt2063_set_analog_params,
2161 .set_params = mt2063_set_params,
2162 .get_frequency = mt2063_get_frequency,
2163 .get_bandwidth = mt2063_get_bandwidth,
2164 .release = mt2063_release,
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002165};
2166
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002167struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
2168 struct mt2063_config *config,
2169 struct i2c_adapter *i2c)
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002170{
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002171 struct mt2063_state *state = NULL;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002172
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03002173 dprintk(2, "\n");
2174
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002175 state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002176 if (state == NULL)
2177 goto error;
2178
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002179 state->config = config;
2180 state->i2c = i2c;
2181 state->frontend = fe;
2182 state->reference = config->refclock / 1000; /* kHz */
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002183 fe->tuner_priv = state;
2184 fe->ops.tuner_ops = mt2063_ops;
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002185
Mauro Carvalho Chehab6fb16702011-07-21 14:12:04 -03002186 printk(KERN_INFO "%s: Attaching MT2063\n", __func__);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002187 return fe;
2188
2189error:
2190 kfree(state);
2191 return NULL;
2192}
Mauro Carvalho Chehab3d497002011-07-21 11:00:59 -03002193EXPORT_SYMBOL_GPL(mt2063_attach);
Mauro Carvalho Chehab223c7b02011-07-20 19:48:59 -03002194
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03002195/*
2196 * Ancillary routines visible outside mt2063
2197 * FIXME: Remove them in favor of using standard tuner callbacks
2198 */
2199unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
2200{
2201 struct mt2063_state *state = fe->tuner_priv;
2202 int err = 0;
2203
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03002204 dprintk(2, "\n");
2205
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03002206 err = MT2063_SoftwareShutdown(state, 1);
2207 if (err < 0)
2208 printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
2209
2210 return err;
2211}
2212EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
2213
2214unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
2215{
2216 struct mt2063_state *state = fe->tuner_priv;
2217 int err = 0;
2218
Mauro Carvalho Chehabdb6587b2011-07-22 16:54:05 -03002219 dprintk(2, "\n");
2220
Mauro Carvalho Chehab8294e3e2011-07-21 13:33:32 -03002221 err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
2222 if (err < 0)
2223 printk(KERN_ERR "%s: Invalid parameter\n", __func__);
2224
2225 return err;
2226}
2227EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
2228
Mauro Carvalho Chehab54a46132011-07-21 16:40:03 -03002229MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
Mauro Carvalho Chehab0e301442011-07-20 19:52:49 -03002230MODULE_DESCRIPTION("MT2063 Silicon tuner");
2231MODULE_LICENSE("GPL");