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