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