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