提交 59067f7e 编写于 作者: M Michael Krufky 提交者: Mauro Carvalho Chehab

V4L/DVB (6961): tda18271: move common code to tda18271-common.c

Move some common code to a new file to make this easier to look at.
Signed-off-by: NMichael Krufky <mkrufky@linuxtv.org>
Signed-off-by: NMauro Carvalho Chehab <mchehab@infradead.org>
上级 255b5113
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
EXTRA_CFLAGS += -Idrivers/media/video/ EXTRA_CFLAGS += -Idrivers/media/video/
tda18271-objs := tda18271-tables.o tda18271-fe.o tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o
obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o obj-$(CONFIG_DVB_STV0299) += stv0299.o
......
/*
tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner
Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "tda18271-priv.h"
static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct tda18271_priv *priv = fe->tuner_priv;
enum tda18271_i2c_gate gate;
int ret = 0;
switch (priv->gate) {
case TDA18271_GATE_DIGITAL:
case TDA18271_GATE_ANALOG:
gate = priv->gate;
break;
case TDA18271_GATE_AUTO:
default:
switch (priv->mode) {
case TDA18271_DIGITAL:
gate = TDA18271_GATE_DIGITAL;
break;
case TDA18271_ANALOG:
default:
gate = TDA18271_GATE_ANALOG;
break;
}
}
switch (gate) {
case TDA18271_GATE_ANALOG:
if (fe->ops.analog_ops.i2c_gate_ctrl)
ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
break;
case TDA18271_GATE_DIGITAL:
if (fe->ops.i2c_gate_ctrl)
ret = fe->ops.i2c_gate_ctrl(fe, enable);
break;
default:
ret = -EINVAL;
break;
}
return ret;
};
/*---------------------------------------------------------------------*/
static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
tda_reg("=== TDA18271 REG DUMP ===\n");
tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]);
tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]);
tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]);
tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]);
tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]);
tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]);
tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]);
tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]);
tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]);
tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]);
tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]);
tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]);
tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]);
tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]);
tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]);
/* only dump extended regs if DBG_ADV is set */
if (!(tda18271_debug & DBG_ADV))
return;
/* W indicates write-only registers.
* Register dump for write-only registers shows last value written. */
tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]);
tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]);
tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]);
tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]);
tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]);
tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]);
tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]);
tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]);
tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]);
tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]);
tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]);
tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]);
tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]);
tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]);
tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]);
tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]);
tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]);
tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]);
tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]);
}
int tda18271_read_regs(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
unsigned char buf = 0x00;
int ret;
struct i2c_msg msg[] = {
{ .addr = priv->i2c_addr, .flags = 0,
.buf = &buf, .len = 1 },
{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
.buf = regs, .len = 16 }
};
tda18271_i2c_gate_ctrl(fe, 1);
/* read all registers */
ret = i2c_transfer(priv->i2c_adap, msg, 2);
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 2)
tda_err("ERROR: i2c_transfer returned: %d\n", ret);
if (tda18271_debug & DBG_REG)
tda18271_dump_regs(fe, 0);
return (ret == 2 ? 0 : ret);
}
int tda18271_read_extended(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
unsigned char regdump[TDA18271_NUM_REGS];
unsigned char buf = 0x00;
int ret, i;
struct i2c_msg msg[] = {
{ .addr = priv->i2c_addr, .flags = 0,
.buf = &buf, .len = 1 },
{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
.buf = regdump, .len = TDA18271_NUM_REGS }
};
tda18271_i2c_gate_ctrl(fe, 1);
/* read all registers */
ret = i2c_transfer(priv->i2c_adap, msg, 2);
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 2)
tda_err("ERROR: i2c_transfer returned: %d\n", ret);
for (i = 0; i <= TDA18271_NUM_REGS; i++) {
/* don't update write-only registers */
if ((i != R_EB9) &&
(i != R_EB16) &&
(i != R_EB17) &&
(i != R_EB19) &&
(i != R_EB20))
regs[i] = regdump[i];
}
if (tda18271_debug & DBG_REG)
tda18271_dump_regs(fe, 1);
return (ret == 2 ? 0 : ret);
}
int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
unsigned char buf[TDA18271_NUM_REGS + 1];
struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
.buf = buf, .len = len + 1 };
int i, ret;
BUG_ON((len == 0) || (idx + len > sizeof(buf)));
buf[0] = idx;
for (i = 1; i <= len; i++)
buf[i] = regs[idx - 1 + i];
tda18271_i2c_gate_ctrl(fe, 1);
/* write registers */
ret = i2c_transfer(priv->i2c_adap, &msg, 1);
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 1)
tda_err("ERROR: i2c_transfer returned: %d\n", ret);
return (ret == 1 ? 0 : ret);
}
/*---------------------------------------------------------------------*/
int tda18271_init_regs(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
tda_dbg("initializing registers for device @ %d-%04x\n",
i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
/* initialize registers */
switch (priv->id) {
case TDA18271HDC1:
regs[R_ID] = 0x83;
break;
case TDA18271HDC2:
regs[R_ID] = 0x84;
break;
};
regs[R_TM] = 0x08;
regs[R_PL] = 0x80;
regs[R_EP1] = 0xc6;
regs[R_EP2] = 0xdf;
regs[R_EP3] = 0x16;
regs[R_EP4] = 0x60;
regs[R_EP5] = 0x80;
regs[R_CPD] = 0x80;
regs[R_CD1] = 0x00;
regs[R_CD2] = 0x00;
regs[R_CD3] = 0x00;
regs[R_MPD] = 0x00;
regs[R_MD1] = 0x00;
regs[R_MD2] = 0x00;
regs[R_MD3] = 0x00;
switch (priv->id) {
case TDA18271HDC1:
regs[R_EB1] = 0xff;
break;
case TDA18271HDC2:
regs[R_EB1] = 0xfc;
break;
};
regs[R_EB2] = 0x01;
regs[R_EB3] = 0x84;
regs[R_EB4] = 0x41;
regs[R_EB5] = 0x01;
regs[R_EB6] = 0x84;
regs[R_EB7] = 0x40;
regs[R_EB8] = 0x07;
regs[R_EB9] = 0x00;
regs[R_EB10] = 0x00;
regs[R_EB11] = 0x96;
switch (priv->id) {
case TDA18271HDC1:
regs[R_EB12] = 0x0f;
break;
case TDA18271HDC2:
regs[R_EB12] = 0x33;
break;
};
regs[R_EB13] = 0xc1;
regs[R_EB14] = 0x00;
regs[R_EB15] = 0x8f;
regs[R_EB16] = 0x00;
regs[R_EB17] = 0x00;
switch (priv->id) {
case TDA18271HDC1:
regs[R_EB18] = 0x00;
break;
case TDA18271HDC2:
regs[R_EB18] = 0x8c;
break;
};
regs[R_EB19] = 0x00;
regs[R_EB20] = 0x20;
switch (priv->id) {
case TDA18271HDC1:
regs[R_EB21] = 0x33;
break;
case TDA18271HDC2:
regs[R_EB21] = 0xb3;
break;
};
regs[R_EB22] = 0x48;
regs[R_EB23] = 0xb0;
tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
/* setup agc1 gain */
regs[R_EB17] = 0x00;
tda18271_write_regs(fe, R_EB17, 1);
regs[R_EB17] = 0x03;
tda18271_write_regs(fe, R_EB17, 1);
regs[R_EB17] = 0x43;
tda18271_write_regs(fe, R_EB17, 1);
regs[R_EB17] = 0x4c;
tda18271_write_regs(fe, R_EB17, 1);
/* setup agc2 gain */
if ((priv->id) == TDA18271HDC1) {
regs[R_EB20] = 0xa0;
tda18271_write_regs(fe, R_EB20, 1);
regs[R_EB20] = 0xa7;
tda18271_write_regs(fe, R_EB20, 1);
regs[R_EB20] = 0xe7;
tda18271_write_regs(fe, R_EB20, 1);
regs[R_EB20] = 0xec;
tda18271_write_regs(fe, R_EB20, 1);
}
/* image rejection calibration */
/* low-band */
regs[R_EP3] = 0x1f;
regs[R_EP4] = 0x66;
regs[R_EP5] = 0x81;
regs[R_CPD] = 0xcc;
regs[R_CD1] = 0x6c;
regs[R_CD2] = 0x00;
regs[R_CD3] = 0x00;
regs[R_MPD] = 0xcd;
regs[R_MD1] = 0x77;
regs[R_MD2] = 0x08;
regs[R_MD3] = 0x00;
switch (priv->id) {
case TDA18271HDC1:
tda18271_write_regs(fe, R_EP3, 11);
break;
case TDA18271HDC2:
tda18271_write_regs(fe, R_EP3, 12);
break;
};
if ((priv->id) == TDA18271HDC2) {
/* main pll cp source on */
regs[R_EB4] = 0x61;
tda18271_write_regs(fe, R_EB4, 1);
msleep(1);
/* main pll cp source off */
regs[R_EB4] = 0x41;
tda18271_write_regs(fe, R_EB4, 1);
}
msleep(5); /* pll locking */
/* launch detector */
tda18271_write_regs(fe, R_EP1, 1);
msleep(5); /* wanted low measurement */
regs[R_EP5] = 0x85;
regs[R_CPD] = 0xcb;
regs[R_CD1] = 0x66;
regs[R_CD2] = 0x70;
tda18271_write_regs(fe, R_EP3, 7);
msleep(5); /* pll locking */
/* launch optimization algorithm */
tda18271_write_regs(fe, R_EP2, 1);
msleep(30); /* image low optimization completion */
/* mid-band */
regs[R_EP5] = 0x82;
regs[R_CPD] = 0xa8;
regs[R_CD2] = 0x00;
regs[R_MPD] = 0xa9;
regs[R_MD1] = 0x73;
regs[R_MD2] = 0x1a;
tda18271_write_regs(fe, R_EP3, 11);
msleep(5); /* pll locking */
tda18271_write_regs(fe, R_EP1, 1);
msleep(5); /* wanted mid measurement */
regs[R_EP5] = 0x86;
regs[R_CPD] = 0xa8;
regs[R_CD1] = 0x66;
regs[R_CD2] = 0xa0;
tda18271_write_regs(fe, R_EP3, 7);
msleep(5); /* pll locking */
/* launch optimization algorithm */
tda18271_write_regs(fe, R_EP2, 1);
msleep(30); /* image mid optimization completion */
/* high-band */
regs[R_EP5] = 0x83;
regs[R_CPD] = 0x98;
regs[R_CD1] = 0x65;
regs[R_CD2] = 0x00;
regs[R_MPD] = 0x99;
regs[R_MD1] = 0x71;
regs[R_MD2] = 0xcd;
tda18271_write_regs(fe, R_EP3, 11);
msleep(5); /* pll locking */
/* launch detector */
tda18271_write_regs(fe, R_EP1, 1);
msleep(5); /* wanted high measurement */
regs[R_EP5] = 0x87;
regs[R_CD1] = 0x65;
regs[R_CD2] = 0x50;
tda18271_write_regs(fe, R_EP3, 7);
msleep(5); /* pll locking */
/* launch optimization algorithm */
tda18271_write_regs(fe, R_EP2, 1);
msleep(30); /* image high optimization completion */
/* return to normal mode */
regs[R_EP4] = 0x64;
tda18271_write_regs(fe, R_EP4, 1);
/* synchronize */
tda18271_write_regs(fe, R_EP1, 1);
return 0;
}
/*---------------------------------------------------------------------*/
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;
int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
if (ret < 0)
goto fail;
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;
fail:
return ret;
}
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;
int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
if (ret < 0)
goto fail;
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;
fail:
return ret;
}
/*---------------------------------------------------------------------*/
int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
{
/* sets bp filter bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
if (ret < 0)
goto fail;
regs[R_EP1] &= ~0x07; /* clear bp filter bits */
regs[R_EP1] |= (0x07 & val);
fail:
return ret;
}
int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
{
/* sets K & M bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
if (ret < 0)
goto fail;
regs[R_EB13] &= ~0x7c; /* clear k & m bits */
regs[R_EB13] |= (0x7c & val);
fail:
return ret;
}
int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
{
/* sets rf band bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
if (ret < 0)
goto fail;
regs[R_EP2] &= ~0xe0; /* clear rf band bits */
regs[R_EP2] |= (0xe0 & (val << 5));
fail:
return ret;
}
int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
{
/* sets gain taper bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
if (ret < 0)
goto fail;
regs[R_EP2] &= ~0x1f; /* clear gain taper bits */
regs[R_EP2] |= (0x1f & val);
fail:
return ret;
}
int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
{
/* sets IR Meas bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
if (ret < 0)
goto fail;
regs[R_EP5] &= ~0x07;
regs[R_EP5] |= (0x07 & val);
fail:
return ret;
}
int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
{
/* sets rf cal byte (RFC_Cprog), but does not write it */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val);
if (ret < 0)
goto fail;
regs[R_EB14] = val;
fail:
return ret;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/
/* /*
tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -28,431 +28,6 @@ MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))"); ...@@ -28,431 +28,6 @@ MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4 (or-able))");
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct tda18271_priv *priv = fe->tuner_priv;
enum tda18271_i2c_gate gate;
int ret = 0;
switch (priv->gate) {
case TDA18271_GATE_DIGITAL:
case TDA18271_GATE_ANALOG:
gate = priv->gate;
break;
case TDA18271_GATE_AUTO:
default:
switch (priv->mode) {
case TDA18271_DIGITAL:
gate = TDA18271_GATE_DIGITAL;
break;
case TDA18271_ANALOG:
default:
gate = TDA18271_GATE_ANALOG;
break;
}
}
switch (gate) {
case TDA18271_GATE_ANALOG:
if (fe->ops.analog_ops.i2c_gate_ctrl)
ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
break;
case TDA18271_GATE_DIGITAL:
if (fe->ops.i2c_gate_ctrl)
ret = fe->ops.i2c_gate_ctrl(fe, enable);
break;
default:
ret = -EINVAL;
break;
}
return ret;
};
/*---------------------------------------------------------------------*/
static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
tda_reg("=== TDA18271 REG DUMP ===\n");
tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]);
tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]);
tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]);
tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]);
tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]);
tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]);
tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]);
tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]);
tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]);
tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]);
tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]);
tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]);
tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]);
tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]);
tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]);
/* only dump extended regs if DBG_ADV is set */
if (!(tda18271_debug & DBG_ADV))
return;
/* W indicates write-only registers.
* Register dump for write-only registers shows last value written. */
tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]);
tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]);
tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]);
tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]);
tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]);
tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]);
tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]);
tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]);
tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]);
tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]);
tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]);
tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]);
tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]);
tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]);
tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]);
tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]);
tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]);
tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]);
tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]);
}
static void tda18271_read_regs(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
unsigned char buf = 0x00;
int ret;
struct i2c_msg msg[] = {
{ .addr = priv->i2c_addr, .flags = 0,
.buf = &buf, .len = 1 },
{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
.buf = regs, .len = 16 }
};
tda18271_i2c_gate_ctrl(fe, 1);
/* read all registers */
ret = i2c_transfer(priv->i2c_adap, msg, 2);
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 2)
tda_err("ERROR: i2c_transfer returned: %d\n", ret);
if (tda18271_debug & DBG_REG)
tda18271_dump_regs(fe, 0);
}
static void tda18271_read_extended(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
unsigned char regdump[TDA18271_NUM_REGS];
unsigned char buf = 0x00;
int ret, i;
struct i2c_msg msg[] = {
{ .addr = priv->i2c_addr, .flags = 0,
.buf = &buf, .len = 1 },
{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
.buf = regdump, .len = TDA18271_NUM_REGS }
};
tda18271_i2c_gate_ctrl(fe, 1);
/* read all registers */
ret = i2c_transfer(priv->i2c_adap, msg, 2);
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 2)
tda_err("ERROR: i2c_transfer returned: %d\n", ret);
for (i = 0; i <= TDA18271_NUM_REGS; i++) {
/* don't update write-only registers */
if ((i != R_EB9) &&
(i != R_EB16) &&
(i != R_EB17) &&
(i != R_EB19) &&
(i != R_EB20))
regs[i] = regdump[i];
}
if (tda18271_debug & DBG_REG)
tda18271_dump_regs(fe, 1);
}
static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
unsigned char buf[TDA18271_NUM_REGS+1];
struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
.buf = buf, .len = len+1 };
int i, ret;
BUG_ON((len == 0) || (idx+len > sizeof(buf)));
buf[0] = idx;
for (i = 1; i <= len; i++) {
buf[i] = regs[idx-1+i];
}
tda18271_i2c_gate_ctrl(fe, 1);
/* write registers */
ret = i2c_transfer(priv->i2c_adap, &msg, 1);
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 1)
tda_err("ERROR: i2c_transfer returned: %d\n", ret);
}
/*---------------------------------------------------------------------*/
static int tda18271_init_regs(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
tda_dbg("initializing registers for device @ %d-%04x\n",
i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
/* initialize registers */
switch (priv->id) {
case TDA18271HDC1:
regs[R_ID] = 0x83;
break;
case TDA18271HDC2:
regs[R_ID] = 0x84;
break;
};
regs[R_TM] = 0x08;
regs[R_PL] = 0x80;
regs[R_EP1] = 0xc6;
regs[R_EP2] = 0xdf;
regs[R_EP3] = 0x16;
regs[R_EP4] = 0x60;
regs[R_EP5] = 0x80;
regs[R_CPD] = 0x80;
regs[R_CD1] = 0x00;
regs[R_CD2] = 0x00;
regs[R_CD3] = 0x00;
regs[R_MPD] = 0x00;
regs[R_MD1] = 0x00;
regs[R_MD2] = 0x00;
regs[R_MD3] = 0x00;
switch (priv->id) {
case TDA18271HDC1:
regs[R_EB1] = 0xff;
break;
case TDA18271HDC2:
regs[R_EB1] = 0xfc;
break;
};
regs[R_EB2] = 0x01;
regs[R_EB3] = 0x84;
regs[R_EB4] = 0x41;
regs[R_EB5] = 0x01;
regs[R_EB6] = 0x84;
regs[R_EB7] = 0x40;
regs[R_EB8] = 0x07;
regs[R_EB9] = 0x00;
regs[R_EB10] = 0x00;
regs[R_EB11] = 0x96;
switch (priv->id) {
case TDA18271HDC1:
regs[R_EB12] = 0x0f;
break;
case TDA18271HDC2:
regs[R_EB12] = 0x33;
break;
};
regs[R_EB13] = 0xc1;
regs[R_EB14] = 0x00;
regs[R_EB15] = 0x8f;
regs[R_EB16] = 0x00;
regs[R_EB17] = 0x00;
switch (priv->id) {
case TDA18271HDC1:
regs[R_EB18] = 0x00;
break;
case TDA18271HDC2:
regs[R_EB18] = 0x8c;
break;
};
regs[R_EB19] = 0x00;
regs[R_EB20] = 0x20;
switch (priv->id) {
case TDA18271HDC1:
regs[R_EB21] = 0x33;
break;
case TDA18271HDC2:
regs[R_EB21] = 0xb3;
break;
};
regs[R_EB22] = 0x48;
regs[R_EB23] = 0xb0;
tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
/* setup agc1 gain */
regs[R_EB17] = 0x00;
tda18271_write_regs(fe, R_EB17, 1);
regs[R_EB17] = 0x03;
tda18271_write_regs(fe, R_EB17, 1);
regs[R_EB17] = 0x43;
tda18271_write_regs(fe, R_EB17, 1);
regs[R_EB17] = 0x4c;
tda18271_write_regs(fe, R_EB17, 1);
/* setup agc2 gain */
if ((priv->id) == TDA18271HDC1) {
regs[R_EB20] = 0xa0;
tda18271_write_regs(fe, R_EB20, 1);
regs[R_EB20] = 0xa7;
tda18271_write_regs(fe, R_EB20, 1);
regs[R_EB20] = 0xe7;
tda18271_write_regs(fe, R_EB20, 1);
regs[R_EB20] = 0xec;
tda18271_write_regs(fe, R_EB20, 1);
}
/* image rejection calibration */
/* low-band */
regs[R_EP3] = 0x1f;
regs[R_EP4] = 0x66;
regs[R_EP5] = 0x81;
regs[R_CPD] = 0xcc;
regs[R_CD1] = 0x6c;
regs[R_CD2] = 0x00;
regs[R_CD3] = 0x00;
regs[R_MPD] = 0xcd;
regs[R_MD1] = 0x77;
regs[R_MD2] = 0x08;
regs[R_MD3] = 0x00;
switch (priv->id) {
case TDA18271HDC1:
tda18271_write_regs(fe, R_EP3, 11);
break;
case TDA18271HDC2:
tda18271_write_regs(fe, R_EP3, 12);
break;
};
if ((priv->id) == TDA18271HDC2) {
/* main pll cp source on */
regs[R_EB4] = 0x61;
tda18271_write_regs(fe, R_EB4, 1);
msleep(1);
/* main pll cp source off */
regs[R_EB4] = 0x41;
tda18271_write_regs(fe, R_EB4, 1);
}
msleep(5); /* pll locking */
/* launch detector */
tda18271_write_regs(fe, R_EP1, 1);
msleep(5); /* wanted low measurement */
regs[R_EP5] = 0x85;
regs[R_CPD] = 0xcb;
regs[R_CD1] = 0x66;
regs[R_CD2] = 0x70;
tda18271_write_regs(fe, R_EP3, 7);
msleep(5); /* pll locking */
/* launch optimization algorithm */
tda18271_write_regs(fe, R_EP2, 1);
msleep(30); /* image low optimization completion */
/* mid-band */
regs[R_EP5] = 0x82;
regs[R_CPD] = 0xa8;
regs[R_CD2] = 0x00;
regs[R_MPD] = 0xa9;
regs[R_MD1] = 0x73;
regs[R_MD2] = 0x1a;
tda18271_write_regs(fe, R_EP3, 11);
msleep(5); /* pll locking */
tda18271_write_regs(fe, R_EP1, 1);
msleep(5); /* wanted mid measurement */
regs[R_EP5] = 0x86;
regs[R_CPD] = 0xa8;
regs[R_CD1] = 0x66;
regs[R_CD2] = 0xa0;
tda18271_write_regs(fe, R_EP3, 7);
msleep(5); /* pll locking */
/* launch optimization algorithm */
tda18271_write_regs(fe, R_EP2, 1);
msleep(30); /* image mid optimization completion */
/* high-band */
regs[R_EP5] = 0x83;
regs[R_CPD] = 0x98;
regs[R_CD1] = 0x65;
regs[R_CD2] = 0x00;
regs[R_MPD] = 0x99;
regs[R_MD1] = 0x71;
regs[R_MD2] = 0xcd;
tda18271_write_regs(fe, R_EP3, 11);
msleep(5); /* pll locking */
/* launch detector */
tda18271_write_regs(fe, R_EP1, 1);
msleep(5); /* wanted high measurement */
regs[R_EP5] = 0x87;
regs[R_CD1] = 0x65;
regs[R_CD2] = 0x50;
tda18271_write_regs(fe, R_EP3, 7);
msleep(5); /* pll locking */
/* launch optimization algorithm */
tda18271_write_regs(fe, R_EP2, 1);
msleep(30); /* image high optimization completion */
/* return to normal mode */
regs[R_EP4] = 0x64;
tda18271_write_regs(fe, R_EP4, 1);
/* synchronize */
tda18271_write_regs(fe, R_EP1, 1);
return 0;
}
static int tda18271_init(struct dvb_frontend *fe) static int tda18271_init(struct dvb_frontend *fe)
{ {
struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_priv *priv = fe->tuner_priv;
...@@ -467,162 +42,6 @@ static int tda18271_init(struct dvb_frontend *fe) ...@@ -467,162 +42,6 @@ static int tda18271_init(struct dvb_frontend *fe)
return 0; 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;
int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
if (ret < 0)
goto fail;
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;
fail:
return ret;
}
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;
int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
if (ret < 0)
goto fail;
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;
fail:
return ret;
}
static int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
{
/* Sets BP filter bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
if (ret < 0)
goto fail;
regs[R_EP1] &= ~0x07; /* clear bp filter bits */
regs[R_EP1] |= (0x07 & val);
fail:
return ret;
}
static int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
{
/* Sets K & M bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
if (ret < 0)
goto fail;
regs[R_EB13] &= ~0x7c; /* clear k & m bits */
regs[R_EB13] |= (0x7c & val);
fail:
return ret;
}
static int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
{
/* Sets RF Band bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
if (ret < 0)
goto fail;
regs[R_EP2] &= ~0xe0; /* clear rf band bits */
regs[R_EP2] |= (0xe0 & (val << 5));
fail:
return ret;
}
static int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
{
/* Sets Gain Taper bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
if (ret < 0)
goto fail;
regs[R_EP2] &= ~0x1f; /* clear gain taper bits */
regs[R_EP2] |= (0x1f & val);
fail:
return ret;
}
static int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
{
/* Sets IR Meas bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
if (ret < 0)
goto fail;
regs[R_EP5] &= ~0x07;
regs[R_EP5] |= (0x07 & val);
fail:
return ret;
}
static int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
{
/* Sets RF Cal bits, but does not write them */
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u8 val;
int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val);
if (ret < 0)
goto fail;
regs[R_EB14] = val;
fail:
return ret;
}
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
static int tda18271_channel_configuration(struct dvb_frontend *fe, static int tda18271_channel_configuration(struct dvb_frontend *fe,
......
/* /*
tda18271-priv.h - private header for the NXP TDA18271 silicon tuner tda18271-priv.h - private header for the NXP TDA18271 silicon tuner
Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -196,6 +196,23 @@ extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, ...@@ -196,6 +196,23 @@ extern int tda18271_lookup_cid_target(struct dvb_frontend *fe,
extern int tda18271_assign_map_layout(struct dvb_frontend *fe); extern int tda18271_assign_map_layout(struct dvb_frontend *fe);
/*---------------------------------------------------------------------*/
extern int tda18271_read_regs(struct dvb_frontend *fe);
extern int tda18271_read_extended(struct dvb_frontend *fe);
extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
extern int tda18271_init_regs(struct dvb_frontend *fe);
extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq);
extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq);
extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq);
extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq);
extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq);
extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq);
extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
#endif /* __TDA18271_PRIV_H__ */ #endif /* __TDA18271_PRIV_H__ */
/* /*
......
/* /*
tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
......
/* /*
tda18271.h - header for the Philips / NXP TDA18271 silicon tuner tda18271.h - header for the Philips / NXP TDA18271 silicon tuner
Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册