diff options
Diffstat (limited to 'linux/drivers/media/dvb/frontends/tda18271-fe.c')
-rw-r--r-- | linux/drivers/media/dvb/frontends/tda18271-fe.c | 151 |
1 files changed, 100 insertions, 51 deletions
diff --git a/linux/drivers/media/dvb/frontends/tda18271-fe.c b/linux/drivers/media/dvb/frontends/tda18271-fe.c index da6bc4857..e1a187e14 100644 --- a/linux/drivers/media/dvb/frontends/tda18271-fe.c +++ b/linux/drivers/media/dvb/frontends/tda18271-fe.c @@ -372,13 +372,64 @@ static int tda18271_init(struct dvb_frontend *fe) return 0; } +static int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) +{ + /* Sets Main Post-Divider & Divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + tda18271_lookup_main_pll(&freq, &pd, &d); + + regs[R_MPD] = (0x77 & pd); + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_MD1] = 0x7f & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; + + return 0; +} + +static int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) +{ + /* Sets Cal Post-Divider & Divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + tda18271_lookup_cal_pll(&freq, &pd, &d); + + regs[R_CPD] = pd; + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_CD1] = 0x7f & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; + + return 0; +} + static int tda18271_tune(struct dvb_frontend *fe, u32 ifc, u32 freq, u32 bw, u8 std) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; - u32 div, N = 0; - u8 d, pd, val; + u32 N = 0; + u8 val; tda18271_init(fe); #if 0 @@ -392,7 +443,7 @@ static int tda18271_tune(struct dvb_frontend *fe, /* RF tracking filter calibration */ /* calculate BP_Filter */ - tda18271_calc_bp_filter(&freq, &val); + tda18271_lookup_bp_filter(&freq, &val); regs[R_EP1] &= ~0x07; /* clear bp filter bits */ regs[R_EP1] |= val; @@ -425,14 +476,7 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - tda18271_calc_cal_pll(&N, &pd, &d); - - regs[R_CPD] = pd; - - div = ((d * (N / 1000)) << 7) / 125; - regs[R_CD1] = 0xff & (div >> 16); - regs[R_CD2] = 0xff & (div >> 8); - regs[R_CD3] = 0xff & div; + tda18271_calc_cal_pll(fe, N); /* calculate MAIN PLL */ @@ -445,42 +489,26 @@ static int tda18271_tune(struct dvb_frontend *fe, break; } - tda18271_calc_main_pll(&N, &pd, &d); - - regs[R_MPD] = (0x7f & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((d * (N / 1000)) << 7) / 125; - regs[R_MD1] = 0xff & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; + tda18271_calc_main_pll(fe, N); tda18271_write_regs(fe, R_EP3, 11); msleep(5); /* RF tracking filter calibration initialization */ /* search for K,M,CO for RF Calibration */ - tda18271_calc_km(&freq, &val); + tda18271_lookup_km(&freq, &val); regs[R_EB13] &= 0x83; regs[R_EB13] |= val; tda18271_write_regs(fe, R_EB13, 1); /* search for RF_BAND */ - tda18271_calc_rf_band(&freq, &val); + tda18271_lookup_rf_band(&freq, &val); regs[R_EP2] &= ~0xe0; /* clear rf band bits */ regs[R_EP2] |= (val << 5); /* search for Gain_Taper */ - tda18271_calc_gain_taper(&freq, &val); + tda18271_lookup_gain_taper(&freq, &val); regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ regs[R_EP2] |= val; @@ -508,7 +536,7 @@ static int tda18271_tune(struct dvb_frontend *fe, tda18271_write_regs(fe, R_EP1, 1); /* RF tracking filer correction for VHF_Low band */ - tda18271_calc_rf_cal(&freq, &val); + tda18271_lookup_rf_cal(&freq, &val); /* VHF_Low band only */ if (val != 0) { @@ -552,7 +580,7 @@ static int tda18271_tune(struct dvb_frontend *fe, regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ /* image rejection validity EP5[2:0] */ - tda18271_calc_ir_measure(&freq, &val); + tda18271_lookup_ir_measure(&freq, &val); regs[R_EP5] &= ~0x07; regs[R_EP5] |= val; @@ -560,22 +588,7 @@ static int tda18271_tune(struct dvb_frontend *fe, /* calculate MAIN PLL */ N = freq + ifc; - tda18271_calc_main_pll(&N, &pd, &d); - - regs[R_MPD] = (0x7f & pd); - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((d * (N / 1000)) << 7) / 125; - regs[R_MD1] = 0xff & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; + tda18271_calc_main_pll(fe, N); tda18271_write_regs(fe, R_TM, 15); msleep(5); @@ -725,6 +738,36 @@ static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int tda18271_get_id(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + char *name; + int ret = 0; + + tda18271_read_regs(fe); + + switch (regs[R_ID] & 0x7f) { + case 3: + name = "TDA18271HD/C1"; + break; + case 4: + name = "TDA18271HD/C2"; + ret = -EPROTONOSUPPORT; + break; + default: + name = "Unknown device"; + ret = -EINVAL; + break; + } + + dbg_info("%s detected @ %d-%04x%s\n", name, + i2c_adapter_id(priv->i2c_adap), priv->i2c_addr, + (0 == ret) ? "" : ", device not supported."); + + return ret; +} + static struct dvb_tuner_ops tda18271_tuner_ops = { .info = { .name = "NXP TDA18271HD", @@ -755,14 +798,20 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, priv->i2c_adap = i2c; priv->gate = gate; + fe->tuner_priv = priv; + + if (tda18271_get_id(fe) < 0) + goto fail; + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - tda18271_init_regs(fe); return fe; +fail: + tda18271_release(fe); + return NULL; } EXPORT_SYMBOL_GPL(tda18271_attach); MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); |