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