xref: /openbmc/linux/drivers/media/tuners/tda18271-fe.c (revision 4cfae67515ed4c7bf5bb94fde20130153936f465)
1ccae7af2SMauro Carvalho Chehab /*
2ccae7af2SMauro Carvalho Chehab     tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
3ccae7af2SMauro Carvalho Chehab 
4ccae7af2SMauro Carvalho Chehab     Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
5ccae7af2SMauro Carvalho Chehab 
6ccae7af2SMauro Carvalho Chehab     This program is free software; you can redistribute it and/or modify
7ccae7af2SMauro Carvalho Chehab     it under the terms of the GNU General Public License as published by
8ccae7af2SMauro Carvalho Chehab     the Free Software Foundation; either version 2 of the License, or
9ccae7af2SMauro Carvalho Chehab     (at your option) any later version.
10ccae7af2SMauro Carvalho Chehab 
11ccae7af2SMauro Carvalho Chehab     This program is distributed in the hope that it will be useful,
12ccae7af2SMauro Carvalho Chehab     but WITHOUT ANY WARRANTY; without even the implied warranty of
13ccae7af2SMauro Carvalho Chehab     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14ccae7af2SMauro Carvalho Chehab     GNU General Public License for more details.
15ccae7af2SMauro Carvalho Chehab 
16ccae7af2SMauro Carvalho Chehab     You should have received a copy of the GNU General Public License
17ccae7af2SMauro Carvalho Chehab     along with this program; if not, write to the Free Software
18ccae7af2SMauro Carvalho Chehab     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19ccae7af2SMauro Carvalho Chehab */
20ccae7af2SMauro Carvalho Chehab 
21ccae7af2SMauro Carvalho Chehab #include <linux/delay.h>
22ccae7af2SMauro Carvalho Chehab #include <linux/videodev2.h>
23ccae7af2SMauro Carvalho Chehab #include "tda18271-priv.h"
24ccae7af2SMauro Carvalho Chehab 
25ccae7af2SMauro Carvalho Chehab int tda18271_debug;
26ccae7af2SMauro Carvalho Chehab module_param_named(debug, tda18271_debug, int, 0644);
27ccae7af2SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "set debug level "
28ccae7af2SMauro Carvalho Chehab 		 "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
29ccae7af2SMauro Carvalho Chehab 
30ccae7af2SMauro Carvalho Chehab static int tda18271_cal_on_startup = -1;
31ccae7af2SMauro Carvalho Chehab module_param_named(cal, tda18271_cal_on_startup, int, 0644);
32ccae7af2SMauro Carvalho Chehab MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
33ccae7af2SMauro Carvalho Chehab 
34ccae7af2SMauro Carvalho Chehab static DEFINE_MUTEX(tda18271_list_mutex);
35ccae7af2SMauro Carvalho Chehab static LIST_HEAD(hybrid_tuner_instance_list);
36ccae7af2SMauro Carvalho Chehab 
37ccae7af2SMauro Carvalho Chehab /*---------------------------------------------------------------------*/
38ccae7af2SMauro Carvalho Chehab 
39ccae7af2SMauro Carvalho Chehab static int tda18271_toggle_output(struct dvb_frontend *fe, int standby)
40ccae7af2SMauro Carvalho Chehab {
41ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
42ccae7af2SMauro Carvalho Chehab 
43ccae7af2SMauro Carvalho Chehab 	int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0,
44ccae7af2SMauro Carvalho Chehab 			priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0,
45ccae7af2SMauro Carvalho Chehab 			priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0);
46ccae7af2SMauro Carvalho Chehab 
47ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
48ccae7af2SMauro Carvalho Chehab 		goto fail;
49ccae7af2SMauro Carvalho Chehab 
50ccae7af2SMauro Carvalho Chehab 	tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n",
51ccae7af2SMauro Carvalho Chehab 		standby ? "standby" : "active",
52ccae7af2SMauro Carvalho Chehab 		priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on",
53ccae7af2SMauro Carvalho Chehab 		priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on");
54ccae7af2SMauro Carvalho Chehab fail:
55ccae7af2SMauro Carvalho Chehab 	return ret;
56ccae7af2SMauro Carvalho Chehab }
57ccae7af2SMauro Carvalho Chehab 
58ccae7af2SMauro Carvalho Chehab /*---------------------------------------------------------------------*/
59ccae7af2SMauro Carvalho Chehab 
60ccae7af2SMauro Carvalho Chehab static inline int charge_pump_source(struct dvb_frontend *fe, int force)
61ccae7af2SMauro Carvalho Chehab {
62ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
63ccae7af2SMauro Carvalho Chehab 	return tda18271_charge_pump_source(fe,
64ccae7af2SMauro Carvalho Chehab 					   (priv->role == TDA18271_SLAVE) ?
65ccae7af2SMauro Carvalho Chehab 					   TDA18271_CAL_PLL :
66ccae7af2SMauro Carvalho Chehab 					   TDA18271_MAIN_PLL, force);
67ccae7af2SMauro Carvalho Chehab }
68ccae7af2SMauro Carvalho Chehab 
69ccae7af2SMauro Carvalho Chehab static inline void tda18271_set_if_notch(struct dvb_frontend *fe)
70ccae7af2SMauro Carvalho Chehab {
71ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
72ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
73ccae7af2SMauro Carvalho Chehab 
74ccae7af2SMauro Carvalho Chehab 	switch (priv->mode) {
75ccae7af2SMauro Carvalho Chehab 	case TDA18271_ANALOG:
76ccae7af2SMauro Carvalho Chehab 		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
77ccae7af2SMauro Carvalho Chehab 		break;
78ccae7af2SMauro Carvalho Chehab 	case TDA18271_DIGITAL:
79ccae7af2SMauro Carvalho Chehab 		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
80ccae7af2SMauro Carvalho Chehab 		break;
81ccae7af2SMauro Carvalho Chehab 	}
82ccae7af2SMauro Carvalho Chehab }
83ccae7af2SMauro Carvalho Chehab 
84ccae7af2SMauro Carvalho Chehab static int tda18271_channel_configuration(struct dvb_frontend *fe,
85ccae7af2SMauro Carvalho Chehab 					  struct tda18271_std_map_item *map,
86ccae7af2SMauro Carvalho Chehab 					  u32 freq, u32 bw)
87ccae7af2SMauro Carvalho Chehab {
88ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
89ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
90ccae7af2SMauro Carvalho Chehab 	int ret;
91ccae7af2SMauro Carvalho Chehab 	u32 N;
92ccae7af2SMauro Carvalho Chehab 
93ccae7af2SMauro Carvalho Chehab 	/* update TV broadcast parameters */
94ccae7af2SMauro Carvalho Chehab 
95ccae7af2SMauro Carvalho Chehab 	/* set standard */
96ccae7af2SMauro Carvalho Chehab 	regs[R_EP3]  &= ~0x1f; /* clear std bits */
97ccae7af2SMauro Carvalho Chehab 	regs[R_EP3]  |= (map->agc_mode << 3) | map->std;
98ccae7af2SMauro Carvalho Chehab 
99ccae7af2SMauro Carvalho Chehab 	if (priv->id == TDA18271HDC2) {
100ccae7af2SMauro Carvalho Chehab 		/* set rfagc to high speed mode */
101ccae7af2SMauro Carvalho Chehab 		regs[R_EP3] &= ~0x04;
102ccae7af2SMauro Carvalho Chehab 	}
103ccae7af2SMauro Carvalho Chehab 
104ccae7af2SMauro Carvalho Chehab 	/* set cal mode to normal */
105ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x03;
106ccae7af2SMauro Carvalho Chehab 
107ccae7af2SMauro Carvalho Chehab 	/* update IF output level */
108ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
109ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  |= (map->if_lvl << 2);
110ccae7af2SMauro Carvalho Chehab 
111ccae7af2SMauro Carvalho Chehab 	/* update FM_RFn */
112ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x80;
113ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  |= map->fm_rfn << 7;
114ccae7af2SMauro Carvalho Chehab 
115ccae7af2SMauro Carvalho Chehab 	/* update rf top / if top */
116ccae7af2SMauro Carvalho Chehab 	regs[R_EB22]  = 0x00;
117ccae7af2SMauro Carvalho Chehab 	regs[R_EB22] |= map->rfagc_top;
118ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EB22, 1);
119ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
120ccae7af2SMauro Carvalho Chehab 		goto fail;
121ccae7af2SMauro Carvalho Chehab 
122ccae7af2SMauro Carvalho Chehab 	/* --------------------------------------------------------------- */
123ccae7af2SMauro Carvalho Chehab 
124ccae7af2SMauro Carvalho Chehab 	/* disable Power Level Indicator */
125ccae7af2SMauro Carvalho Chehab 	regs[R_EP1]  |= 0x40;
126ccae7af2SMauro Carvalho Chehab 
127ccae7af2SMauro Carvalho Chehab 	/* make sure thermometer is off */
128ccae7af2SMauro Carvalho Chehab 	regs[R_TM]   &= ~0x10;
129ccae7af2SMauro Carvalho Chehab 
130ccae7af2SMauro Carvalho Chehab 	/* frequency dependent parameters */
131ccae7af2SMauro Carvalho Chehab 
132ccae7af2SMauro Carvalho Chehab 	tda18271_calc_ir_measure(fe, &freq);
133ccae7af2SMauro Carvalho Chehab 
134ccae7af2SMauro Carvalho Chehab 	tda18271_calc_bp_filter(fe, &freq);
135ccae7af2SMauro Carvalho Chehab 
136ccae7af2SMauro Carvalho Chehab 	tda18271_calc_rf_band(fe, &freq);
137ccae7af2SMauro Carvalho Chehab 
138ccae7af2SMauro Carvalho Chehab 	tda18271_calc_gain_taper(fe, &freq);
139ccae7af2SMauro Carvalho Chehab 
140ccae7af2SMauro Carvalho Chehab 	/* --------------------------------------------------------------- */
141ccae7af2SMauro Carvalho Chehab 
142ccae7af2SMauro Carvalho Chehab 	/* dual tuner and agc1 extra configuration */
143ccae7af2SMauro Carvalho Chehab 
144ccae7af2SMauro Carvalho Chehab 	switch (priv->role) {
145ccae7af2SMauro Carvalho Chehab 	case TDA18271_MASTER:
146ccae7af2SMauro Carvalho Chehab 		regs[R_EB1]  |= 0x04; /* main vco */
147ccae7af2SMauro Carvalho Chehab 		break;
148ccae7af2SMauro Carvalho Chehab 	case TDA18271_SLAVE:
149ccae7af2SMauro Carvalho Chehab 		regs[R_EB1]  &= ~0x04; /* cal vco */
150ccae7af2SMauro Carvalho Chehab 		break;
151ccae7af2SMauro Carvalho Chehab 	}
152ccae7af2SMauro Carvalho Chehab 
153ccae7af2SMauro Carvalho Chehab 	/* agc1 always active */
154ccae7af2SMauro Carvalho Chehab 	regs[R_EB1]  &= ~0x02;
155ccae7af2SMauro Carvalho Chehab 
156ccae7af2SMauro Carvalho Chehab 	/* agc1 has priority on agc2 */
157ccae7af2SMauro Carvalho Chehab 	regs[R_EB1]  &= ~0x01;
158ccae7af2SMauro Carvalho Chehab 
159ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EB1, 1);
160ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
161ccae7af2SMauro Carvalho Chehab 		goto fail;
162ccae7af2SMauro Carvalho Chehab 
163ccae7af2SMauro Carvalho Chehab 	/* --------------------------------------------------------------- */
164ccae7af2SMauro Carvalho Chehab 
165ccae7af2SMauro Carvalho Chehab 	N = map->if_freq * 1000 + freq;
166ccae7af2SMauro Carvalho Chehab 
167ccae7af2SMauro Carvalho Chehab 	switch (priv->role) {
168ccae7af2SMauro Carvalho Chehab 	case TDA18271_MASTER:
169ccae7af2SMauro Carvalho Chehab 		tda18271_calc_main_pll(fe, N);
170ccae7af2SMauro Carvalho Chehab 		tda18271_set_if_notch(fe);
171ccae7af2SMauro Carvalho Chehab 		tda18271_write_regs(fe, R_MPD, 4);
172ccae7af2SMauro Carvalho Chehab 		break;
173ccae7af2SMauro Carvalho Chehab 	case TDA18271_SLAVE:
174ccae7af2SMauro Carvalho Chehab 		tda18271_calc_cal_pll(fe, N);
175ccae7af2SMauro Carvalho Chehab 		tda18271_write_regs(fe, R_CPD, 4);
176ccae7af2SMauro Carvalho Chehab 
177ccae7af2SMauro Carvalho Chehab 		regs[R_MPD] = regs[R_CPD] & 0x7f;
178ccae7af2SMauro Carvalho Chehab 		tda18271_set_if_notch(fe);
179ccae7af2SMauro Carvalho Chehab 		tda18271_write_regs(fe, R_MPD, 1);
180ccae7af2SMauro Carvalho Chehab 		break;
181ccae7af2SMauro Carvalho Chehab 	}
182ccae7af2SMauro Carvalho Chehab 
183ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_TM, 7);
184ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
185ccae7af2SMauro Carvalho Chehab 		goto fail;
186ccae7af2SMauro Carvalho Chehab 
187ccae7af2SMauro Carvalho Chehab 	/* force charge pump source */
188ccae7af2SMauro Carvalho Chehab 	charge_pump_source(fe, 1);
189ccae7af2SMauro Carvalho Chehab 
190ccae7af2SMauro Carvalho Chehab 	msleep(1);
191ccae7af2SMauro Carvalho Chehab 
192ccae7af2SMauro Carvalho Chehab 	/* return pll to normal operation */
193ccae7af2SMauro Carvalho Chehab 	charge_pump_source(fe, 0);
194ccae7af2SMauro Carvalho Chehab 
195ccae7af2SMauro Carvalho Chehab 	msleep(20);
196ccae7af2SMauro Carvalho Chehab 
197ccae7af2SMauro Carvalho Chehab 	if (priv->id == TDA18271HDC2) {
198ccae7af2SMauro Carvalho Chehab 		/* set rfagc to normal speed mode */
199ccae7af2SMauro Carvalho Chehab 		if (map->fm_rfn)
200ccae7af2SMauro Carvalho Chehab 			regs[R_EP3] &= ~0x04;
201ccae7af2SMauro Carvalho Chehab 		else
202ccae7af2SMauro Carvalho Chehab 			regs[R_EP3] |= 0x04;
203ccae7af2SMauro Carvalho Chehab 		ret = tda18271_write_regs(fe, R_EP3, 1);
204ccae7af2SMauro Carvalho Chehab 	}
205ccae7af2SMauro Carvalho Chehab fail:
206ccae7af2SMauro Carvalho Chehab 	return ret;
207ccae7af2SMauro Carvalho Chehab }
208ccae7af2SMauro Carvalho Chehab 
209ccae7af2SMauro Carvalho Chehab static int tda18271_read_thermometer(struct dvb_frontend *fe)
210ccae7af2SMauro Carvalho Chehab {
211ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
212ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
213ccae7af2SMauro Carvalho Chehab 	int tm;
214ccae7af2SMauro Carvalho Chehab 
215ccae7af2SMauro Carvalho Chehab 	/* switch thermometer on */
216ccae7af2SMauro Carvalho Chehab 	regs[R_TM]   |= 0x10;
217ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_TM, 1);
218ccae7af2SMauro Carvalho Chehab 
219ccae7af2SMauro Carvalho Chehab 	/* read thermometer info */
220ccae7af2SMauro Carvalho Chehab 	tda18271_read_regs(fe);
221ccae7af2SMauro Carvalho Chehab 
222ccae7af2SMauro Carvalho Chehab 	if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
223ccae7af2SMauro Carvalho Chehab 	    (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
224ccae7af2SMauro Carvalho Chehab 
225ccae7af2SMauro Carvalho Chehab 		if ((regs[R_TM] & 0x20) == 0x20)
226ccae7af2SMauro Carvalho Chehab 			regs[R_TM] &= ~0x20;
227ccae7af2SMauro Carvalho Chehab 		else
228ccae7af2SMauro Carvalho Chehab 			regs[R_TM] |= 0x20;
229ccae7af2SMauro Carvalho Chehab 
230ccae7af2SMauro Carvalho Chehab 		tda18271_write_regs(fe, R_TM, 1);
231ccae7af2SMauro Carvalho Chehab 
232ccae7af2SMauro Carvalho Chehab 		msleep(10); /* temperature sensing */
233ccae7af2SMauro Carvalho Chehab 
234ccae7af2SMauro Carvalho Chehab 		/* read thermometer info */
235ccae7af2SMauro Carvalho Chehab 		tda18271_read_regs(fe);
236ccae7af2SMauro Carvalho Chehab 	}
237ccae7af2SMauro Carvalho Chehab 
238ccae7af2SMauro Carvalho Chehab 	tm = tda18271_lookup_thermometer(fe);
239ccae7af2SMauro Carvalho Chehab 
240ccae7af2SMauro Carvalho Chehab 	/* switch thermometer off */
241ccae7af2SMauro Carvalho Chehab 	regs[R_TM]   &= ~0x10;
242ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_TM, 1);
243ccae7af2SMauro Carvalho Chehab 
244ccae7af2SMauro Carvalho Chehab 	/* set CAL mode to normal */
245ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x03;
246ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP4, 1);
247ccae7af2SMauro Carvalho Chehab 
248ccae7af2SMauro Carvalho Chehab 	return tm;
249ccae7af2SMauro Carvalho Chehab }
250ccae7af2SMauro Carvalho Chehab 
251ccae7af2SMauro Carvalho Chehab /* ------------------------------------------------------------------ */
252ccae7af2SMauro Carvalho Chehab 
253ccae7af2SMauro Carvalho Chehab static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
254ccae7af2SMauro Carvalho Chehab 						     u32 freq)
255ccae7af2SMauro Carvalho Chehab {
256ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
257ccae7af2SMauro Carvalho Chehab 	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
258ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
259ccae7af2SMauro Carvalho Chehab 	int i, ret;
260ccae7af2SMauro Carvalho Chehab 	u8 tm_current, dc_over_dt, rf_tab;
261ccae7af2SMauro Carvalho Chehab 	s32 rfcal_comp, approx;
262ccae7af2SMauro Carvalho Chehab 
263ccae7af2SMauro Carvalho Chehab 	/* power up */
264ccae7af2SMauro Carvalho Chehab 	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
265ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
266ccae7af2SMauro Carvalho Chehab 		goto fail;
267ccae7af2SMauro Carvalho Chehab 
268ccae7af2SMauro Carvalho Chehab 	/* read die current temperature */
269ccae7af2SMauro Carvalho Chehab 	tm_current = tda18271_read_thermometer(fe);
270ccae7af2SMauro Carvalho Chehab 
271ccae7af2SMauro Carvalho Chehab 	/* frequency dependent parameters */
272ccae7af2SMauro Carvalho Chehab 
273ccae7af2SMauro Carvalho Chehab 	tda18271_calc_rf_cal(fe, &freq);
274ccae7af2SMauro Carvalho Chehab 	rf_tab = regs[R_EB14];
275ccae7af2SMauro Carvalho Chehab 
276ccae7af2SMauro Carvalho Chehab 	i = tda18271_lookup_rf_band(fe, &freq, NULL);
277ccae7af2SMauro Carvalho Chehab 	if (tda_fail(i))
278ccae7af2SMauro Carvalho Chehab 		return i;
279ccae7af2SMauro Carvalho Chehab 
280ccae7af2SMauro Carvalho Chehab 	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
281ccae7af2SMauro Carvalho Chehab 		approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) +
282ccae7af2SMauro Carvalho Chehab 			map[i].rf_b1 + rf_tab;
283ccae7af2SMauro Carvalho Chehab 	} else {
284ccae7af2SMauro Carvalho Chehab 		approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) +
285ccae7af2SMauro Carvalho Chehab 			map[i].rf_b2 + rf_tab;
286ccae7af2SMauro Carvalho Chehab 	}
287ccae7af2SMauro Carvalho Chehab 
288ccae7af2SMauro Carvalho Chehab 	if (approx < 0)
289ccae7af2SMauro Carvalho Chehab 		approx = 0;
290ccae7af2SMauro Carvalho Chehab 	if (approx > 255)
291ccae7af2SMauro Carvalho Chehab 		approx = 255;
292ccae7af2SMauro Carvalho Chehab 
293ccae7af2SMauro Carvalho Chehab 	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
294ccae7af2SMauro Carvalho Chehab 
295ccae7af2SMauro Carvalho Chehab 	/* calculate temperature compensation */
296ccae7af2SMauro Carvalho Chehab 	rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000;
297ccae7af2SMauro Carvalho Chehab 
298ccae7af2SMauro Carvalho Chehab 	regs[R_EB14] = (unsigned char)(approx + rfcal_comp);
299ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EB14, 1);
300ccae7af2SMauro Carvalho Chehab fail:
301ccae7af2SMauro Carvalho Chehab 	return ret;
302ccae7af2SMauro Carvalho Chehab }
303ccae7af2SMauro Carvalho Chehab 
304ccae7af2SMauro Carvalho Chehab static int tda18271_por(struct dvb_frontend *fe)
305ccae7af2SMauro Carvalho Chehab {
306ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
307ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
308ccae7af2SMauro Carvalho Chehab 	int ret;
309ccae7af2SMauro Carvalho Chehab 
310ccae7af2SMauro Carvalho Chehab 	/* power up detector 1 */
311ccae7af2SMauro Carvalho Chehab 	regs[R_EB12] &= ~0x20;
312ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EB12, 1);
313ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
314ccae7af2SMauro Carvalho Chehab 		goto fail;
315ccae7af2SMauro Carvalho Chehab 
316ccae7af2SMauro Carvalho Chehab 	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
317ccae7af2SMauro Carvalho Chehab 	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
318ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EB18, 1);
319ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
320ccae7af2SMauro Carvalho Chehab 		goto fail;
321ccae7af2SMauro Carvalho Chehab 
322ccae7af2SMauro Carvalho Chehab 	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
323ccae7af2SMauro Carvalho Chehab 
324ccae7af2SMauro Carvalho Chehab 	/* POR mode */
325ccae7af2SMauro Carvalho Chehab 	ret = tda18271_set_standby_mode(fe, 1, 0, 0);
326ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
327ccae7af2SMauro Carvalho Chehab 		goto fail;
328ccae7af2SMauro Carvalho Chehab 
329ccae7af2SMauro Carvalho Chehab 	/* disable 1.5 MHz low pass filter */
330ccae7af2SMauro Carvalho Chehab 	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
331ccae7af2SMauro Carvalho Chehab 	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
332ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EB21, 3);
333ccae7af2SMauro Carvalho Chehab fail:
334ccae7af2SMauro Carvalho Chehab 	return ret;
335ccae7af2SMauro Carvalho Chehab }
336ccae7af2SMauro Carvalho Chehab 
337ccae7af2SMauro Carvalho Chehab static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
338ccae7af2SMauro Carvalho Chehab {
339ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
340ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
341ccae7af2SMauro Carvalho Chehab 	u32 N;
342ccae7af2SMauro Carvalho Chehab 
343ccae7af2SMauro Carvalho Chehab 	/* set CAL mode to normal */
344ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x03;
345ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP4, 1);
346ccae7af2SMauro Carvalho Chehab 
347ccae7af2SMauro Carvalho Chehab 	/* switch off agc1 */
348ccae7af2SMauro Carvalho Chehab 	regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
349ccae7af2SMauro Carvalho Chehab 
350ccae7af2SMauro Carvalho Chehab 	regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
351ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB18, 1);
352ccae7af2SMauro Carvalho Chehab 
353ccae7af2SMauro Carvalho Chehab 	/* frequency dependent parameters */
354ccae7af2SMauro Carvalho Chehab 
355ccae7af2SMauro Carvalho Chehab 	tda18271_calc_bp_filter(fe, &freq);
356ccae7af2SMauro Carvalho Chehab 	tda18271_calc_gain_taper(fe, &freq);
357ccae7af2SMauro Carvalho Chehab 	tda18271_calc_rf_band(fe, &freq);
358ccae7af2SMauro Carvalho Chehab 	tda18271_calc_km(fe, &freq);
359ccae7af2SMauro Carvalho Chehab 
360ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP1, 3);
361ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB13, 1);
362ccae7af2SMauro Carvalho Chehab 
363ccae7af2SMauro Carvalho Chehab 	/* main pll charge pump source */
364ccae7af2SMauro Carvalho Chehab 	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
365ccae7af2SMauro Carvalho Chehab 
366ccae7af2SMauro Carvalho Chehab 	/* cal pll charge pump source */
367ccae7af2SMauro Carvalho Chehab 	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1);
368ccae7af2SMauro Carvalho Chehab 
369ccae7af2SMauro Carvalho Chehab 	/* force dcdc converter to 0 V */
370ccae7af2SMauro Carvalho Chehab 	regs[R_EB14] = 0x00;
371ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB14, 1);
372ccae7af2SMauro Carvalho Chehab 
373ccae7af2SMauro Carvalho Chehab 	/* disable plls lock */
374ccae7af2SMauro Carvalho Chehab 	regs[R_EB20] &= ~0x20;
375ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB20, 1);
376ccae7af2SMauro Carvalho Chehab 
377ccae7af2SMauro Carvalho Chehab 	/* set CAL mode to RF tracking filter calibration */
378ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  |= 0x03;
379ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP4, 2);
380ccae7af2SMauro Carvalho Chehab 
381ccae7af2SMauro Carvalho Chehab 	/* --------------------------------------------------------------- */
382ccae7af2SMauro Carvalho Chehab 
383ccae7af2SMauro Carvalho Chehab 	/* set the internal calibration signal */
384ccae7af2SMauro Carvalho Chehab 	N = freq;
385ccae7af2SMauro Carvalho Chehab 
386ccae7af2SMauro Carvalho Chehab 	tda18271_calc_cal_pll(fe, N);
387ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_CPD, 4);
388ccae7af2SMauro Carvalho Chehab 
389ccae7af2SMauro Carvalho Chehab 	/* downconvert internal calibration */
390ccae7af2SMauro Carvalho Chehab 	N += 1000000;
391ccae7af2SMauro Carvalho Chehab 
392ccae7af2SMauro Carvalho Chehab 	tda18271_calc_main_pll(fe, N);
393ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_MPD, 4);
394ccae7af2SMauro Carvalho Chehab 
395ccae7af2SMauro Carvalho Chehab 	msleep(5);
396ccae7af2SMauro Carvalho Chehab 
397ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP2, 1);
398ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP1, 1);
399ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP2, 1);
400ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP1, 1);
401ccae7af2SMauro Carvalho Chehab 
402ccae7af2SMauro Carvalho Chehab 	/* --------------------------------------------------------------- */
403ccae7af2SMauro Carvalho Chehab 
404ccae7af2SMauro Carvalho Chehab 	/* normal operation for the main pll */
405ccae7af2SMauro Carvalho Chehab 	tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
406ccae7af2SMauro Carvalho Chehab 
407ccae7af2SMauro Carvalho Chehab 	/* normal operation for the cal pll  */
408ccae7af2SMauro Carvalho Chehab 	tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0);
409ccae7af2SMauro Carvalho Chehab 
410ccae7af2SMauro Carvalho Chehab 	msleep(10); /* plls locking */
411ccae7af2SMauro Carvalho Chehab 
412ccae7af2SMauro Carvalho Chehab 	/* launch the rf tracking filters calibration */
413ccae7af2SMauro Carvalho Chehab 	regs[R_EB20]  |= 0x20;
414ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB20, 1);
415ccae7af2SMauro Carvalho Chehab 
416ccae7af2SMauro Carvalho Chehab 	msleep(60); /* calibration */
417ccae7af2SMauro Carvalho Chehab 
418ccae7af2SMauro Carvalho Chehab 	/* --------------------------------------------------------------- */
419ccae7af2SMauro Carvalho Chehab 
420ccae7af2SMauro Carvalho Chehab 	/* set CAL mode to normal */
421ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x03;
422ccae7af2SMauro Carvalho Chehab 
423ccae7af2SMauro Carvalho Chehab 	/* switch on agc1 */
424ccae7af2SMauro Carvalho Chehab 	regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
425ccae7af2SMauro Carvalho Chehab 
426ccae7af2SMauro Carvalho Chehab 	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
427ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB18, 1);
428ccae7af2SMauro Carvalho Chehab 
429ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP3, 2);
430ccae7af2SMauro Carvalho Chehab 
431ccae7af2SMauro Carvalho Chehab 	/* synchronization */
432ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP1, 1);
433ccae7af2SMauro Carvalho Chehab 
434ccae7af2SMauro Carvalho Chehab 	/* get calibration result */
435ccae7af2SMauro Carvalho Chehab 	tda18271_read_extended(fe);
436ccae7af2SMauro Carvalho Chehab 
437ccae7af2SMauro Carvalho Chehab 	return regs[R_EB14];
438ccae7af2SMauro Carvalho Chehab }
439ccae7af2SMauro Carvalho Chehab 
440ccae7af2SMauro Carvalho Chehab static int tda18271_powerscan(struct dvb_frontend *fe,
441ccae7af2SMauro Carvalho Chehab 			      u32 *freq_in, u32 *freq_out)
442ccae7af2SMauro Carvalho Chehab {
443ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
444ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
445ccae7af2SMauro Carvalho Chehab 	int sgn, bcal, count, wait, ret;
446ccae7af2SMauro Carvalho Chehab 	u8 cid_target;
447ccae7af2SMauro Carvalho Chehab 	u16 count_limit;
448ccae7af2SMauro Carvalho Chehab 	u32 freq;
449ccae7af2SMauro Carvalho Chehab 
450ccae7af2SMauro Carvalho Chehab 	freq = *freq_in;
451ccae7af2SMauro Carvalho Chehab 
452ccae7af2SMauro Carvalho Chehab 	tda18271_calc_rf_band(fe, &freq);
453ccae7af2SMauro Carvalho Chehab 	tda18271_calc_rf_cal(fe, &freq);
454ccae7af2SMauro Carvalho Chehab 	tda18271_calc_gain_taper(fe, &freq);
455ccae7af2SMauro Carvalho Chehab 	tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
456ccae7af2SMauro Carvalho Chehab 
457ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP2, 1);
458ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB14, 1);
459ccae7af2SMauro Carvalho Chehab 
460ccae7af2SMauro Carvalho Chehab 	/* downconvert frequency */
461ccae7af2SMauro Carvalho Chehab 	freq += 1000000;
462ccae7af2SMauro Carvalho Chehab 
463ccae7af2SMauro Carvalho Chehab 	tda18271_calc_main_pll(fe, freq);
464ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_MPD, 4);
465ccae7af2SMauro Carvalho Chehab 
466ccae7af2SMauro Carvalho Chehab 	msleep(5); /* pll locking */
467ccae7af2SMauro Carvalho Chehab 
468ccae7af2SMauro Carvalho Chehab 	/* detection mode */
469ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x03;
470ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  |= 0x01;
471ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP4, 1);
472ccae7af2SMauro Carvalho Chehab 
473ccae7af2SMauro Carvalho Chehab 	/* launch power detection measurement */
474ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP2, 1);
475ccae7af2SMauro Carvalho Chehab 
476ccae7af2SMauro Carvalho Chehab 	/* read power detection info, stored in EB10 */
477ccae7af2SMauro Carvalho Chehab 	ret = tda18271_read_extended(fe);
478ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
479ccae7af2SMauro Carvalho Chehab 		return ret;
480ccae7af2SMauro Carvalho Chehab 
481ccae7af2SMauro Carvalho Chehab 	/* algorithm initialization */
482ccae7af2SMauro Carvalho Chehab 	sgn = 1;
483ccae7af2SMauro Carvalho Chehab 	*freq_out = *freq_in;
484ccae7af2SMauro Carvalho Chehab 	bcal = 0;
485ccae7af2SMauro Carvalho Chehab 	count = 0;
486ccae7af2SMauro Carvalho Chehab 	wait = false;
487ccae7af2SMauro Carvalho Chehab 
488ccae7af2SMauro Carvalho Chehab 	while ((regs[R_EB10] & 0x3f) < cid_target) {
489ccae7af2SMauro Carvalho Chehab 		/* downconvert updated freq to 1 MHz */
490ccae7af2SMauro Carvalho Chehab 		freq = *freq_in + (sgn * count) + 1000000;
491ccae7af2SMauro Carvalho Chehab 
492ccae7af2SMauro Carvalho Chehab 		tda18271_calc_main_pll(fe, freq);
493ccae7af2SMauro Carvalho Chehab 		tda18271_write_regs(fe, R_MPD, 4);
494ccae7af2SMauro Carvalho Chehab 
495ccae7af2SMauro Carvalho Chehab 		if (wait) {
496ccae7af2SMauro Carvalho Chehab 			msleep(5); /* pll locking */
497ccae7af2SMauro Carvalho Chehab 			wait = false;
498ccae7af2SMauro Carvalho Chehab 		} else
499ccae7af2SMauro Carvalho Chehab 			udelay(100); /* pll locking */
500ccae7af2SMauro Carvalho Chehab 
501ccae7af2SMauro Carvalho Chehab 		/* launch power detection measurement */
502ccae7af2SMauro Carvalho Chehab 		tda18271_write_regs(fe, R_EP2, 1);
503ccae7af2SMauro Carvalho Chehab 
504ccae7af2SMauro Carvalho Chehab 		/* read power detection info, stored in EB10 */
505ccae7af2SMauro Carvalho Chehab 		ret = tda18271_read_extended(fe);
506ccae7af2SMauro Carvalho Chehab 		if (tda_fail(ret))
507ccae7af2SMauro Carvalho Chehab 			return ret;
508ccae7af2SMauro Carvalho Chehab 
509ccae7af2SMauro Carvalho Chehab 		count += 200;
510ccae7af2SMauro Carvalho Chehab 
511ccae7af2SMauro Carvalho Chehab 		if (count <= count_limit)
512ccae7af2SMauro Carvalho Chehab 			continue;
513ccae7af2SMauro Carvalho Chehab 
514ccae7af2SMauro Carvalho Chehab 		if (sgn <= 0)
515ccae7af2SMauro Carvalho Chehab 			break;
516ccae7af2SMauro Carvalho Chehab 
517ccae7af2SMauro Carvalho Chehab 		sgn = -1 * sgn;
518ccae7af2SMauro Carvalho Chehab 		count = 200;
519ccae7af2SMauro Carvalho Chehab 		wait = true;
520ccae7af2SMauro Carvalho Chehab 	}
521ccae7af2SMauro Carvalho Chehab 
522ccae7af2SMauro Carvalho Chehab 	if ((regs[R_EB10] & 0x3f) >= cid_target) {
523ccae7af2SMauro Carvalho Chehab 		bcal = 1;
524ccae7af2SMauro Carvalho Chehab 		*freq_out = freq - 1000000;
525ccae7af2SMauro Carvalho Chehab 	} else
526ccae7af2SMauro Carvalho Chehab 		bcal = 0;
527ccae7af2SMauro Carvalho Chehab 
528ccae7af2SMauro Carvalho Chehab 	tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
529ccae7af2SMauro Carvalho Chehab 		bcal, *freq_in, *freq_out, freq);
530ccae7af2SMauro Carvalho Chehab 
531ccae7af2SMauro Carvalho Chehab 	return bcal;
532ccae7af2SMauro Carvalho Chehab }
533ccae7af2SMauro Carvalho Chehab 
534ccae7af2SMauro Carvalho Chehab static int tda18271_powerscan_init(struct dvb_frontend *fe)
535ccae7af2SMauro Carvalho Chehab {
536ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
537ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
538ccae7af2SMauro Carvalho Chehab 	int ret;
539ccae7af2SMauro Carvalho Chehab 
540ccae7af2SMauro Carvalho Chehab 	/* set standard to digital */
541ccae7af2SMauro Carvalho Chehab 	regs[R_EP3]  &= ~0x1f; /* clear std bits */
542ccae7af2SMauro Carvalho Chehab 	regs[R_EP3]  |= 0x12;
543ccae7af2SMauro Carvalho Chehab 
544ccae7af2SMauro Carvalho Chehab 	/* set cal mode to normal */
545ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x03;
546ccae7af2SMauro Carvalho Chehab 
547ccae7af2SMauro Carvalho Chehab 	/* update IF output level */
548ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
549ccae7af2SMauro Carvalho Chehab 
550ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EP3, 2);
551ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
552ccae7af2SMauro Carvalho Chehab 		goto fail;
553ccae7af2SMauro Carvalho Chehab 
554ccae7af2SMauro Carvalho Chehab 	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
555ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EB18, 1);
556ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
557ccae7af2SMauro Carvalho Chehab 		goto fail;
558ccae7af2SMauro Carvalho Chehab 
559ccae7af2SMauro Carvalho Chehab 	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
560ccae7af2SMauro Carvalho Chehab 
561ccae7af2SMauro Carvalho Chehab 	/* 1.5 MHz low pass filter */
562ccae7af2SMauro Carvalho Chehab 	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
563ccae7af2SMauro Carvalho Chehab 	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
564ccae7af2SMauro Carvalho Chehab 
565ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EB21, 3);
566ccae7af2SMauro Carvalho Chehab fail:
567ccae7af2SMauro Carvalho Chehab 	return ret;
568ccae7af2SMauro Carvalho Chehab }
569ccae7af2SMauro Carvalho Chehab 
570ccae7af2SMauro Carvalho Chehab static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
571ccae7af2SMauro Carvalho Chehab {
572ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
573ccae7af2SMauro Carvalho Chehab 	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
574ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
575ccae7af2SMauro Carvalho Chehab 	int bcal, rf, i;
576ccae7af2SMauro Carvalho Chehab 	s32 divisor, dividend;
577ccae7af2SMauro Carvalho Chehab #define RF1 0
578ccae7af2SMauro Carvalho Chehab #define RF2 1
579ccae7af2SMauro Carvalho Chehab #define RF3 2
580ccae7af2SMauro Carvalho Chehab 	u32 rf_default[3];
581ccae7af2SMauro Carvalho Chehab 	u32 rf_freq[3];
582ccae7af2SMauro Carvalho Chehab 	s32 prog_cal[3];
583ccae7af2SMauro Carvalho Chehab 	s32 prog_tab[3];
584ccae7af2SMauro Carvalho Chehab 
585ccae7af2SMauro Carvalho Chehab 	i = tda18271_lookup_rf_band(fe, &freq, NULL);
586ccae7af2SMauro Carvalho Chehab 
587ccae7af2SMauro Carvalho Chehab 	if (tda_fail(i))
588ccae7af2SMauro Carvalho Chehab 		return i;
589ccae7af2SMauro Carvalho Chehab 
590ccae7af2SMauro Carvalho Chehab 	rf_default[RF1] = 1000 * map[i].rf1_def;
591ccae7af2SMauro Carvalho Chehab 	rf_default[RF2] = 1000 * map[i].rf2_def;
592ccae7af2SMauro Carvalho Chehab 	rf_default[RF3] = 1000 * map[i].rf3_def;
593ccae7af2SMauro Carvalho Chehab 
594ccae7af2SMauro Carvalho Chehab 	for (rf = RF1; rf <= RF3; rf++) {
595ccae7af2SMauro Carvalho Chehab 		if (0 == rf_default[rf])
596ccae7af2SMauro Carvalho Chehab 			return 0;
597ccae7af2SMauro Carvalho Chehab 		tda_cal("freq = %d, rf = %d\n", freq, rf);
598ccae7af2SMauro Carvalho Chehab 
599ccae7af2SMauro Carvalho Chehab 		/* look for optimized calibration frequency */
600ccae7af2SMauro Carvalho Chehab 		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
601ccae7af2SMauro Carvalho Chehab 		if (tda_fail(bcal))
602ccae7af2SMauro Carvalho Chehab 			return bcal;
603ccae7af2SMauro Carvalho Chehab 
604ccae7af2SMauro Carvalho Chehab 		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
605ccae7af2SMauro Carvalho Chehab 		prog_tab[rf] = (s32)regs[R_EB14];
606ccae7af2SMauro Carvalho Chehab 
607ccae7af2SMauro Carvalho Chehab 		if (1 == bcal)
608ccae7af2SMauro Carvalho Chehab 			prog_cal[rf] =
609ccae7af2SMauro Carvalho Chehab 				(s32)tda18271_calibrate_rf(fe, rf_freq[rf]);
610ccae7af2SMauro Carvalho Chehab 		else
611ccae7af2SMauro Carvalho Chehab 			prog_cal[rf] = prog_tab[rf];
612ccae7af2SMauro Carvalho Chehab 
613ccae7af2SMauro Carvalho Chehab 		switch (rf) {
614ccae7af2SMauro Carvalho Chehab 		case RF1:
615ccae7af2SMauro Carvalho Chehab 			map[i].rf_a1 = 0;
616ccae7af2SMauro Carvalho Chehab 			map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]);
617ccae7af2SMauro Carvalho Chehab 			map[i].rf1   = rf_freq[RF1] / 1000;
618ccae7af2SMauro Carvalho Chehab 			break;
619ccae7af2SMauro Carvalho Chehab 		case RF2:
620ccae7af2SMauro Carvalho Chehab 			dividend = (prog_cal[RF2] - prog_tab[RF2] -
621ccae7af2SMauro Carvalho Chehab 				    prog_cal[RF1] + prog_tab[RF1]);
622ccae7af2SMauro Carvalho Chehab 			divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000;
623ccae7af2SMauro Carvalho Chehab 			map[i].rf_a1 = (dividend / divisor);
624ccae7af2SMauro Carvalho Chehab 			map[i].rf2   = rf_freq[RF2] / 1000;
625ccae7af2SMauro Carvalho Chehab 			break;
626ccae7af2SMauro Carvalho Chehab 		case RF3:
627ccae7af2SMauro Carvalho Chehab 			dividend = (prog_cal[RF3] - prog_tab[RF3] -
628ccae7af2SMauro Carvalho Chehab 				    prog_cal[RF2] + prog_tab[RF2]);
629ccae7af2SMauro Carvalho Chehab 			divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000;
630ccae7af2SMauro Carvalho Chehab 			map[i].rf_a2 = (dividend / divisor);
631ccae7af2SMauro Carvalho Chehab 			map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]);
632ccae7af2SMauro Carvalho Chehab 			map[i].rf3   = rf_freq[RF3] / 1000;
633ccae7af2SMauro Carvalho Chehab 			break;
634ccae7af2SMauro Carvalho Chehab 		default:
635ccae7af2SMauro Carvalho Chehab 			BUG();
636ccae7af2SMauro Carvalho Chehab 		}
637ccae7af2SMauro Carvalho Chehab 	}
638ccae7af2SMauro Carvalho Chehab 
639ccae7af2SMauro Carvalho Chehab 	return 0;
640ccae7af2SMauro Carvalho Chehab }
641ccae7af2SMauro Carvalho Chehab 
642ccae7af2SMauro Carvalho Chehab static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
643ccae7af2SMauro Carvalho Chehab {
644ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
645ccae7af2SMauro Carvalho Chehab 	unsigned int i;
646ccae7af2SMauro Carvalho Chehab 	int ret;
647ccae7af2SMauro Carvalho Chehab 
648ccae7af2SMauro Carvalho Chehab 	tda_info("tda18271: performing RF tracking filter calibration\n");
649ccae7af2SMauro Carvalho Chehab 
650ccae7af2SMauro Carvalho Chehab 	/* wait for die temperature stabilization */
651ccae7af2SMauro Carvalho Chehab 	msleep(200);
652ccae7af2SMauro Carvalho Chehab 
653ccae7af2SMauro Carvalho Chehab 	ret = tda18271_powerscan_init(fe);
654ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
655ccae7af2SMauro Carvalho Chehab 		goto fail;
656ccae7af2SMauro Carvalho Chehab 
657ccae7af2SMauro Carvalho Chehab 	/* rf band calibration */
658ccae7af2SMauro Carvalho Chehab 	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) {
659ccae7af2SMauro Carvalho Chehab 		ret =
660ccae7af2SMauro Carvalho Chehab 		tda18271_rf_tracking_filters_init(fe, 1000 *
661ccae7af2SMauro Carvalho Chehab 						  priv->rf_cal_state[i].rfmax);
662ccae7af2SMauro Carvalho Chehab 		if (tda_fail(ret))
663ccae7af2SMauro Carvalho Chehab 			goto fail;
664ccae7af2SMauro Carvalho Chehab 	}
665ccae7af2SMauro Carvalho Chehab 
666ccae7af2SMauro Carvalho Chehab 	priv->tm_rfcal = tda18271_read_thermometer(fe);
667ccae7af2SMauro Carvalho Chehab fail:
668ccae7af2SMauro Carvalho Chehab 	return ret;
669ccae7af2SMauro Carvalho Chehab }
670ccae7af2SMauro Carvalho Chehab 
671ccae7af2SMauro Carvalho Chehab /* ------------------------------------------------------------------ */
672ccae7af2SMauro Carvalho Chehab 
673ccae7af2SMauro Carvalho Chehab static int tda18271c2_rf_cal_init(struct dvb_frontend *fe)
674ccae7af2SMauro Carvalho Chehab {
675ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
676ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
677ccae7af2SMauro Carvalho Chehab 	int ret;
678ccae7af2SMauro Carvalho Chehab 
679ccae7af2SMauro Carvalho Chehab 	/* test RF_CAL_OK to see if we need init */
680ccae7af2SMauro Carvalho Chehab 	if ((regs[R_EP1] & 0x10) == 0)
681ccae7af2SMauro Carvalho Chehab 		priv->cal_initialized = false;
682ccae7af2SMauro Carvalho Chehab 
683ccae7af2SMauro Carvalho Chehab 	if (priv->cal_initialized)
684ccae7af2SMauro Carvalho Chehab 		return 0;
685ccae7af2SMauro Carvalho Chehab 
686ccae7af2SMauro Carvalho Chehab 	ret = tda18271_calc_rf_filter_curve(fe);
687ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
688ccae7af2SMauro Carvalho Chehab 		goto fail;
689ccae7af2SMauro Carvalho Chehab 
690ccae7af2SMauro Carvalho Chehab 	ret = tda18271_por(fe);
691ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
692ccae7af2SMauro Carvalho Chehab 		goto fail;
693ccae7af2SMauro Carvalho Chehab 
694ccae7af2SMauro Carvalho Chehab 	tda_info("tda18271: RF tracking filter calibration complete\n");
695ccae7af2SMauro Carvalho Chehab 
696ccae7af2SMauro Carvalho Chehab 	priv->cal_initialized = true;
697ccae7af2SMauro Carvalho Chehab 	goto end;
698ccae7af2SMauro Carvalho Chehab fail:
699ccae7af2SMauro Carvalho Chehab 	tda_info("tda18271: RF tracking filter calibration failed!\n");
700ccae7af2SMauro Carvalho Chehab end:
701ccae7af2SMauro Carvalho Chehab 	return ret;
702ccae7af2SMauro Carvalho Chehab }
703ccae7af2SMauro Carvalho Chehab 
704ccae7af2SMauro Carvalho Chehab static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
705ccae7af2SMauro Carvalho Chehab 						     u32 freq, u32 bw)
706ccae7af2SMauro Carvalho Chehab {
707ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
708ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
709ccae7af2SMauro Carvalho Chehab 	int ret;
710ccae7af2SMauro Carvalho Chehab 	u32 N = 0;
711ccae7af2SMauro Carvalho Chehab 
712ccae7af2SMauro Carvalho Chehab 	/* calculate bp filter */
713ccae7af2SMauro Carvalho Chehab 	tda18271_calc_bp_filter(fe, &freq);
714ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP1, 1);
715ccae7af2SMauro Carvalho Chehab 
716ccae7af2SMauro Carvalho Chehab 	regs[R_EB4]  &= 0x07;
717ccae7af2SMauro Carvalho Chehab 	regs[R_EB4]  |= 0x60;
718ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB4, 1);
719ccae7af2SMauro Carvalho Chehab 
720ccae7af2SMauro Carvalho Chehab 	regs[R_EB7]   = 0x60;
721ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB7, 1);
722ccae7af2SMauro Carvalho Chehab 
723ccae7af2SMauro Carvalho Chehab 	regs[R_EB14]  = 0x00;
724ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB14, 1);
725ccae7af2SMauro Carvalho Chehab 
726ccae7af2SMauro Carvalho Chehab 	regs[R_EB20]  = 0xcc;
727ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB20, 1);
728ccae7af2SMauro Carvalho Chehab 
729ccae7af2SMauro Carvalho Chehab 	/* set cal mode to RF tracking filter calibration */
730ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  |= 0x03;
731ccae7af2SMauro Carvalho Chehab 
732ccae7af2SMauro Carvalho Chehab 	/* calculate cal pll */
733ccae7af2SMauro Carvalho Chehab 
734ccae7af2SMauro Carvalho Chehab 	switch (priv->mode) {
735ccae7af2SMauro Carvalho Chehab 	case TDA18271_ANALOG:
736ccae7af2SMauro Carvalho Chehab 		N = freq - 1250000;
737ccae7af2SMauro Carvalho Chehab 		break;
738ccae7af2SMauro Carvalho Chehab 	case TDA18271_DIGITAL:
739ccae7af2SMauro Carvalho Chehab 		N = freq + bw / 2;
740ccae7af2SMauro Carvalho Chehab 		break;
741ccae7af2SMauro Carvalho Chehab 	}
742ccae7af2SMauro Carvalho Chehab 
743ccae7af2SMauro Carvalho Chehab 	tda18271_calc_cal_pll(fe, N);
744ccae7af2SMauro Carvalho Chehab 
745ccae7af2SMauro Carvalho Chehab 	/* calculate main pll */
746ccae7af2SMauro Carvalho Chehab 
747ccae7af2SMauro Carvalho Chehab 	switch (priv->mode) {
748ccae7af2SMauro Carvalho Chehab 	case TDA18271_ANALOG:
749ccae7af2SMauro Carvalho Chehab 		N = freq - 250000;
750ccae7af2SMauro Carvalho Chehab 		break;
751ccae7af2SMauro Carvalho Chehab 	case TDA18271_DIGITAL:
752ccae7af2SMauro Carvalho Chehab 		N = freq + bw / 2 + 1000000;
753ccae7af2SMauro Carvalho Chehab 		break;
754ccae7af2SMauro Carvalho Chehab 	}
755ccae7af2SMauro Carvalho Chehab 
756ccae7af2SMauro Carvalho Chehab 	tda18271_calc_main_pll(fe, N);
757ccae7af2SMauro Carvalho Chehab 
758ccae7af2SMauro Carvalho Chehab 	ret = tda18271_write_regs(fe, R_EP3, 11);
759ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
760ccae7af2SMauro Carvalho Chehab 		return ret;
761ccae7af2SMauro Carvalho Chehab 
762ccae7af2SMauro Carvalho Chehab 	msleep(5); /* RF tracking filter calibration initialization */
763ccae7af2SMauro Carvalho Chehab 
764ccae7af2SMauro Carvalho Chehab 	/* search for K,M,CO for RF calibration */
765ccae7af2SMauro Carvalho Chehab 	tda18271_calc_km(fe, &freq);
766ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB13, 1);
767ccae7af2SMauro Carvalho Chehab 
768ccae7af2SMauro Carvalho Chehab 	/* search for rf band */
769ccae7af2SMauro Carvalho Chehab 	tda18271_calc_rf_band(fe, &freq);
770ccae7af2SMauro Carvalho Chehab 
771ccae7af2SMauro Carvalho Chehab 	/* search for gain taper */
772ccae7af2SMauro Carvalho Chehab 	tda18271_calc_gain_taper(fe, &freq);
773ccae7af2SMauro Carvalho Chehab 
774ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP2, 1);
775ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP1, 1);
776ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP2, 1);
777ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP1, 1);
778ccae7af2SMauro Carvalho Chehab 
779ccae7af2SMauro Carvalho Chehab 	regs[R_EB4]  &= 0x07;
780ccae7af2SMauro Carvalho Chehab 	regs[R_EB4]  |= 0x40;
781ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB4, 1);
782ccae7af2SMauro Carvalho Chehab 
783ccae7af2SMauro Carvalho Chehab 	regs[R_EB7]   = 0x40;
784ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB7, 1);
785ccae7af2SMauro Carvalho Chehab 	msleep(10); /* pll locking */
786ccae7af2SMauro Carvalho Chehab 
787ccae7af2SMauro Carvalho Chehab 	regs[R_EB20]  = 0xec;
788ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EB20, 1);
789ccae7af2SMauro Carvalho Chehab 	msleep(60); /* RF tracking filter calibration completion */
790ccae7af2SMauro Carvalho Chehab 
791ccae7af2SMauro Carvalho Chehab 	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
792ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP4, 1);
793ccae7af2SMauro Carvalho Chehab 
794ccae7af2SMauro Carvalho Chehab 	tda18271_write_regs(fe, R_EP1, 1);
795ccae7af2SMauro Carvalho Chehab 
796ccae7af2SMauro Carvalho Chehab 	/* RF tracking filter correction for VHF_Low band */
797ccae7af2SMauro Carvalho Chehab 	if (0 == tda18271_calc_rf_cal(fe, &freq))
798ccae7af2SMauro Carvalho Chehab 		tda18271_write_regs(fe, R_EB14, 1);
799ccae7af2SMauro Carvalho Chehab 
800ccae7af2SMauro Carvalho Chehab 	return 0;
801ccae7af2SMauro Carvalho Chehab }
802ccae7af2SMauro Carvalho Chehab 
803ccae7af2SMauro Carvalho Chehab /* ------------------------------------------------------------------ */
804ccae7af2SMauro Carvalho Chehab 
805ccae7af2SMauro Carvalho Chehab static int tda18271_ir_cal_init(struct dvb_frontend *fe)
806ccae7af2SMauro Carvalho Chehab {
807ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
808ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
809ccae7af2SMauro Carvalho Chehab 	int ret;
810ccae7af2SMauro Carvalho Chehab 
811ccae7af2SMauro Carvalho Chehab 	ret = tda18271_read_regs(fe);
812ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
813ccae7af2SMauro Carvalho Chehab 		goto fail;
814ccae7af2SMauro Carvalho Chehab 
815ccae7af2SMauro Carvalho Chehab 	/* test IR_CAL_OK to see if we need init */
816ccae7af2SMauro Carvalho Chehab 	if ((regs[R_EP1] & 0x08) == 0)
817ccae7af2SMauro Carvalho Chehab 		ret = tda18271_init_regs(fe);
818ccae7af2SMauro Carvalho Chehab fail:
819ccae7af2SMauro Carvalho Chehab 	return ret;
820ccae7af2SMauro Carvalho Chehab }
821ccae7af2SMauro Carvalho Chehab 
822ccae7af2SMauro Carvalho Chehab static int tda18271_init(struct dvb_frontend *fe)
823ccae7af2SMauro Carvalho Chehab {
824ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
825ccae7af2SMauro Carvalho Chehab 	int ret;
826ccae7af2SMauro Carvalho Chehab 
827ccae7af2SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
828ccae7af2SMauro Carvalho Chehab 
829ccae7af2SMauro Carvalho Chehab 	/* full power up */
830ccae7af2SMauro Carvalho Chehab 	ret = tda18271_set_standby_mode(fe, 0, 0, 0);
831ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
832ccae7af2SMauro Carvalho Chehab 		goto fail;
833ccae7af2SMauro Carvalho Chehab 
834ccae7af2SMauro Carvalho Chehab 	/* initialization */
835ccae7af2SMauro Carvalho Chehab 	ret = tda18271_ir_cal_init(fe);
836ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
837ccae7af2SMauro Carvalho Chehab 		goto fail;
838ccae7af2SMauro Carvalho Chehab 
839ccae7af2SMauro Carvalho Chehab 	if (priv->id == TDA18271HDC2)
840ccae7af2SMauro Carvalho Chehab 		tda18271c2_rf_cal_init(fe);
841ccae7af2SMauro Carvalho Chehab fail:
842ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
843ccae7af2SMauro Carvalho Chehab 
844ccae7af2SMauro Carvalho Chehab 	return ret;
845ccae7af2SMauro Carvalho Chehab }
846ccae7af2SMauro Carvalho Chehab 
847ccae7af2SMauro Carvalho Chehab static int tda18271_sleep(struct dvb_frontend *fe)
848ccae7af2SMauro Carvalho Chehab {
849ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
850ccae7af2SMauro Carvalho Chehab 	int ret;
851ccae7af2SMauro Carvalho Chehab 
852ccae7af2SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
853ccae7af2SMauro Carvalho Chehab 
854ccae7af2SMauro Carvalho Chehab 	/* enter standby mode, with required output features enabled */
855ccae7af2SMauro Carvalho Chehab 	ret = tda18271_toggle_output(fe, 1);
856ccae7af2SMauro Carvalho Chehab 
857ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
858ccae7af2SMauro Carvalho Chehab 
859ccae7af2SMauro Carvalho Chehab 	return ret;
860ccae7af2SMauro Carvalho Chehab }
861ccae7af2SMauro Carvalho Chehab 
862ccae7af2SMauro Carvalho Chehab /* ------------------------------------------------------------------ */
863ccae7af2SMauro Carvalho Chehab 
864ccae7af2SMauro Carvalho Chehab static int tda18271_agc(struct dvb_frontend *fe)
865ccae7af2SMauro Carvalho Chehab {
866ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
867ccae7af2SMauro Carvalho Chehab 	int ret = 0;
868ccae7af2SMauro Carvalho Chehab 
869ccae7af2SMauro Carvalho Chehab 	switch (priv->config) {
870ccae7af2SMauro Carvalho Chehab 	case 0:
871ccae7af2SMauro Carvalho Chehab 		/* no external agc configuration required */
872ccae7af2SMauro Carvalho Chehab 		if (tda18271_debug & DBG_ADV)
873ccae7af2SMauro Carvalho Chehab 			tda_dbg("no agc configuration provided\n");
874ccae7af2SMauro Carvalho Chehab 		break;
875ccae7af2SMauro Carvalho Chehab 	case 3:
876ccae7af2SMauro Carvalho Chehab 		/* switch with GPIO of saa713x */
877ccae7af2SMauro Carvalho Chehab 		tda_dbg("invoking callback\n");
878ccae7af2SMauro Carvalho Chehab 		if (fe->callback)
879ccae7af2SMauro Carvalho Chehab 			ret = fe->callback(priv->i2c_props.adap->algo_data,
880ccae7af2SMauro Carvalho Chehab 					   DVB_FRONTEND_COMPONENT_TUNER,
881ccae7af2SMauro Carvalho Chehab 					   TDA18271_CALLBACK_CMD_AGC_ENABLE,
882ccae7af2SMauro Carvalho Chehab 					   priv->mode);
883ccae7af2SMauro Carvalho Chehab 		break;
884ccae7af2SMauro Carvalho Chehab 	case 1:
885ccae7af2SMauro Carvalho Chehab 	case 2:
886ccae7af2SMauro Carvalho Chehab 	default:
887ccae7af2SMauro Carvalho Chehab 		/* n/a - currently not supported */
888ccae7af2SMauro Carvalho Chehab 		tda_err("unsupported configuration: %d\n", priv->config);
889ccae7af2SMauro Carvalho Chehab 		ret = -EINVAL;
890ccae7af2SMauro Carvalho Chehab 		break;
891ccae7af2SMauro Carvalho Chehab 	}
892ccae7af2SMauro Carvalho Chehab 	return ret;
893ccae7af2SMauro Carvalho Chehab }
894ccae7af2SMauro Carvalho Chehab 
895ccae7af2SMauro Carvalho Chehab static int tda18271_tune(struct dvb_frontend *fe,
896ccae7af2SMauro Carvalho Chehab 			 struct tda18271_std_map_item *map, u32 freq, u32 bw)
897ccae7af2SMauro Carvalho Chehab {
898ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
899ccae7af2SMauro Carvalho Chehab 	int ret;
900ccae7af2SMauro Carvalho Chehab 
901ccae7af2SMauro Carvalho Chehab 	tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
902ccae7af2SMauro Carvalho Chehab 		freq, map->if_freq, bw, map->agc_mode, map->std);
903ccae7af2SMauro Carvalho Chehab 
904ccae7af2SMauro Carvalho Chehab 	ret = tda18271_agc(fe);
905ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
906ccae7af2SMauro Carvalho Chehab 		tda_warn("failed to configure agc\n");
907ccae7af2SMauro Carvalho Chehab 
908ccae7af2SMauro Carvalho Chehab 	ret = tda18271_init(fe);
909ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
910ccae7af2SMauro Carvalho Chehab 		goto fail;
911ccae7af2SMauro Carvalho Chehab 
912ccae7af2SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
913ccae7af2SMauro Carvalho Chehab 
914ccae7af2SMauro Carvalho Chehab 	switch (priv->id) {
915ccae7af2SMauro Carvalho Chehab 	case TDA18271HDC1:
916ccae7af2SMauro Carvalho Chehab 		tda18271c1_rf_tracking_filter_calibration(fe, freq, bw);
917ccae7af2SMauro Carvalho Chehab 		break;
918ccae7af2SMauro Carvalho Chehab 	case TDA18271HDC2:
919ccae7af2SMauro Carvalho Chehab 		tda18271c2_rf_tracking_filters_correction(fe, freq);
920ccae7af2SMauro Carvalho Chehab 		break;
921ccae7af2SMauro Carvalho Chehab 	}
922ccae7af2SMauro Carvalho Chehab 	ret = tda18271_channel_configuration(fe, map, freq, bw);
923ccae7af2SMauro Carvalho Chehab 
924ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
925ccae7af2SMauro Carvalho Chehab fail:
926ccae7af2SMauro Carvalho Chehab 	return ret;
927ccae7af2SMauro Carvalho Chehab }
928ccae7af2SMauro Carvalho Chehab 
929ccae7af2SMauro Carvalho Chehab /* ------------------------------------------------------------------ */
930ccae7af2SMauro Carvalho Chehab 
931ccae7af2SMauro Carvalho Chehab static int tda18271_set_params(struct dvb_frontend *fe)
932ccae7af2SMauro Carvalho Chehab {
933ccae7af2SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
934ccae7af2SMauro Carvalho Chehab 	u32 delsys = c->delivery_system;
935ccae7af2SMauro Carvalho Chehab 	u32 bw = c->bandwidth_hz;
936ccae7af2SMauro Carvalho Chehab 	u32 freq = c->frequency;
937ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
938ccae7af2SMauro Carvalho Chehab 	struct tda18271_std_map *std_map = &priv->std;
939ccae7af2SMauro Carvalho Chehab 	struct tda18271_std_map_item *map;
940ccae7af2SMauro Carvalho Chehab 	int ret;
941ccae7af2SMauro Carvalho Chehab 
942ccae7af2SMauro Carvalho Chehab 	priv->mode = TDA18271_DIGITAL;
943ccae7af2SMauro Carvalho Chehab 
944ccae7af2SMauro Carvalho Chehab 	switch (delsys) {
945ccae7af2SMauro Carvalho Chehab 	case SYS_ATSC:
946ccae7af2SMauro Carvalho Chehab 		map = &std_map->atsc_6;
947ccae7af2SMauro Carvalho Chehab 		bw = 6000000;
948ccae7af2SMauro Carvalho Chehab 		break;
949ccae7af2SMauro Carvalho Chehab 	case SYS_ISDBT:
950ccae7af2SMauro Carvalho Chehab 	case SYS_DVBT:
951ccae7af2SMauro Carvalho Chehab 	case SYS_DVBT2:
952ccae7af2SMauro Carvalho Chehab 		if (bw <= 6000000) {
953ccae7af2SMauro Carvalho Chehab 			map = &std_map->dvbt_6;
954ccae7af2SMauro Carvalho Chehab 		} else if (bw <= 7000000) {
955ccae7af2SMauro Carvalho Chehab 			map = &std_map->dvbt_7;
956ccae7af2SMauro Carvalho Chehab 		} else {
957ccae7af2SMauro Carvalho Chehab 			map = &std_map->dvbt_8;
958ccae7af2SMauro Carvalho Chehab 		}
959ccae7af2SMauro Carvalho Chehab 		break;
960ccae7af2SMauro Carvalho Chehab 	case SYS_DVBC_ANNEX_B:
961ccae7af2SMauro Carvalho Chehab 		bw = 6000000;
962ccae7af2SMauro Carvalho Chehab 		/* falltrough */
963ccae7af2SMauro Carvalho Chehab 	case SYS_DVBC_ANNEX_A:
964ccae7af2SMauro Carvalho Chehab 	case SYS_DVBC_ANNEX_C:
965ccae7af2SMauro Carvalho Chehab 		if (bw <= 6000000) {
966ccae7af2SMauro Carvalho Chehab 			map = &std_map->qam_6;
967ccae7af2SMauro Carvalho Chehab 		} else if (bw <= 7000000) {
968ccae7af2SMauro Carvalho Chehab 			map = &std_map->qam_7;
969ccae7af2SMauro Carvalho Chehab 		} else {
970ccae7af2SMauro Carvalho Chehab 			map = &std_map->qam_8;
971ccae7af2SMauro Carvalho Chehab 		}
972ccae7af2SMauro Carvalho Chehab 		break;
973ccae7af2SMauro Carvalho Chehab 	default:
974ccae7af2SMauro Carvalho Chehab 		tda_warn("modulation type not supported!\n");
975ccae7af2SMauro Carvalho Chehab 		return -EINVAL;
976ccae7af2SMauro Carvalho Chehab 	}
977ccae7af2SMauro Carvalho Chehab 
978ccae7af2SMauro Carvalho Chehab 	/* When tuning digital, the analog demod must be tri-stated */
979ccae7af2SMauro Carvalho Chehab 	if (fe->ops.analog_ops.standby)
980ccae7af2SMauro Carvalho Chehab 		fe->ops.analog_ops.standby(fe);
981ccae7af2SMauro Carvalho Chehab 
982ccae7af2SMauro Carvalho Chehab 	ret = tda18271_tune(fe, map, freq, bw);
983ccae7af2SMauro Carvalho Chehab 
984ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
985ccae7af2SMauro Carvalho Chehab 		goto fail;
986ccae7af2SMauro Carvalho Chehab 
987ccae7af2SMauro Carvalho Chehab 	priv->if_freq   = map->if_freq;
988ccae7af2SMauro Carvalho Chehab 	priv->frequency = freq;
989ccae7af2SMauro Carvalho Chehab 	priv->bandwidth = bw;
990ccae7af2SMauro Carvalho Chehab fail:
991ccae7af2SMauro Carvalho Chehab 	return ret;
992ccae7af2SMauro Carvalho Chehab }
993ccae7af2SMauro Carvalho Chehab 
994ccae7af2SMauro Carvalho Chehab static int tda18271_set_analog_params(struct dvb_frontend *fe,
995ccae7af2SMauro Carvalho Chehab 				      struct analog_parameters *params)
996ccae7af2SMauro Carvalho Chehab {
997ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
998ccae7af2SMauro Carvalho Chehab 	struct tda18271_std_map *std_map = &priv->std;
999ccae7af2SMauro Carvalho Chehab 	struct tda18271_std_map_item *map;
1000ccae7af2SMauro Carvalho Chehab 	char *mode;
1001ccae7af2SMauro Carvalho Chehab 	int ret;
1002ccae7af2SMauro Carvalho Chehab 	u32 freq = params->frequency * 125 *
1003ccae7af2SMauro Carvalho Chehab 		((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2;
1004ccae7af2SMauro Carvalho Chehab 
1005ccae7af2SMauro Carvalho Chehab 	priv->mode = TDA18271_ANALOG;
1006ccae7af2SMauro Carvalho Chehab 
1007ccae7af2SMauro Carvalho Chehab 	if (params->mode == V4L2_TUNER_RADIO) {
1008ccae7af2SMauro Carvalho Chehab 		map = &std_map->fm_radio;
1009ccae7af2SMauro Carvalho Chehab 		mode = "fm";
1010ccae7af2SMauro Carvalho Chehab 	} else if (params->std & V4L2_STD_MN) {
1011ccae7af2SMauro Carvalho Chehab 		map = &std_map->atv_mn;
1012ccae7af2SMauro Carvalho Chehab 		mode = "MN";
1013ccae7af2SMauro Carvalho Chehab 	} else if (params->std & V4L2_STD_B) {
1014ccae7af2SMauro Carvalho Chehab 		map = &std_map->atv_b;
1015ccae7af2SMauro Carvalho Chehab 		mode = "B";
1016ccae7af2SMauro Carvalho Chehab 	} else if (params->std & V4L2_STD_GH) {
1017ccae7af2SMauro Carvalho Chehab 		map = &std_map->atv_gh;
1018ccae7af2SMauro Carvalho Chehab 		mode = "GH";
1019ccae7af2SMauro Carvalho Chehab 	} else if (params->std & V4L2_STD_PAL_I) {
1020ccae7af2SMauro Carvalho Chehab 		map = &std_map->atv_i;
1021ccae7af2SMauro Carvalho Chehab 		mode = "I";
1022ccae7af2SMauro Carvalho Chehab 	} else if (params->std & V4L2_STD_DK) {
1023ccae7af2SMauro Carvalho Chehab 		map = &std_map->atv_dk;
1024ccae7af2SMauro Carvalho Chehab 		mode = "DK";
1025ccae7af2SMauro Carvalho Chehab 	} else if (params->std & V4L2_STD_SECAM_L) {
1026ccae7af2SMauro Carvalho Chehab 		map = &std_map->atv_l;
1027ccae7af2SMauro Carvalho Chehab 		mode = "L";
1028ccae7af2SMauro Carvalho Chehab 	} else if (params->std & V4L2_STD_SECAM_LC) {
1029ccae7af2SMauro Carvalho Chehab 		map = &std_map->atv_lc;
1030ccae7af2SMauro Carvalho Chehab 		mode = "L'";
1031ccae7af2SMauro Carvalho Chehab 	} else {
1032ccae7af2SMauro Carvalho Chehab 		map = &std_map->atv_i;
1033ccae7af2SMauro Carvalho Chehab 		mode = "xx";
1034ccae7af2SMauro Carvalho Chehab 	}
1035ccae7af2SMauro Carvalho Chehab 
1036ccae7af2SMauro Carvalho Chehab 	tda_dbg("setting tda18271 to system %s\n", mode);
1037ccae7af2SMauro Carvalho Chehab 
1038ccae7af2SMauro Carvalho Chehab 	ret = tda18271_tune(fe, map, freq, 0);
1039ccae7af2SMauro Carvalho Chehab 
1040ccae7af2SMauro Carvalho Chehab 	if (tda_fail(ret))
1041ccae7af2SMauro Carvalho Chehab 		goto fail;
1042ccae7af2SMauro Carvalho Chehab 
1043ccae7af2SMauro Carvalho Chehab 	priv->if_freq   = map->if_freq;
1044ccae7af2SMauro Carvalho Chehab 	priv->frequency = freq;
1045ccae7af2SMauro Carvalho Chehab 	priv->bandwidth = 0;
1046ccae7af2SMauro Carvalho Chehab fail:
1047ccae7af2SMauro Carvalho Chehab 	return ret;
1048ccae7af2SMauro Carvalho Chehab }
1049ccae7af2SMauro Carvalho Chehab 
1050ccae7af2SMauro Carvalho Chehab static int tda18271_release(struct dvb_frontend *fe)
1051ccae7af2SMauro Carvalho Chehab {
1052ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
1053ccae7af2SMauro Carvalho Chehab 
1054ccae7af2SMauro Carvalho Chehab 	mutex_lock(&tda18271_list_mutex);
1055ccae7af2SMauro Carvalho Chehab 
1056ccae7af2SMauro Carvalho Chehab 	if (priv)
1057ccae7af2SMauro Carvalho Chehab 		hybrid_tuner_release_state(priv);
1058ccae7af2SMauro Carvalho Chehab 
1059ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&tda18271_list_mutex);
1060ccae7af2SMauro Carvalho Chehab 
1061ccae7af2SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
1062ccae7af2SMauro Carvalho Chehab 
1063ccae7af2SMauro Carvalho Chehab 	return 0;
1064ccae7af2SMauro Carvalho Chehab }
1065ccae7af2SMauro Carvalho Chehab 
1066ccae7af2SMauro Carvalho Chehab static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
1067ccae7af2SMauro Carvalho Chehab {
1068ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
1069ccae7af2SMauro Carvalho Chehab 	*frequency = priv->frequency;
1070ccae7af2SMauro Carvalho Chehab 	return 0;
1071ccae7af2SMauro Carvalho Chehab }
1072ccae7af2SMauro Carvalho Chehab 
1073ccae7af2SMauro Carvalho Chehab static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
1074ccae7af2SMauro Carvalho Chehab {
1075ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
1076ccae7af2SMauro Carvalho Chehab 	*bandwidth = priv->bandwidth;
1077ccae7af2SMauro Carvalho Chehab 	return 0;
1078ccae7af2SMauro Carvalho Chehab }
1079ccae7af2SMauro Carvalho Chehab 
1080ccae7af2SMauro Carvalho Chehab static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
1081ccae7af2SMauro Carvalho Chehab {
1082ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
1083ccae7af2SMauro Carvalho Chehab 	*frequency = (u32)priv->if_freq * 1000;
1084ccae7af2SMauro Carvalho Chehab 	return 0;
1085ccae7af2SMauro Carvalho Chehab }
1086ccae7af2SMauro Carvalho Chehab 
1087ccae7af2SMauro Carvalho Chehab /* ------------------------------------------------------------------ */
1088ccae7af2SMauro Carvalho Chehab 
1089ccae7af2SMauro Carvalho Chehab #define tda18271_update_std(std_cfg, name) do {				\
1090ccae7af2SMauro Carvalho Chehab 	if (map->std_cfg.if_freq +					\
1091ccae7af2SMauro Carvalho Chehab 		map->std_cfg.agc_mode + map->std_cfg.std +		\
1092ccae7af2SMauro Carvalho Chehab 		map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) {	\
1093ccae7af2SMauro Carvalho Chehab 		tda_dbg("Using custom std config for %s\n", name);	\
1094ccae7af2SMauro Carvalho Chehab 		memcpy(&std->std_cfg, &map->std_cfg,			\
1095ccae7af2SMauro Carvalho Chehab 			sizeof(struct tda18271_std_map_item));		\
1096ccae7af2SMauro Carvalho Chehab 	} } while (0)
1097ccae7af2SMauro Carvalho Chehab 
1098ccae7af2SMauro Carvalho Chehab #define tda18271_dump_std_item(std_cfg, name) do {			\
1099ccae7af2SMauro Carvalho Chehab 	tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, "		\
1100ccae7af2SMauro Carvalho Chehab 		"if_lvl = %d, rfagc_top = 0x%02x\n",			\
1101ccae7af2SMauro Carvalho Chehab 		name, std->std_cfg.if_freq,				\
1102ccae7af2SMauro Carvalho Chehab 		std->std_cfg.agc_mode, std->std_cfg.std,		\
1103ccae7af2SMauro Carvalho Chehab 		std->std_cfg.if_lvl, std->std_cfg.rfagc_top);		\
1104ccae7af2SMauro Carvalho Chehab 	} while (0)
1105ccae7af2SMauro Carvalho Chehab 
1106ccae7af2SMauro Carvalho Chehab static int tda18271_dump_std_map(struct dvb_frontend *fe)
1107ccae7af2SMauro Carvalho Chehab {
1108ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
1109ccae7af2SMauro Carvalho Chehab 	struct tda18271_std_map *std = &priv->std;
1110ccae7af2SMauro Carvalho Chehab 
1111ccae7af2SMauro Carvalho Chehab 	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
1112ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(fm_radio, "  fm  ");
1113ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(atv_b,  "atv b ");
1114ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(atv_dk, "atv dk");
1115ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(atv_gh, "atv gh");
1116ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(atv_i,  "atv i ");
1117ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(atv_l,  "atv l ");
1118ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(atv_lc, "atv l'");
1119ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(atv_mn, "atv mn");
1120ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(atsc_6, "atsc 6");
1121ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(dvbt_6, "dvbt 6");
1122ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(dvbt_7, "dvbt 7");
1123ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(dvbt_8, "dvbt 8");
1124ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(qam_6,  "qam 6 ");
1125ccae7af2SMauro Carvalho Chehab 	tda18271_dump_std_item(qam_8,  "qam 8 ");
1126ccae7af2SMauro Carvalho Chehab 
1127ccae7af2SMauro Carvalho Chehab 	return 0;
1128ccae7af2SMauro Carvalho Chehab }
1129ccae7af2SMauro Carvalho Chehab 
1130ccae7af2SMauro Carvalho Chehab static int tda18271_update_std_map(struct dvb_frontend *fe,
1131ccae7af2SMauro Carvalho Chehab 				   struct tda18271_std_map *map)
1132ccae7af2SMauro Carvalho Chehab {
1133ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
1134ccae7af2SMauro Carvalho Chehab 	struct tda18271_std_map *std = &priv->std;
1135ccae7af2SMauro Carvalho Chehab 
1136ccae7af2SMauro Carvalho Chehab 	if (!map)
1137ccae7af2SMauro Carvalho Chehab 		return -EINVAL;
1138ccae7af2SMauro Carvalho Chehab 
1139ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(fm_radio, "fm");
1140ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(atv_b,  "atv b");
1141ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(atv_dk, "atv dk");
1142ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(atv_gh, "atv gh");
1143ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(atv_i,  "atv i");
1144ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(atv_l,  "atv l");
1145ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(atv_lc, "atv l'");
1146ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(atv_mn, "atv mn");
1147ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(atsc_6, "atsc 6");
1148ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(dvbt_6, "dvbt 6");
1149ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(dvbt_7, "dvbt 7");
1150ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(dvbt_8, "dvbt 8");
1151ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(qam_6,  "qam 6");
1152ccae7af2SMauro Carvalho Chehab 	tda18271_update_std(qam_8,  "qam 8");
1153ccae7af2SMauro Carvalho Chehab 
1154ccae7af2SMauro Carvalho Chehab 	return 0;
1155ccae7af2SMauro Carvalho Chehab }
1156ccae7af2SMauro Carvalho Chehab 
1157ccae7af2SMauro Carvalho Chehab static int tda18271_get_id(struct dvb_frontend *fe)
1158ccae7af2SMauro Carvalho Chehab {
1159ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
1160ccae7af2SMauro Carvalho Chehab 	unsigned char *regs = priv->tda18271_regs;
1161ccae7af2SMauro Carvalho Chehab 	char *name;
1162ccae7af2SMauro Carvalho Chehab 
1163ccae7af2SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
1164ccae7af2SMauro Carvalho Chehab 	tda18271_read_regs(fe);
1165ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
1166ccae7af2SMauro Carvalho Chehab 
1167ccae7af2SMauro Carvalho Chehab 	switch (regs[R_ID] & 0x7f) {
1168ccae7af2SMauro Carvalho Chehab 	case 3:
1169ccae7af2SMauro Carvalho Chehab 		name = "TDA18271HD/C1";
1170ccae7af2SMauro Carvalho Chehab 		priv->id = TDA18271HDC1;
1171ccae7af2SMauro Carvalho Chehab 		break;
1172ccae7af2SMauro Carvalho Chehab 	case 4:
1173ccae7af2SMauro Carvalho Chehab 		name = "TDA18271HD/C2";
1174ccae7af2SMauro Carvalho Chehab 		priv->id = TDA18271HDC2;
1175ccae7af2SMauro Carvalho Chehab 		break;
1176ccae7af2SMauro Carvalho Chehab 	default:
1177ccae7af2SMauro Carvalho Chehab 		tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n",
1178ccae7af2SMauro Carvalho Chehab 			 regs[R_ID], i2c_adapter_id(priv->i2c_props.adap),
1179ccae7af2SMauro Carvalho Chehab 			 priv->i2c_props.addr);
1180ccae7af2SMauro Carvalho Chehab 		return -EINVAL;
1181ccae7af2SMauro Carvalho Chehab 	}
1182ccae7af2SMauro Carvalho Chehab 
1183ccae7af2SMauro Carvalho Chehab 	tda_info("%s detected @ %d-%04x\n", name,
1184ccae7af2SMauro Carvalho Chehab 		 i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr);
1185ccae7af2SMauro Carvalho Chehab 
1186ccae7af2SMauro Carvalho Chehab 	return 0;
1187ccae7af2SMauro Carvalho Chehab }
1188ccae7af2SMauro Carvalho Chehab 
1189ccae7af2SMauro Carvalho Chehab static int tda18271_setup_configuration(struct dvb_frontend *fe,
1190ccae7af2SMauro Carvalho Chehab 					struct tda18271_config *cfg)
1191ccae7af2SMauro Carvalho Chehab {
1192ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = fe->tuner_priv;
1193ccae7af2SMauro Carvalho Chehab 
1194ccae7af2SMauro Carvalho Chehab 	priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
1195ccae7af2SMauro Carvalho Chehab 	priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
1196ccae7af2SMauro Carvalho Chehab 	priv->config = (cfg) ? cfg->config : 0;
1197ccae7af2SMauro Carvalho Chehab 	priv->small_i2c = (cfg) ?
1198ccae7af2SMauro Carvalho Chehab 		cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT;
1199ccae7af2SMauro Carvalho Chehab 	priv->output_opt = (cfg) ?
1200ccae7af2SMauro Carvalho Chehab 		cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
1201ccae7af2SMauro Carvalho Chehab 
1202ccae7af2SMauro Carvalho Chehab 	return 0;
1203ccae7af2SMauro Carvalho Chehab }
1204ccae7af2SMauro Carvalho Chehab 
1205ccae7af2SMauro Carvalho Chehab static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg)
1206ccae7af2SMauro Carvalho Chehab {
1207ccae7af2SMauro Carvalho Chehab 	/* tda18271_cal_on_startup == -1 when cal module option is unset */
1208ccae7af2SMauro Carvalho Chehab 	return ((tda18271_cal_on_startup == -1) ?
1209ccae7af2SMauro Carvalho Chehab 		/* honor configuration setting */
1210ccae7af2SMauro Carvalho Chehab 		((cfg) && (cfg->rf_cal_on_startup)) :
1211ccae7af2SMauro Carvalho Chehab 		/* module option overrides configuration setting */
1212ccae7af2SMauro Carvalho Chehab 		(tda18271_cal_on_startup)) ? 1 : 0;
1213ccae7af2SMauro Carvalho Chehab }
1214ccae7af2SMauro Carvalho Chehab 
1215ccae7af2SMauro Carvalho Chehab static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg)
1216ccae7af2SMauro Carvalho Chehab {
1217ccae7af2SMauro Carvalho Chehab 	struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg;
1218ccae7af2SMauro Carvalho Chehab 
1219ccae7af2SMauro Carvalho Chehab 	tda18271_setup_configuration(fe, cfg);
1220ccae7af2SMauro Carvalho Chehab 
1221ccae7af2SMauro Carvalho Chehab 	if (tda18271_need_cal_on_startup(cfg))
1222ccae7af2SMauro Carvalho Chehab 		tda18271_init(fe);
1223ccae7af2SMauro Carvalho Chehab 
1224ccae7af2SMauro Carvalho Chehab 	/* override default std map with values in config struct */
1225ccae7af2SMauro Carvalho Chehab 	if ((cfg) && (cfg->std_map))
1226ccae7af2SMauro Carvalho Chehab 		tda18271_update_std_map(fe, cfg->std_map);
1227ccae7af2SMauro Carvalho Chehab 
1228ccae7af2SMauro Carvalho Chehab 	return 0;
1229ccae7af2SMauro Carvalho Chehab }
1230ccae7af2SMauro Carvalho Chehab 
1231ccae7af2SMauro Carvalho Chehab static const struct dvb_tuner_ops tda18271_tuner_ops = {
1232ccae7af2SMauro Carvalho Chehab 	.info = {
1233ccae7af2SMauro Carvalho Chehab 		.name = "NXP TDA18271HD",
1234ccae7af2SMauro Carvalho Chehab 		.frequency_min  =  45000000,
1235ccae7af2SMauro Carvalho Chehab 		.frequency_max  = 864000000,
1236ccae7af2SMauro Carvalho Chehab 		.frequency_step =     62500
1237ccae7af2SMauro Carvalho Chehab 	},
1238ccae7af2SMauro Carvalho Chehab 	.init              = tda18271_init,
1239ccae7af2SMauro Carvalho Chehab 	.sleep             = tda18271_sleep,
1240ccae7af2SMauro Carvalho Chehab 	.set_params        = tda18271_set_params,
1241ccae7af2SMauro Carvalho Chehab 	.set_analog_params = tda18271_set_analog_params,
1242ccae7af2SMauro Carvalho Chehab 	.release           = tda18271_release,
1243ccae7af2SMauro Carvalho Chehab 	.set_config        = tda18271_set_config,
1244ccae7af2SMauro Carvalho Chehab 	.get_frequency     = tda18271_get_frequency,
1245ccae7af2SMauro Carvalho Chehab 	.get_bandwidth     = tda18271_get_bandwidth,
1246ccae7af2SMauro Carvalho Chehab 	.get_if_frequency  = tda18271_get_if_frequency,
1247ccae7af2SMauro Carvalho Chehab };
1248ccae7af2SMauro Carvalho Chehab 
1249ccae7af2SMauro Carvalho Chehab struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
1250ccae7af2SMauro Carvalho Chehab 				     struct i2c_adapter *i2c,
1251ccae7af2SMauro Carvalho Chehab 				     struct tda18271_config *cfg)
1252ccae7af2SMauro Carvalho Chehab {
1253ccae7af2SMauro Carvalho Chehab 	struct tda18271_priv *priv = NULL;
1254ccae7af2SMauro Carvalho Chehab 	int instance, ret;
1255ccae7af2SMauro Carvalho Chehab 
1256ccae7af2SMauro Carvalho Chehab 	mutex_lock(&tda18271_list_mutex);
1257ccae7af2SMauro Carvalho Chehab 
1258ccae7af2SMauro Carvalho Chehab 	instance = hybrid_tuner_request_state(struct tda18271_priv, priv,
1259ccae7af2SMauro Carvalho Chehab 					      hybrid_tuner_instance_list,
1260ccae7af2SMauro Carvalho Chehab 					      i2c, addr, "tda18271");
1261ccae7af2SMauro Carvalho Chehab 	switch (instance) {
1262ccae7af2SMauro Carvalho Chehab 	case 0:
1263ccae7af2SMauro Carvalho Chehab 		goto fail;
1264ccae7af2SMauro Carvalho Chehab 	case 1:
1265ccae7af2SMauro Carvalho Chehab 		/* new tuner instance */
1266ccae7af2SMauro Carvalho Chehab 		fe->tuner_priv = priv;
1267ccae7af2SMauro Carvalho Chehab 
1268ccae7af2SMauro Carvalho Chehab 		tda18271_setup_configuration(fe, cfg);
1269ccae7af2SMauro Carvalho Chehab 
1270ccae7af2SMauro Carvalho Chehab 		priv->cal_initialized = false;
1271ccae7af2SMauro Carvalho Chehab 		mutex_init(&priv->lock);
1272ccae7af2SMauro Carvalho Chehab 
1273ccae7af2SMauro Carvalho Chehab 		ret = tda18271_get_id(fe);
1274ccae7af2SMauro Carvalho Chehab 		if (tda_fail(ret))
1275ccae7af2SMauro Carvalho Chehab 			goto fail;
1276ccae7af2SMauro Carvalho Chehab 
1277ccae7af2SMauro Carvalho Chehab 		ret = tda18271_assign_map_layout(fe);
1278ccae7af2SMauro Carvalho Chehab 		if (tda_fail(ret))
1279ccae7af2SMauro Carvalho Chehab 			goto fail;
1280ccae7af2SMauro Carvalho Chehab 
1281ccae7af2SMauro Carvalho Chehab 		mutex_lock(&priv->lock);
1282ccae7af2SMauro Carvalho Chehab 		tda18271_init_regs(fe);
1283ccae7af2SMauro Carvalho Chehab 
1284ccae7af2SMauro Carvalho Chehab 		if ((tda18271_need_cal_on_startup(cfg)) &&
1285ccae7af2SMauro Carvalho Chehab 		    (priv->id == TDA18271HDC2))
1286ccae7af2SMauro Carvalho Chehab 			tda18271c2_rf_cal_init(fe);
1287ccae7af2SMauro Carvalho Chehab 
1288*4cfae675SMichael Krufky 		/* enter standby mode, with required output features enabled */
1289*4cfae675SMichael Krufky 		ret = tda18271_toggle_output(fe, 1);
1290*4cfae675SMichael Krufky 		tda_fail(ret);
1291*4cfae675SMichael Krufky 
1292ccae7af2SMauro Carvalho Chehab 		mutex_unlock(&priv->lock);
1293ccae7af2SMauro Carvalho Chehab 		break;
1294ccae7af2SMauro Carvalho Chehab 	default:
1295ccae7af2SMauro Carvalho Chehab 		/* existing tuner instance */
1296ccae7af2SMauro Carvalho Chehab 		fe->tuner_priv = priv;
1297ccae7af2SMauro Carvalho Chehab 
1298ccae7af2SMauro Carvalho Chehab 		/* allow dvb driver to override configuration settings */
1299ccae7af2SMauro Carvalho Chehab 		if (cfg) {
1300ccae7af2SMauro Carvalho Chehab 			if (cfg->gate != TDA18271_GATE_ANALOG)
1301ccae7af2SMauro Carvalho Chehab 				priv->gate = cfg->gate;
1302ccae7af2SMauro Carvalho Chehab 			if (cfg->role)
1303ccae7af2SMauro Carvalho Chehab 				priv->role = cfg->role;
1304ccae7af2SMauro Carvalho Chehab 			if (cfg->config)
1305ccae7af2SMauro Carvalho Chehab 				priv->config = cfg->config;
1306ccae7af2SMauro Carvalho Chehab 			if (cfg->small_i2c)
1307ccae7af2SMauro Carvalho Chehab 				priv->small_i2c = cfg->small_i2c;
1308ccae7af2SMauro Carvalho Chehab 			if (cfg->output_opt)
1309ccae7af2SMauro Carvalho Chehab 				priv->output_opt = cfg->output_opt;
1310ccae7af2SMauro Carvalho Chehab 			if (cfg->std_map)
1311ccae7af2SMauro Carvalho Chehab 				tda18271_update_std_map(fe, cfg->std_map);
1312ccae7af2SMauro Carvalho Chehab 		}
1313ccae7af2SMauro Carvalho Chehab 		if (tda18271_need_cal_on_startup(cfg))
1314ccae7af2SMauro Carvalho Chehab 			tda18271_init(fe);
1315ccae7af2SMauro Carvalho Chehab 		break;
1316ccae7af2SMauro Carvalho Chehab 	}
1317ccae7af2SMauro Carvalho Chehab 
1318ccae7af2SMauro Carvalho Chehab 	/* override default std map with values in config struct */
1319ccae7af2SMauro Carvalho Chehab 	if ((cfg) && (cfg->std_map))
1320ccae7af2SMauro Carvalho Chehab 		tda18271_update_std_map(fe, cfg->std_map);
1321ccae7af2SMauro Carvalho Chehab 
1322ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&tda18271_list_mutex);
1323ccae7af2SMauro Carvalho Chehab 
1324ccae7af2SMauro Carvalho Chehab 	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
1325ccae7af2SMauro Carvalho Chehab 	       sizeof(struct dvb_tuner_ops));
1326ccae7af2SMauro Carvalho Chehab 
1327ccae7af2SMauro Carvalho Chehab 	if (tda18271_debug & (DBG_MAP | DBG_ADV))
1328ccae7af2SMauro Carvalho Chehab 		tda18271_dump_std_map(fe);
1329ccae7af2SMauro Carvalho Chehab 
1330ccae7af2SMauro Carvalho Chehab 	return fe;
1331ccae7af2SMauro Carvalho Chehab fail:
1332ccae7af2SMauro Carvalho Chehab 	mutex_unlock(&tda18271_list_mutex);
1333ccae7af2SMauro Carvalho Chehab 
1334ccae7af2SMauro Carvalho Chehab 	tda18271_release(fe);
1335ccae7af2SMauro Carvalho Chehab 	return NULL;
1336ccae7af2SMauro Carvalho Chehab }
1337ccae7af2SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(tda18271_attach);
1338ccae7af2SMauro Carvalho Chehab MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
1339ccae7af2SMauro Carvalho Chehab MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
1340ccae7af2SMauro Carvalho Chehab MODULE_LICENSE("GPL");
1341ccae7af2SMauro Carvalho Chehab MODULE_VERSION("0.4");
1342ccae7af2SMauro Carvalho Chehab 
1343ccae7af2SMauro Carvalho Chehab /*
1344ccae7af2SMauro Carvalho Chehab  * Overrides for Emacs so that we follow Linus's tabbing style.
1345ccae7af2SMauro Carvalho Chehab  * ---------------------------------------------------------------------------
1346ccae7af2SMauro Carvalho Chehab  * Local variables:
1347ccae7af2SMauro Carvalho Chehab  * c-basic-offset: 8
1348ccae7af2SMauro Carvalho Chehab  * End:
1349ccae7af2SMauro Carvalho Chehab  */
1350