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