aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/frontends
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/frontends')
-rw-r--r--drivers/media/dvb/frontends/Kconfig18
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c4
-rw-r--r--drivers/media/dvb/frontends/bsbe1.h6
-rw-r--r--drivers/media/dvb/frontends/bsru6.h6
-rw-r--r--drivers/media/dvb/frontends/cx22700.c31
-rw-r--r--drivers/media/dvb/frontends/cx22700.h4
-rw-r--r--drivers/media/dvb/frontends/cx22702.c29
-rw-r--r--drivers/media/dvb/frontends/cx22702.h7
-rw-r--r--drivers/media/dvb/frontends/cx24110.c26
-rw-r--r--drivers/media/dvb/frontends/cx24110.h5
-rw-r--r--drivers/media/dvb/frontends/cx24123.c195
-rw-r--r--drivers/media/dvb/frontends/cx24123.h13
-rw-r--r--drivers/media/dvb/frontends/dib3000-common.h2
-rw-r--r--drivers/media/dvb/frontends/dib3000.h4
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c11
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c14
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c181
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h18
-rw-r--r--drivers/media/dvb/frontends/dvb_dummy_fe.c21
-rw-r--r--drivers/media/dvb/frontends/isl6421.c149
-rw-r--r--drivers/media/dvb/frontends/isl6421.h46
-rw-r--r--drivers/media/dvb/frontends/l64781.c11
-rw-r--r--drivers/media/dvb/frontends/l64781.h4
-rw-r--r--drivers/media/dvb/frontends/lg_h06xf.h64
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c19
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.h1
-rw-r--r--drivers/media/dvb/frontends/lnbp21.c145
-rw-r--r--drivers/media/dvb/frontends/lnbp21.h102
-rw-r--r--drivers/media/dvb/frontends/mt312.c46
-rw-r--r--drivers/media/dvb/frontends/mt312.h4
-rw-r--r--drivers/media/dvb/frontends/mt352.c23
-rw-r--r--drivers/media/dvb/frontends/mt352.h6
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c20
-rw-r--r--drivers/media/dvb/frontends/nxt200x.h4
-rw-r--r--drivers/media/dvb/frontends/nxt6000.c29
-rw-r--r--drivers/media/dvb/frontends/nxt6000.h4
-rw-r--r--drivers/media/dvb/frontends/or51132.c157
-rw-r--r--drivers/media/dvb/frontends/or51132.h2
-rw-r--r--drivers/media/dvb/frontends/or51211.c4
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c43
-rw-r--r--drivers/media/dvb/frontends/s5h1420.h4
-rw-r--r--drivers/media/dvb/frontends/sp8870.c31
-rw-r--r--drivers/media/dvb/frontends/sp8870.h4
-rw-r--r--drivers/media/dvb/frontends/sp887x.c38
-rw-r--r--drivers/media/dvb/frontends/sp887x.h6
-rw-r--r--drivers/media/dvb/frontends/stv0297.c73
-rw-r--r--drivers/media/dvb/frontends/stv0297.h6
-rw-r--r--drivers/media/dvb/frontends/stv0299.c41
-rw-r--r--drivers/media/dvb/frontends/stv0299.h5
-rw-r--r--drivers/media/dvb/frontends/tda10021.c39
-rw-r--r--drivers/media/dvb/frontends/tda10021.h6
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c55
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h5
-rw-r--r--drivers/media/dvb/frontends/tda8083.c12
-rw-r--r--drivers/media/dvb/frontends/tda8083.h4
-rw-r--r--drivers/media/dvb/frontends/ves1820.c19
-rw-r--r--drivers/media/dvb/frontends/ves1820.h4
-rw-r--r--drivers/media/dvb/frontends/ves1x93.c29
-rw-r--r--drivers/media/dvb/frontends/ves1x93.h4
-rw-r--r--drivers/media/dvb/frontends/zl10353.c30
-rw-r--r--drivers/media/dvb/frontends/zl10353.h6
62 files changed, 1150 insertions, 751 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 37d5e0af1683..0ef361f0309b 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -157,7 +157,7 @@ config DVB_STV0297
help
A DVB-C tuner module. Say Y when you want to support this frontend.
-comment "ATSC (North American/Korean Terresterial DTV) frontends"
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
depends on DVB_CORE
config DVB_NXT200X
@@ -216,4 +216,20 @@ config DVB_LGDT330X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+
+comment "Miscellaneous devices"
+ depends on DVB_CORE
+
+config DVB_LNBP21
+ tristate "LNBP21 SEC controller"
+ depends on DVB_CORE
+ help
+ An SEC control chip.
+
+config DVB_ISL6421
+ tristate "ISL6421 SEC controller"
+ depends on DVB_CORE
+ help
+ An SEC control chip.
+
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index d09b6071fbaf..5222245c7f59 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -31,3 +31,5 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index 1708a1d4893e..baeb311de893 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -48,7 +48,6 @@
struct bcm3510_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct bcm3510_config* config;
struct dvb_frontend frontend;
@@ -791,10 +790,9 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
mutex_init(&state->hab_mutex);
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
index 78573b22ada9..d8f65738e5d2 100644
--- a/drivers/media/dvb/frontends/bsbe1.h
+++ b/drivers/media/dvb/frontends/bsbe1.h
@@ -89,12 +89,13 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
int ret;
u8 data[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+ struct i2c_adapter *i2c = fe->tuner_priv;
if ((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
@@ -105,6 +106,8 @@ static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c,
data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
ret = i2c_transfer(i2c, &msg, 1);
return (ret != 1) ? -EIO : 0;
}
@@ -117,7 +120,6 @@ static struct stv0299_config alps_bsbe1_config = {
.skip_reinit = 0,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsbe1_set_symbol_rate,
- .pll_set = alps_bsbe1_pll_set,
};
#endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
index 2a5366ce79cc..e231cd84b3a1 100644
--- a/drivers/media/dvb/frontends/bsru6.h
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -101,11 +101,12 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct i2c_adapter *i2c = fe->tuner_priv;
if ((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
@@ -119,6 +120,8 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c,
if (params->frequency > 1530000)
buf[3] = 0xc0;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(i2c, &msg, 1) != 1)
return -EIO;
return 0;
@@ -134,7 +137,6 @@ static struct stv0299_config alps_bsru6_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
};
#endif
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 755f774f6b7d..3c7c09a362b2 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -34,8 +34,6 @@ struct cx22700_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct cx22700_config* config;
struct dvb_frontend frontend;
@@ -247,12 +245,6 @@ static int cx22700_init (struct dvb_frontend* fe)
cx22700_writereg (state, 0x00, 0x01);
- if (state->config->pll_init) {
- cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
- state->config->pll_init(fe);
- cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
- }
-
return 0;
}
@@ -333,9 +325,11 @@ static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
cx22700_writereg (state, 0x00, 0x00);
- cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
- state->config->pll_set(fe, p);
- cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
cx22700_set_inversion (state, p->inversion);
cx22700_set_tps (state, &p->u.ofdm);
cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */
@@ -353,6 +347,17 @@ static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
return cx22700_get_tps (state, &p->u.ofdm);
}
+static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct cx22700_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return cx22700_writereg(state, 0x0a, 0x00);
+ } else {
+ return cx22700_writereg(state, 0x0a, 0x01);
+ }
+}
+
static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 150;
@@ -381,13 +386,12 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (cx22700_readreg(state, 0x07) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -413,6 +417,7 @@ static struct dvb_frontend_ops cx22700_ops = {
.release = cx22700_release,
.init = cx22700_init,
+ .i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
.set_frontend = cx22700_set_frontend,
.get_frontend = cx22700_get_frontend,
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
index c9145b45874b..dcd8979c1a15 100644
--- a/drivers/media/dvb/frontends/cx22700.h
+++ b/drivers/media/dvb/frontends/cx22700.h
@@ -29,10 +29,6 @@ struct cx22700_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 0fc899f81c5e..4106d46c957f 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -40,8 +40,6 @@ struct cx22702_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct cx22702_config* config;
@@ -211,22 +209,10 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
u8 val;
struct cx22702_state* state = fe->demodulator_priv;
- /* set PLL */
- cx22702_i2c_gate_ctrl(fe, 1);
- if (state->config->pll_set) {
- state->config->pll_set(fe, p);
- } else if (state->config->pll_desc) {
- u8 pllbuf[4];
- struct i2c_msg msg = { .addr = state->config->pll_address,
- .buf = pllbuf, .len = 4 };
- dvb_pll_configure(state->config->pll_desc, pllbuf,
- p->frequency,
- p->u.ofdm.bandwidth);
- i2c_transfer(state->i2c, &msg, 1);
- } else {
- BUG();
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- cx22702_i2c_gate_ctrl(fe, 0);
/* set inversion */
cx22702_set_inversion (state, p->inversion);
@@ -358,10 +344,6 @@ static int cx22702_init (struct dvb_frontend* fe)
cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
- /* init PLL */
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
cx22702_i2c_gate_ctrl(fe, 0);
return 0;
@@ -495,7 +477,6 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
state->prevUCBlocks = 0;
/* check if the demod is there */
@@ -503,7 +484,7 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -530,6 +511,7 @@ static struct dvb_frontend_ops cx22702_ops = {
.release = cx22702_release,
.init = cx22702_init,
+ .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
.set_frontend = cx22702_set_tps,
.get_frontend = cx22702_get_frontend,
@@ -540,7 +522,6 @@ static struct dvb_frontend_ops cx22702_ops = {
.read_signal_strength = cx22702_read_signal_strength,
.read_snr = cx22702_read_snr,
.read_ucblocks = cx22702_read_ucblocks,
- .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
};
module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 5633976a58f1..7f2f241e5d44 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -39,13 +39,6 @@ struct cx22702_config
#define CX22702_PARALLEL_OUTPUT 0
#define CX22702_SERIAL_OUTPUT 1
u8 output_mode;
-
- /* PLL maintenance */
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
-
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index f3edf8b517dd..ce3c7398bac9 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -36,8 +36,6 @@ struct cx24110_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct cx24110_config* config;
struct dvb_frontend frontend;
@@ -250,7 +248,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
int i;
-dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
+ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
if (srate>90999000UL/2)
srate=90999000UL/2;
if (srate<500000)
@@ -366,17 +364,6 @@ static int cx24110_initfe(struct dvb_frontend* fe)
cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
};
- if (state->config->pll_init) state->config->pll_init(fe);
-
- return 0;
-}
-
-static int cx24110_sleep(struct dvb_frontend *fe)
-{
- struct cx24110_state *state = fe->demodulator_priv;
-
- if (state->config->pll_sleep)
- return state->config->pll_sleep(fe);
return 0;
}
@@ -548,7 +535,12 @@ static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct cx24110_state *state = fe->demodulator_priv;
- state->config->pll_set(fe, p);
+
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
cx24110_set_inversion (state, p->inversion);
cx24110_set_fec (state, p->u.qpsk.fec_inner);
cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -612,7 +604,6 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->lastbler = 0;
state->lastesn0 = 0;
@@ -622,7 +613,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
if ((ret != 0x5a) && (ret != 0x69)) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -651,7 +642,6 @@ static struct dvb_frontend_ops cx24110_ops = {
.release = cx24110_release,
.init = cx24110_initfe,
- .sleep = cx24110_sleep,
.set_frontend = cx24110_set_frontend,
.get_frontend = cx24110_get_frontend,
.read_status = cx24110_read_status,
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index 609ac642b406..b354a64e0e74 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -31,11 +31,6 @@ struct cx24110_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
- int (*pll_sleep)(struct dvb_frontend* fe);
};
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 691dc840dcc0..f2f795cba56a 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -41,14 +41,12 @@ static int debug;
struct cx24123_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct cx24123_config* config;
struct dvb_frontend frontend;
u32 lastber;
u16 snr;
- u8 lnbreg;
/* Some PLL specifics for tuning */
u32 VCAarg;
@@ -249,29 +247,6 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
return 0;
}
-static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
-{
- u8 buf[] = { reg, data };
- /* fixme: put the intersil addr int the config */
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
- int err;
-
- if (debug>1)
- printk("cx24123: %s: writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
- __FUNCTION__,reg, data);
-
- if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
- printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
- " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
- return -EREMOTEIO;
- }
-
- /* cache the write, no way to read back */
- state->lnbreg = data;
-
- return 0;
-}
-
static int cx24123_readreg(struct cx24123_state* state, u8 reg)
{
int ret;
@@ -295,11 +270,6 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg)
return b1[0];
}
-static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
-{
- return state->lnbreg;
-}
-
static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
{
u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -458,8 +428,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
u8 pll_mult;
/* check if symbol rate is within limits */
- if ((srate > state->ops.info.symbol_rate_max) ||
- (srate < state->ops.info.symbol_rate_min))
+ if ((srate > state->frontend.ops.info.symbol_rate_max) ||
+ (srate < state->frontend.ops.info.symbol_rate_min))
return -EOPNOTSUPP;;
/* choose the sampling rate high enough for the required operation,
@@ -687,13 +657,6 @@ static int cx24123_initfe(struct dvb_frontend* fe)
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
- /* Configure the LNB for 14V */
- if (state->config->use_isl6421)
- cx24123_writelnbreg(state, 0x0, 0x2a);
-
return 0;
}
@@ -702,50 +665,18 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
- switch (state->config->use_isl6421) {
-
- case 1:
+ val = cx24123_readreg(state, 0x29) & ~0x40;
- val = cx24123_readlnbreg(state, 0x0);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: isl6421 voltage = 13V\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
- case SEC_VOLTAGE_18:
- dprintk("%s: isl6421 voltage = 18V\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
- case SEC_VOLTAGE_OFF:
- dprintk("%s: isl5421 voltage off\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x30);
- default:
- return -EINVAL;
- };
-
- case 0:
-
- val = cx24123_readreg(state, 0x29);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: setting voltage 13V\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 1);
- return cx24123_writereg(state, 0x29, val | 0x80);
- case SEC_VOLTAGE_18:
- dprintk("%s: setting voltage 18V\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 1);
- return cx24123_writereg(state, 0x29, val & 0x7f);
- case SEC_VOLTAGE_OFF:
- dprintk("%s: setting voltage off\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 0);
- return 0;
- default:
- return -EINVAL;
- };
- }
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x80);
+ case SEC_VOLTAGE_18:
+ dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0x7f);
+ default:
+ return -EINVAL;
+ };
return 0;
}
@@ -766,27 +697,20 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
{
struct cx24123_state *state = fe->demodulator_priv;
- int i, val;
+ int i, val, tone;
dprintk("%s:\n",__FUNCTION__);
- /* check if continuous tone has been stopped */
- if (state->config->use_isl6421)
- val = cx24123_readlnbreg(state, 0x00) & 0x10;
- else
- val = cx24123_readreg(state, 0x29) & 0x10;
-
-
- if (val) {
- printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
- return -ENOTSUPP;
- }
+ /* stop continuous tone if enabled */
+ tone = cx24123_readreg(state, 0x29);
+ if (tone & 0x10)
+ cx24123_writereg(state, 0x29, tone & ~0x50);
/* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state);
/* select tone mode */
- cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
for (i = 0; i < cmd->msg_len; i++)
cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
@@ -797,36 +721,33 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
/* wait for diseqc message to finish sending */
cx24123_wait_for_diseqc(state);
+ /* restart continuous tone if enabled */
+ if (tone & 0x10) {
+ cx24123_writereg(state, 0x29, tone & ~0x40);
+ }
+
return 0;
}
static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
{
struct cx24123_state *state = fe->demodulator_priv;
- int val;
+ int val, tone;
dprintk("%s:\n", __FUNCTION__);
- /* check if continuous tone has been stoped */
- if (state->config->use_isl6421)
- val = cx24123_readlnbreg(state, 0x00) & 0x10;
- else
- val = cx24123_readreg(state, 0x29) & 0x10;
-
-
- if (val) {
- printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
- return -ENOTSUPP;
- }
+ /* stop continuous tone if enabled */
+ tone = cx24123_readreg(state, 0x29);
+ if (tone & 0x10)
+ cx24123_writereg(state, 0x29, tone & ~0x50);
+ /* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state);
/* select tone mode */
- val = cx24123_readreg(state, 0x2a) & 0xf8;
- cx24123_writereg(state, 0x2a, val | 0x04);
-
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
+ msleep(30);
val = cx24123_readreg(state, 0x29);
-
if (burst == SEC_MINI_A)
cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
else if (burst == SEC_MINI_B)
@@ -835,7 +756,12 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
return -EINVAL;
cx24123_wait_for_diseqc(state);
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
+ /* restart continuous tone if enabled */
+ if (tone & 0x10) {
+ cx24123_writereg(state, 0x29, tone & ~0x40);
+ }
return 0;
}
@@ -976,38 +902,21 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
- switch (state->config->use_isl6421) {
- case 1:
-
- val = cx24123_readlnbreg(state, 0x0);
-
- switch (tone) {
- case SEC_TONE_ON:
- dprintk("%s: isl6421 sec tone on\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val | 0x10);
- case SEC_TONE_OFF:
- dprintk("%s: isl6421 sec tone off\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x2f);
- default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
- return -EINVAL;
- }
-
- case 0:
+ /* wait for diseqc queue ready */
+ cx24123_wait_for_diseqc(state);
- val = cx24123_readreg(state, 0x29);
+ val = cx24123_readreg(state, 0x29) & ~0x40;
- switch (tone) {
- case SEC_TONE_ON:
- dprintk("%s: setting tone on\n", __FUNCTION__);
- return cx24123_writereg(state, 0x29, val | 0x10);
- case SEC_TONE_OFF:
- dprintk("%s: setting tone off\n",__FUNCTION__);
- return cx24123_writereg(state, 0x29, val & 0xef);
- default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
- return -EINVAL;
- }
+ switch (tone) {
+ case SEC_TONE_ON:
+ dprintk("%s: setting tone on\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x10);
+ case SEC_TONE_OFF:
+ dprintk("%s: setting tone off\n",__FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0xef);
+ default:
+ printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+ return -EINVAL;
}
return 0;
@@ -1040,10 +949,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->snr = 0;
- state->lnbreg = 0;
state->VCAarg = 0;
state->VGAarg = 0;
state->bandselectarg = 0;
@@ -1059,7 +966,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 0c922b5e9263..9606f825935c 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -28,21 +28,8 @@ struct cx24123_config
/* the demodulator's i2c address */
u8 demod_address;
- /*
- cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
- for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
- from register 0x29 of the CX24123 demodulator
- */
- int use_isl6421;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-
- void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
};
extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
index c31d6df15472..be1c0d3e1389 100644
--- a/drivers/media/dvb/frontends/dib3000-common.h
+++ b/drivers/media/dvb/frontends/dib3000-common.h
@@ -38,8 +38,6 @@
struct dib3000_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
struct dib3000_config config;
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index 2d5475b5c063..ec927628d273 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -30,10 +30,6 @@ struct dib3000_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance and the i2c address of the PLL */
- int (*pll_init)(struct dvb_frontend *fe);
- int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
};
struct dib_fe_xfer_ops
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index ae589adb1c0a..7c6dc7e30900 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -60,8 +60,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
fe_code_rate_t fe_cr = FEC_NONE;
int search_state, seq;
- if (tuner && state->config.pll_set) {
- state->config.pll_set(fe, fep);
+ if (tuner && fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fep);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
deb_setf("bandwidth: ");
switch (ofdm->bandwidth) {
@@ -386,9 +387,6 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
- if (state->config.pll_init)
- state->config.pll_init(fe);
-
return 0;
}
@@ -707,7 +705,6 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
- memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -717,7 +714,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* set the xfer operations */
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 3b303dbb6156..6c3be2529980 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -462,8 +462,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
int search_state,auto_val;
u16 val;
- if (tuner && state->config.pll_set) { /* initial call from dvb */
- state->config.pll_set(fe,fep);
+ if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+ fe->ops.tuner_ops.set_params(fe, fep);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
state->last_tuned_freq = fep->frequency;
// if (!scanboost) {
@@ -642,9 +643,6 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
- if (state->config.pll_init)
- state->config.pll_init(fe);
-
deb_info("init end\n");
return 0;
}
@@ -839,7 +837,6 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
- memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -859,7 +856,7 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* set the xfer operations */
@@ -876,6 +873,7 @@ error:
kfree(state);
return NULL;
}
+EXPORT_SYMBOL(dib3000mc_attach);
static struct dvb_frontend_ops dib3000mc_ops = {
@@ -914,5 +912,3 @@ static struct dvb_frontend_ops dib3000mc_ops = {
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000mc_attach);
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 791706ec1da3..a189683454b7 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -227,10 +227,10 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
EXPORT_SYMBOL(dvb_pll_tua6034);
/* Infineon TUA6034
- * used in LG TDVS H061F and LG TDVS H062F
+ * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
*/
-struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
- .name = "LG/Infineon TUA6034",
+struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+ .name = "LG TDVS-H06xF",
.min = 54000000,
.max = 863000000,
.count = 3,
@@ -240,7 +240,7 @@ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
{ 999999999, 44000000, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_tdvs_tua6034);
+EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
/* Philips FMD1216ME
* used in Medion Hybrid PCMCIA card and USB Box
@@ -419,6 +419,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
};
EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+struct dvb_pll_priv {
+ /* i2c details */
+ int pll_i2c_address;
+ struct i2c_adapter *i2c;
+
+ /* the PLL descriptor */
+ struct dvb_pll_desc *pll_desc;
+
+ /* cached frequency/bandwidth */
+ u32 frequency;
+ u32 bandwidth;
+};
+
/* ----------------------------------------------------------- */
/* code */
@@ -443,7 +456,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
if (debug)
printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
desc->name, freq, bandwidth, i, desc->count);
- BUG_ON(i == desc->count);
+ if (i == desc->count)
+ return -EINVAL;
div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
buf[0] = div >> 8;
@@ -462,6 +476,163 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
}
EXPORT_SYMBOL(dvb_pll_configure);
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+ if (fe->tuner_priv)
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int i;
+ int result;
+
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (priv->pll_desc->entries[i].limit == 0)
+ break;
+ }
+ if (i == priv->pll_desc->count)
+ return 0;
+
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = priv->pll_desc->entries[i].config;
+ buf[3] = priv->pll_desc->entries[i].cb;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ return 0;
+}
+
+static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int result;
+ u32 div;
+ int i;
+ u32 bandwidth = 0;
+
+ if (priv->i2c == NULL)
+ return -EINVAL;
+
+ // DVBT bandwidth only just now
+ if (fe->ops.info.type == FE_OFDM) {
+ bandwidth = params->u.ofdm.bandwidth;
+ }
+
+ if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+ return result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ // calculate the frequency we set it to
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (params->frequency > priv->pll_desc->entries[i].limit)
+ continue;
+ break;
+ }
+ div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+ priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->bandwidth = bandwidth;
+
+ return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ int result;
+ u32 div;
+ int i;
+ u32 bandwidth = 0;
+
+ if (buf_len < 5)
+ return -EINVAL;
+
+ // DVBT bandwidth only just now
+ if (fe->ops.info.type == FE_OFDM) {
+ bandwidth = params->u.ofdm.bandwidth;
+ }
+
+ if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+ return result;
+ buf[0] = priv->pll_i2c_address;
+
+ // calculate the frequency we set it to
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (params->frequency > priv->pll_desc->entries[i].limit)
+ continue;
+ break;
+ }
+ div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+ priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->bandwidth = bandwidth;
+
+ return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+ .release = dvb_pll_release,
+ .sleep = dvb_pll_sleep,
+ .set_params = dvb_pll_set_params,
+ .calc_regs = dvb_pll_calc_regs,
+ .get_frequency = dvb_pll_get_frequency,
+ .get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+{
+ struct dvb_pll_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ priv->pll_i2c_address = pll_addr;
+ priv->i2c = i2c;
+ priv->pll_desc = desc;
+
+ memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+ strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
+ fe->ops.tuner_ops.info.frequency_min = desc->min;
+ fe->ops.tuner_ops.info.frequency_min = desc->max;
+
+ fe->tuner_priv = priv;
+ return 0;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
MODULE_DESCRIPTION("dvb pll library");
MODULE_AUTHOR("Gerd Knorr");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 2b8461784989..66361cd18807 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -5,6 +5,9 @@
#ifndef __DVB_PLL_H__
#define __DVB_PLL_H__
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
struct dvb_pll_desc {
char *name;
u32 min;
@@ -31,7 +34,7 @@ extern struct dvb_pll_desc dvb_pll_unknown_1;
extern struct dvb_pll_desc dvb_pll_tua6010xs;
extern struct dvb_pll_desc dvb_pll_env57h1xd5;
extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_tdvs_tua6034;
+extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
extern struct dvb_pll_desc dvb_pll_tda665x;
extern struct dvb_pll_desc dvb_pll_fmd1216me;
extern struct dvb_pll_desc dvb_pll_tded4;
@@ -44,7 +47,18 @@ extern struct dvb_pll_desc dvb_pll_philips_td1316;
extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth);
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param desc dvb_pll_desc to use.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+
#endif
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 645946a992d9..6271b1e7f6ab 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -30,7 +30,6 @@
struct dvb_dummy_fe_state {
- struct dvb_frontend_ops ops;
struct dvb_frontend frontend;
};
@@ -77,6 +76,11 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten
static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
+ if (fe->ops->tuner_ops->set_params) {
+ fe->ops->tuner_ops->set_params(fe, p);
+ if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+ }
+
return 0;
}
@@ -116,11 +120,8 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -139,11 +140,8 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -162,11 +160,8 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach()
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
new file mode 100644
index 000000000000..58c34db31071
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -0,0 +1,149 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6421.h"
+
+struct isl6421 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ u8 i2c_addr;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ isl6421->config |= ISL6421_EN1;
+ break;
+ case SEC_VOLTAGE_18:
+ isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ if (arg)
+ isl6421->config |= ISL6421_LLC1;
+ else
+ isl6421->config &= ~ISL6421_LLC1;
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6421_release(struct dvb_frontend *fe)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+
+ /* power off */
+ isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops.release = isl6421->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+
+int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear)
+{
+ struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+ if (!isl6421)
+ return -ENOMEM;
+
+ /* default configuration */
+ isl6421->config = ISL6421_ISEL1;
+ isl6421->i2c = i2c;
+ isl6421->i2c_addr = i2c_addr;
+ fe->misc_priv = isl6421;
+
+ /* bits which should be forced to '1' */
+ isl6421->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ isl6421->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(isl6421);
+ fe->misc_priv = NULL;
+ return -EIO;
+ }
+
+ /* install release callback */
+ isl6421->release_chain = fe->ops.release;
+ fe->ops.release = isl6421_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = isl6421_set_voltage;
+ fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL(isl6421_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
+MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
new file mode 100644
index 000000000000..675f80a19b99
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6421.h
@@ -0,0 +1,46 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6421_H
+#define _ISL6421_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+#define ISL6421_OLF1 0x01
+#define ISL6421_EN1 0x02
+#define ISL6421_VSEL1 0x04
+#define ISL6421_LLC1 0x08
+#define ISL6421_ENT1 0x10
+#define ISL6421_ISEL1 0x20
+#define ISL6421_DCL 0x40
+
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear);
+
+#endif
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 1c7c91224472..f3bc82e44a28 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -32,7 +32,6 @@
struct l64781_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct l64781_config* config;
struct dvb_frontend frontend;
@@ -141,7 +140,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
u8 val0x06;
int bw = p->bandwidth - BANDWIDTH_8_MHZ;
- state->config->pll_set(fe, param);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
if (param->inversion != INVERSION_ON &&
param->inversion != INVERSION_OFF)
@@ -463,8 +465,6 @@ static int l64781_init(struct dvb_frontend* fe)
/* Everything is two's complement, soft bit and CSI_OUT too */
l64781_writereg (state, 0x1e, 0x09);
- if (state->config->pll_init) state->config->pll_init(fe);
-
/* delay a bit after first init attempt */
if (state->first) {
state->first = 0;
@@ -508,7 +508,6 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
state->first = 1;
/**
@@ -554,7 +553,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
index 947f65f87465..83b8bc210274 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -29,10 +29,6 @@ struct l64781_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
diff --git a/drivers/media/dvb/frontends/lg_h06xf.h b/drivers/media/dvb/frontends/lg_h06xf.h
new file mode 100644
index 000000000000..754d51d11120
--- /dev/null
+++ b/drivers/media/dvb/frontends/lg_h06xf.h
@@ -0,0 +1,64 @@
+/*
+ * lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ * 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.
+ */
+
+#ifndef _LG_H06XF_H_
+#define _LG_H06XF_H_
+#include "dvb-pll.h"
+
+static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
+ struct dvb_frontend_parameters* params)
+{
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+ int err;
+
+ dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lg_h06xf: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ /* Set the Auxiliary Byte. */
+ buf[0] = buf[2];
+ buf[0] &= ~0x20;
+ buf[0] |= 0x18;
+ buf[1] = 0x50;
+ msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lg_h06xf: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 4691ac54bc1d..6e8ad176e1a1 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -29,6 +29,7 @@
* DViCO FusionHDTV 5 Lite
* DViCO FusionHDTV 5 USB Gold
* Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
+ * pcHDTV HD5500
*
* TODO:
* signal strength always returns 0.
@@ -59,7 +60,6 @@ if (debug) printk(KERN_DEBUG "lgdt330x: " args); \
struct lgdt330x_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct lgdt330x_config* config;
@@ -399,8 +399,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
}
/* Tune to the specified frequency */
- if (state->config->pll_set)
- state->config->pll_set(fe, param);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* Keep track of the new frequency */
/* FIXME this is the wrong way to do this... */
@@ -672,6 +674,7 @@ static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
if (state->current_modulation == VSB_8) {
+ i2c_read_demod_bytes(state, 0x6e, buf, 5);
/* Phase Tracker Mean-Square Error Register for VSB */
noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
} else {
@@ -721,16 +724,19 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
+
+ /* Create dvb_frontend */
switch (config->demod_chip) {
case LGDT3302:
- memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
break;
case LGDT3303:
- memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
break;
default:
goto error;
}
+ state->frontend.demodulator_priv = state;
/* Verify communication with demod chip */
if (i2c_read_demod_bytes(state, 2, buf, 1))
@@ -739,9 +745,6 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
state->current_frequency = -1;
state->current_modulation = -1;
- /* Create dvb_frontend */
- state->frontend.ops = &state->ops;
- state->frontend.demodulator_priv = state;
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index 2a6529cccf1a..bad903c6f0f8 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -43,7 +43,6 @@ struct lgdt330x_config
/* PLL interface */
int (*pll_rf_set) (struct dvb_frontend* fe, int index);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
new file mode 100644
index 000000000000..e933edc8dd29
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -0,0 +1,145 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp21.h"
+
+struct lnbp21 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ lnbp21->config |= LNBP21_EN;
+ break;
+ case SEC_VOLTAGE_18:
+ lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ if (arg)
+ lnbp21->config |= LNBP21_LLC;
+ else
+ lnbp21->config &= ~LNBP21_LLC;
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_release(struct dvb_frontend *fe)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+ /* LNBP power off */
+ lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops.release = lnbp21->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+
+int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+ struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+ if (!lnbp21)
+ return -ENOMEM;
+
+ /* default configuration */
+ lnbp21->config = LNBP21_ISEL;
+ lnbp21->i2c = i2c;
+ fe->misc_priv = lnbp21;
+
+ /* bits which should be forced to '1' */
+ lnbp21->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ lnbp21->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(lnbp21);
+ fe->misc_priv = NULL;
+ return -EIO;
+ }
+
+ /* install release callback */
+ lnbp21->release_chain = fe->ops.release;
+ fe->ops.release = lnbp21_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = lnbp21_set_voltage;
+ fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL(lnbp21_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
+MODULE_AUTHOR("Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
index 0dcbe61b61b1..047a4ab68c01 100644
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -27,7 +27,7 @@
#ifndef _LNBP21_H
#define _LNBP21_H
-/* system register */
+/* system register bits */
#define LNBP21_OLF 0x01
#define LNBP21_OTF 0x02
#define LNBP21_EN 0x04
@@ -37,103 +37,9 @@
#define LNBP21_ISEL 0x40
#define LNBP21_PCL 0x80
-struct lnbp21 {
- u8 config;
- u8 override_or;
- u8 override_and;
- struct i2c_adapter *i2c;
- void (*release_chain)(struct dvb_frontend* fe);
-};
+#include <linux/dvb/frontend.h>
-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
- .buf = &lnbp21->config,
- .len = sizeof(lnbp21->config) };
-
- lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
-
- switch(voltage) {
- case SEC_VOLTAGE_OFF:
- break;
- case SEC_VOLTAGE_13:
- lnbp21->config |= LNBP21_EN;
- break;
- case SEC_VOLTAGE_18:
- lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
- break;
- default:
- return -EINVAL;
- };
-
- lnbp21->config |= lnbp21->override_or;
- lnbp21->config &= lnbp21->override_and;
-
- return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
- .buf = &lnbp21->config,
- .len = sizeof(lnbp21->config) };
-
- if (arg)
- lnbp21->config |= LNBP21_LLC;
- else
- lnbp21->config &= ~LNBP21_LLC;
-
- lnbp21->config |= lnbp21->override_or;
- lnbp21->config &= lnbp21->override_and;
-
- return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp21_exit(struct dvb_frontend *fe)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
- /* LNBP power off */
- lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-
- /* free data & call next release routine */
- fe->ops->release = lnbp21->release_chain;
- kfree(fe->misc_priv);
- fe->misc_priv = NULL;
- if (fe->ops->release)
- fe->ops->release(fe);
-}
-
-static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
-{
- struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
-
- if (!lnbp21)
- return -ENOMEM;
-
- /* default configuration */
- lnbp21->config = LNBP21_ISEL;
-
- /* bits which should be forced to '1' */
- lnbp21->override_or = override_set;
-
- /* bits which should be forced to '0' */
- lnbp21->override_and = ~override_clear;
-
- /* install release callback */
- lnbp21->release_chain = fe->ops->release;
- fe->ops->release = lnbp21_exit;
-
- /* override frontend ops */
- fe->ops->set_voltage = lnbp21_set_voltage;
- fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-
- lnbp21->i2c = i2c;
- fe->misc_priv = lnbp21;
-
- return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-}
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
#endif
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index d3aea83cf218..1ef821825641 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -39,7 +39,6 @@
struct mt312_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct mt312_config* config;
struct dvb_frontend frontend;
@@ -277,12 +276,6 @@ static int mt312_initfe(struct dvb_frontend* fe)
if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
return ret;
- if (state->config->pll_init) {
- mt312_writereg(state, GPP_CTRL, 0x40);
- state->config->pll_init(fe);
- mt312_writereg(state, GPP_CTRL, 0x00);
- }
-
return 0;
}
@@ -477,16 +470,16 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
- if ((p->frequency < fe->ops->info.frequency_min)
- || (p->frequency > fe->ops->info.frequency_max))
+ if ((p->frequency < fe->ops.info.frequency_min)
+ || (p->frequency > fe->ops.info.frequency_max))
return -EINVAL;
if ((p->inversion < INVERSION_OFF)
|| (p->inversion > INVERSION_ON))
return -EINVAL;
- if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
- || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
+ if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
+ || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
return -EINVAL;
if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -529,9 +522,10 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
return -EINVAL;
}
- mt312_writereg(state, GPP_CTRL, 0x40);
- state->config->pll_set(fe, p);
- mt312_writereg(state, GPP_CTRL, 0x00);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* sr = (u16)(sr * 256.0 / 1000000.0) */
sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
@@ -578,6 +572,17 @@ static int mt312_get_frontend(struct dvb_frontend* fe,
return 0;
}
+static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct mt312_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return mt312_writereg(state, GPP_CTRL, 0x40);
+ } else {
+ return mt312_writereg(state, GPP_CTRL, 0x00);
+ }
+}
+
static int mt312_sleep(struct dvb_frontend* fe)
{
struct mt312_state *state = fe->demodulator_priv;
@@ -633,6 +638,7 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
.init = mt312_initfe,
.sleep = mt312_sleep,
+ .i2c_gate_ctrl = mt312_i2c_gate_ctrl,
.set_frontend = mt312_set_frontend,
.get_frontend = mt312_get_frontend,
@@ -663,19 +669,22 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (mt312_readreg(state, ID, &state->id) < 0)
goto error;
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
switch (state->id) {
case ID_VP310:
- strcpy(state->ops.info.name, "Zarlink VP310 DVB-S");
+ strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
state->frequency = 90;
break;
case ID_MT312:
- strcpy(state->ops.info.name, "Zarlink MT312 DVB-S");
+ strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
state->frequency = 60;
break;
default:
@@ -683,9 +692,6 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
goto error;
}
- /* create dvb_frontend */
- state->frontend.ops = &state->ops;
- state->frontend.demodulator_priv = state;
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index 074d844f0139..666a1bd1c244 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -32,10 +32,6 @@ struct mt312_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index aaaec909ddf8..5de7376c94ce 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -45,7 +45,6 @@
struct mt352_state {
struct i2c_adapter* i2c;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
/* configuration settings */
struct mt352_config config;
@@ -286,16 +285,25 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
mt352_calc_input_freq(state, buf+6);
- state->config.pll_set(fe, param, buf+8);
- mt352_write(fe, buf, sizeof(buf));
if (state->config.no_tuner) {
- /* start decoding */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ mt352_write(fe, buf, 8);
mt352_write(fe, fsm_go, 2);
} else {
- /* start tuning */
- mt352_write(fe, tuner_go, 2);
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+ buf[8] <<= 1;
+ mt352_write(fe, buf, sizeof(buf));
+ mt352_write(fe, tuner_go, 2);
+ }
}
+
return 0;
}
@@ -541,13 +549,12 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct mt352_config));
- memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index 03040cd595bb..9e7ff4b8fe5f 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -49,12 +49,6 @@ struct mt352_config
/* Initialise the demodulator and PLL. Cannot be NULL */
int (*demod_init)(struct dvb_frontend* fe);
-
- /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings.
- * byte0: Set to pll i2c address (nonlinux; left shifted by 1)
- * byte1-4: PLL configuration.
- */
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf);
};
extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index 9e3535394509..55671cb5255e 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -55,7 +55,6 @@
struct nxt200x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct nxt200x_config* config;
struct dvb_frontend frontend;
@@ -333,17 +332,17 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
dprintk("%s\n", __FUNCTION__);
- dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+ dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
/* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
* direct write is required for Philips TUV1236D and ALPS TDHU2 */
switch (state->demod_chip) {
case NXT2004:
- if (i2c_writebytes(state, state->config->pll_address, data, 4))
+ if (i2c_writebytes(state, data[0], data+1, 4))
printk(KERN_WARNING "nxt200x: error writing to tuner\n");
/* wait until we have a lock */
while (count < 20) {
- i2c_readbytes(state, state->config->pll_address, &buf, 1);
+ i2c_readbytes(state, data[0], &buf, 1);
if (buf & 0x40)
return 0;
msleep(100);
@@ -361,10 +360,10 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
nxt200x_writebytes(state, 0x34, &buf, 1);
/* write actual tuner bytes */
- nxt200x_writebytes(state, 0x36, data, 4);
+ nxt200x_writebytes(state, 0x36, data+1, 4);
/* set tuner i2c address */
- buf = state->config->pll_address;
+ buf = data[0] << 1;
nxt200x_writebytes(state, 0x35, &buf, 1);
/* write UC Opmode to begin transfer */
@@ -534,7 +533,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
struct dvb_frontend_parameters *p)
{
struct nxt200x_state* state = fe->demodulator_priv;
- u8 buf[4];
+ u8 buf[5];
/* stop the micro first */
nxt200x_microcontroller_stop(state);
@@ -548,7 +547,9 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
}
/* get tuning information */
- dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+ }
/* set additional params */
switch (p->u.vsb.modulation) {
@@ -1159,7 +1160,6 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* read card id */
@@ -1198,7 +1198,7 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 1d9d70bc37ef..34d61735845b 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -38,10 +38,6 @@ struct nxt200x_config
/* the demodulator's i2c address */
u8 demod_address;
- /* tuner information */
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
-
/* used to set pll input */
int (*set_pll_input)(u8* buf, int input);
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index a16eeba0020d..d313d7dcf386 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -33,7 +33,6 @@
struct nxt6000_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct nxt6000_config* config;
struct dvb_frontend frontend;
@@ -207,12 +206,6 @@ static void nxt6000_setup(struct dvb_frontend* fe)
nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
nxt6000_writereg(state, TS_FORMAT, 0);
-
- if (state->config->pll_init) {
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- state->config->pll_init(fe);
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
- }
}
static void nxt6000_dump_status(struct nxt6000_state *state)
@@ -469,9 +462,10 @@ static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
struct nxt6000_state* state = fe->demodulator_priv;
int result;
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- state->config->pll_set(fe, param);
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
return result;
@@ -532,6 +526,17 @@ static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron
return 0;
}
+static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct nxt6000_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);
+ } else {
+ return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);
+ }
+}
+
static struct dvb_frontend_ops nxt6000_ops;
struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
@@ -546,13 +551,12 @@ struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -584,6 +588,7 @@ static struct dvb_frontend_ops nxt6000_ops = {
.release = nxt6000_release,
.init = nxt6000_init,
+ .i2c_gate_ctrl = nxt6000_i2c_gate_ctrl,
.get_tune_settings = nxt6000_fe_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
index b7d9bead3002..117031d11708 100644
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ b/drivers/media/dvb/frontends/nxt6000.h
@@ -31,10 +31,6 @@ struct nxt6000_config
/* should clock inversion be used? */
u8 clock_inversion:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 80e0f28127b7..d20ab30c1e83 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -54,7 +54,6 @@ static int debug;
struct or51132_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct or51132_config* config;
@@ -106,9 +105,8 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
{
struct or51132_state* state = fe->demodulator_priv;
static u8 run_buf[] = {0x7F,0x01};
- static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
- u8 rec_buf[14];
- u8 cmd_buf[14];
+ u8 rec_buf[8];
+ u8 cmd_buf[3];
u32 firmwareAsize, firmwareBsize;
int i,ret;
@@ -157,7 +155,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x10;
cmd_buf[1] = 0x10;
cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,3))) {
@@ -167,8 +164,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x04;
cmd_buf[1] = 0x17;
- cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,2))) {
@@ -178,8 +173,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x00;
cmd_buf[1] = 0x00;
- cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,2))) {
@@ -189,7 +182,11 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
for(i=0;i<4;i++) {
msleep(20); /* 20ms */
- get_ver_buf[4] = i+1;
+ /* Once upon a time, this command might have had something
+ to do with getting the firmware version, but it's
+ not used anymore:
+ {0x04,0x00,0x30,0x00,i+1} */
+ /* Read 8 bytes, two bytes at a time */
if ((ret = i2c_readbytes(state,state->config->demod_address,
&rec_buf[i*2],2))) {
printk(KERN_WARNING
@@ -208,7 +205,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x10;
cmd_buf[1] = 0x00;
cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,3))) {
@@ -243,7 +239,7 @@ static int or51132_sleep(struct dvb_frontend* fe)
static int or51132_setmode(struct dvb_frontend* fe)
{
struct or51132_state* state = fe->demodulator_priv;
- unsigned char cmd_buf[4];
+ unsigned char cmd_buf[3];
dprintk("setmode %d\n",(int)state->current_modulation);
/* set operation mode in Receiver 1 register; */
@@ -263,7 +259,6 @@ static int or51132_setmode(struct dvb_frontend* fe)
default:
printk("setmode:Modulation set to unsupported value\n");
};
- cmd_buf[3] = 0x00;
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
printk(KERN_WARNING "or51132: set_mode error 1\n");
@@ -301,7 +296,6 @@ static int or51132_setmode(struct dvb_frontend* fe)
default:
printk("setmode: Modulation set to unsupported value\n");
};
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
@@ -313,52 +307,65 @@ static int or51132_setmode(struct dvb_frontend* fe)
return 0;
}
+/* Some modulations use the same firmware. This classifies modulations
+ by the firmware they use. */
+#define MOD_FWCLASS_UNKNOWN 0
+#define MOD_FWCLASS_VSB 1
+#define MOD_FWCLASS_QAM 2
+static int modulation_fw_class(fe_modulation_t modulation)
+{
+ switch(modulation) {
+ case VSB_8:
+ return MOD_FWCLASS_VSB;
+ case QAM_AUTO:
+ case QAM_64:
+ case QAM_256:
+ return MOD_FWCLASS_QAM;
+ default:
+ return MOD_FWCLASS_UNKNOWN;
+ }
+}
+
static int or51132_set_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
int ret;
- u8 buf[4];
struct or51132_state* state = fe->demodulator_priv;
const struct firmware *fw;
-
- /* Change only if we are actually changing the modulation */
- if (state->current_modulation != param->u.vsb.modulation) {
- switch(param->u.vsb.modulation) {
- case VSB_8:
+ const char *fwname;
+ int clock_mode;
+
+ /* Upload new firmware only if we need a different one */
+ if (modulation_fw_class(state->current_modulation) !=
+ modulation_fw_class(param->u.vsb.modulation)) {
+ switch(modulation_fw_class(param->u.vsb.modulation)) {
+ case MOD_FWCLASS_VSB:
dprintk("set_parameters VSB MODE\n");
- printk("or51132: Waiting for firmware upload(%s)...\n",
- OR51132_VSB_FIRMWARE);
- ret = request_firmware(&fw, OR51132_VSB_FIRMWARE,
- &state->i2c->dev);
- if (ret){
- printk(KERN_WARNING "or51132: No firmware up"
- "loaded(timeout or file not found?)\n");
- return ret;
- }
+ fwname = OR51132_VSB_FIRMWARE;
+
/* Set non-punctured clock for VSB */
- state->config->set_ts_params(fe, 0);
+ clock_mode = 0;
break;
- case QAM_AUTO:
- case QAM_64:
- case QAM_256:
+ case MOD_FWCLASS_QAM:
dprintk("set_parameters QAM MODE\n");
- printk("or51132: Waiting for firmware upload(%s)...\n",
- OR51132_QAM_FIRMWARE);
- ret = request_firmware(&fw, OR51132_QAM_FIRMWARE,
- &state->i2c->dev);
- if (ret){
- printk(KERN_WARNING "or51132: No firmware up"
- "loaded(timeout or file not found?)\n");
- return ret;
- }
+ fwname = OR51132_QAM_FIRMWARE;
+
/* Set punctured clock for QAM */
- state->config->set_ts_params(fe, 1);
+ clock_mode = 1;
break;
default:
- printk("or51132:Modulation type(%d) UNSUPPORTED\n",
+ printk("or51132: Modulation type(%d) UNSUPPORTED\n",
param->u.vsb.modulation);
return -1;
- };
+ }
+ printk("or51132: Waiting for firmware upload(%s)...\n",
+ fwname);
+ ret = request_firmware(&fw, fwname, &state->i2c->dev);
+ if (ret) {
+ printk(KERN_WARNING "or51132: No firmware up"
+ "loaded(timeout or file not found?)\n");
+ return ret;
+ }
ret = or51132_load_firmware(fe, fw);
release_firmware(fw);
if (ret) {
@@ -367,18 +374,18 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
return ret;
}
printk("or51132: Firmware upload complete.\n");
-
+ state->config->set_ts_params(fe, clock_mode);
+ }
+ /* Change only if we are actually changing the modulation */
+ if (state->current_modulation != param->u.vsb.modulation) {
state->current_modulation = param->u.vsb.modulation;
or51132_setmode(fe);
}
- dvb_pll_configure(state->config->pll_desc, buf,
- param->frequency, 0);
- dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
- "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
- if (i2c_writebytes(state, state->config->pll_address ,buf, 4))
- printk(KERN_WARNING "or51132: set_parameters error "
- "writing to tuner\n");
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* Set to current mode */
or51132_setmode(fe);
@@ -388,6 +395,44 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
return 0;
}
+static int or51132_get_parameters(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct or51132_state* state = fe->demodulator_priv;
+ u8 buf[2];
+
+ /* Receiver Status */
+ buf[0]=0x04;
+ buf[1]=0x00;
+ msleep(30); /* 30ms */
+ if (i2c_writebytes(state,state->config->demod_address,buf,2)) {
+ printk(KERN_WARNING "or51132: get_parameters write error\n");
+ return -EREMOTEIO;
+ }
+ msleep(30); /* 30ms */
+ if (i2c_readbytes(state,state->config->demod_address,buf,2)) {
+ printk(KERN_WARNING "or51132: get_parameters read error\n");
+ return -EREMOTEIO;
+ }
+ switch(buf[0]) {
+ case 0x06: param->u.vsb.modulation = VSB_8; break;
+ case 0x43: param->u.vsb.modulation = QAM_64; break;
+ case 0x45: param->u.vsb.modulation = QAM_256; break;
+ default:
+ printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+ buf[0]);
+ return -EREMOTEIO;
+ }
+
+ /* FIXME: Read frequency from frontend, take AFC into account */
+ param->frequency = state->current_frequency;
+
+ /* FIXME: How to read inversion setting? Receiver 6 register? */
+ param->inversion = INVERSION_AUTO;
+
+ return 0;
+}
+
static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct or51132_state* state = fe->demodulator_priv;
@@ -572,12 +617,11 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
state->current_frequency = -1;
state->current_modulation = -1;
/* Create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -590,7 +634,7 @@ static struct dvb_frontend_ops or51132_ops = {
.info = {
.name = "Oren OR51132 VSB/QAM Frontend",
- .type = FE_ATSC,
+ .type = FE_ATSC,
.frequency_min = 44000000,
.frequency_max = 958000000,
.frequency_stepsize = 166666,
@@ -606,6 +650,7 @@ static struct dvb_frontend_ops or51132_ops = {
.sleep = or51132_sleep,
.set_frontend = or51132_set_parameters,
+ .get_frontend = or51132_get_parameters,
.get_tune_settings = or51132_get_tune_settings,
.read_status = or51132_read_status,
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
index 622cdd18381b..89658883abf5 100644
--- a/drivers/media/dvb/frontends/or51132.h
+++ b/drivers/media/dvb/frontends/or51132.h
@@ -29,8 +29,6 @@ struct or51132_config
{
/* The demodulator's i2c address */
u8 demod_address;
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 7c3aed1f546b..26bed616fabe 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -54,7 +54,6 @@ static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
struct or51211_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct or51211_config* config;
@@ -585,12 +584,11 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
state->initialized = 0;
state->current_frequency = 0;
/* Create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index d69477596921..2c2c344c4c64 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -38,7 +38,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
struct s5h1420_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct s5h1420_config* config;
struct dvb_frontend frontend;
@@ -584,7 +583,6 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
struct s5h1420_state* state = fe->demodulator_priv;
int frequency_delta;
struct dvb_frontend_tune_settings fesettings;
- u32 tmp;
/* check if we should do a fast-tune */
memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
@@ -596,10 +594,17 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
(state->fec_inner == p->u.qpsk.fec_inner) &&
(state->symbol_rate == p->u.qpsk.symbol_rate)) {
- if (state->config->pll_set) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_set(fe, p, &tmp);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.tuner_ops.get_frequency) {
+ u32 tmp;
+ fe->ops.tuner_ops.get_frequency(fe, &tmp);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, p->frequency - tmp);
+ } else {
+ s5h1420_setfreqoffset(state, 0);
}
return 0;
}
@@ -646,9 +651,9 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
/* set tuner PLL */
- if (state->config->pll_set) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_set(fe, p, &tmp);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, 0);
}
@@ -708,6 +713,17 @@ static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
return 0;
}
+static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+ } else {
+ return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+ }
+}
+
static int s5h1420_init (struct dvb_frontend* fe)
{
struct s5h1420_state* state = fe->demodulator_priv;
@@ -717,13 +733,6 @@ static int s5h1420_init (struct dvb_frontend* fe)
msleep(10);
s5h1420_reset(state);
- /* init PLL */
- if (state->config->pll_init) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_init(fe);
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
- }
-
return 0;
}
@@ -756,7 +765,6 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->postlocked = 0;
state->fclk = 88000000;
state->tunedfreq = 0;
@@ -769,7 +777,7 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -800,6 +808,7 @@ static struct dvb_frontend_ops s5h1420_ops = {
.init = s5h1420_init,
.sleep = s5h1420_sleep,
+ .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
.set_frontend = s5h1420_set_frontend,
.get_frontend = s5h1420_get_frontend,
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 73296f13c324..4e39015fa67e 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -32,10 +32,6 @@ struct s5h1420_config
/* does the inversion require inversion? */
u8 invert:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
};
extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index 73829e647e50..44ec5b9a4695 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -44,8 +44,6 @@ struct sp8870_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct sp8870_config* config;
struct dvb_frontend frontend;
@@ -262,9 +260,10 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
sp8870_microcontroller_stop(state);
// set tuner parameters
- sp8870_writereg(state, 0x206, 0x001);
- state->config->pll_set(fe, p);
- sp8870_writereg(state, 0x206, 0x000);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
// sample rate correction bit [23..17]
sp8870_writereg(state, 0x0319, 0x000A);
@@ -349,13 +348,6 @@ static int sp8870_init (struct dvb_frontend* fe)
sp8870_writereg(state, 0x0D00, 0x010);
sp8870_writereg(state, 0x0D01, 0x000);
- /* setup PLL */
- if (state->config->pll_init) {
- sp8870_writereg(state, 0x206, 0x001);
- state->config->pll_init(fe);
- sp8870_writereg(state, 0x206, 0x000);
- }
-
return 0;
}
@@ -541,6 +533,17 @@ static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend
return 0;
}
+static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct sp8870_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return sp8870_writereg(state, 0x206, 0x001);
+ } else {
+ return sp8870_writereg(state, 0x206, 0x000);
+ }
+}
+
static void sp8870_release(struct dvb_frontend* fe)
{
struct sp8870_state* state = fe->demodulator_priv;
@@ -561,14 +564,13 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* check if the demod is there */
if (sp8870_readreg(state, 0x0200) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -597,6 +599,7 @@ static struct dvb_frontend_ops sp8870_ops = {
.init = sp8870_init,
.sleep = sp8870_sleep,
+ .i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
.set_frontend = sp8870_set_frontend,
.get_tune_settings = sp8870_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
index f3b555dbc960..93afbb969d6b 100644
--- a/drivers/media/dvb/frontends/sp8870.h
+++ b/drivers/media/dvb/frontends/sp8870.h
@@ -31,10 +31,6 @@ struct sp8870_config
/* the demodulator's i2c address */
u8 demod_address;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index eb8a602198ca..b0a2b02f6608 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -24,7 +24,6 @@
struct sp887x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct sp887x_config* config;
struct dvb_frontend frontend;
@@ -208,15 +207,6 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
/* bit 0x010: enable data valid signal */
sp887x_writereg(state, 0xd00, 0x010);
sp887x_writereg(state, 0x0d1, 0x000);
-
- /* setup the PLL */
- if (state->config->pll_init) {
- sp887x_writereg(state, 0x206, 0x001);
- state->config->pll_init(fe);
- sp887x_writereg(state, 0x206, 0x000);
- }
-
- printk ("done.\n");
return 0;
};
@@ -362,9 +352,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
sp887x_microcontroller_stop(state);
/* setup the PLL */
- sp887x_writereg(state, 0x206, 0x001);
- actual_freq = state->config->pll_set(fe, p);
- sp887x_writereg(state, 0x206, 0x000);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.tuner_ops.get_frequency) {
+ fe->ops.tuner_ops.get_frequency(fe, &actual_freq);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ } else {
+ actual_freq = p->frequency;
+ }
/* read status reg in order to clear <pending irqs */
sp887x_readreg(state, 0x200);
@@ -486,6 +483,17 @@ static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
+static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct sp887x_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return sp887x_writereg(state, 0x206, 0x001);
+ } else {
+ return sp887x_writereg(state, 0x206, 0x000);
+ }
+}
+
static int sp887x_sleep(struct dvb_frontend* fe)
{
struct sp887x_state* state = fe->demodulator_priv;
@@ -555,14 +563,13 @@ struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* check if the demod is there */
if (sp887x_readreg(state, 0x0200) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -589,6 +596,7 @@ static struct dvb_frontend_ops sp887x_ops = {
.init = sp887x_init,
.sleep = sp887x_sleep,
+ .i2c_gate_ctrl = sp887x_i2c_gate_ctrl,
.set_frontend = sp887x_setup_frontend_parameters,
.get_tune_settings = sp887x_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
index 6a05d8f8e8cc..c44b0ebdf1e2 100644
--- a/drivers/media/dvb/frontends/sp887x.h
+++ b/drivers/media/dvb/frontends/sp887x.h
@@ -13,12 +13,6 @@ struct sp887x_config
/* the demodulator's i2c address */
u8 demod_address;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
-
- /* this should return the actual frequency tuned to */
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index eb15676d374f..1ca64249010c 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -32,7 +32,6 @@
struct stv0297_state {
struct i2c_adapter *i2c;
- struct dvb_frontend_ops ops;
const struct stv0297_config *config;
struct dvb_frontend frontend;
@@ -68,19 +67,25 @@ static int stv0297_readreg(struct stv0297_state *state, u8 reg)
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
- struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len =
- 1},
- {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
- };
+ struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
+ {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+ };
// this device needs a STOP between the register and data
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
+ if (state->config->stop_during_read) {
+ if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
+ if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
+ } else {
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
}
return b1[0];
@@ -107,13 +112,20 @@ static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len
};
// this device needs a STOP between the register and data
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
+ if (state->config->stop_during_read) {
+ if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
+ if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
+ } else {
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
}
return 0;
@@ -276,12 +288,14 @@ static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_invers
return 0;
}
-int stv0297_enable_plli2c(struct dvb_frontend *fe)
+static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct stv0297_state *state = fe->demodulator_priv;
- stv0297_writereg(state, 0x87, 0x78);
- stv0297_writereg(state, 0x86, 0xc8);
+ if (enable) {
+ stv0297_writereg(state, 0x87, 0x78);
+ stv0297_writereg(state, 0x86, 0xc8);
+ }
return 0;
}
@@ -296,9 +310,6 @@ static int stv0297_init(struct dvb_frontend *fe)
stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
msleep(200);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
return 0;
}
@@ -389,7 +400,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
case QAM_32:
case QAM_64:
delay = 100;
- sweeprate = 1500;
+ sweeprate = 1000;
break;
case QAM_128:
@@ -421,7 +432,10 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
}
stv0297_init(fe);
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* clear software interrupts */
stv0297_writereg(state, 0x82, 0x0);
@@ -634,7 +648,6 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
state->base_freq = 0;
/* check if the demod is there */
@@ -642,7 +655,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -668,6 +681,7 @@ static struct dvb_frontend_ops stv0297_ops = {
.init = stv0297_init,
.sleep = stv0297_sleep,
+ .i2c_gate_ctrl = stv0297_i2c_gate_ctrl,
.set_frontend = stv0297_set_frontend,
.get_frontend = stv0297_get_frontend,
@@ -684,4 +698,3 @@ MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(stv0297_attach);
-EXPORT_SYMBOL(stv0297_enable_plli2c);
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
index 9e53f019db71..1da5384fb985 100644
--- a/drivers/media/dvb/frontends/stv0297.h
+++ b/drivers/media/dvb/frontends/stv0297.h
@@ -38,13 +38,11 @@ struct stv0297_config
/* does the "inversion" need inverted? */
u8 invert:1;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ /* set to 1 if the device requires an i2c STOP during reading */
+ u8 stop_during_read:1;
};
extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
struct i2c_adapter* i2c);
-extern int stv0297_enable_plli2c(struct dvb_frontend* fe);
#endif // STV0297_H
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 5bcd00f792e6..96648a75440d 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -56,7 +56,6 @@
struct stv0299_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct stv0299_config* config;
struct dvb_frontend frontend;
@@ -131,13 +130,6 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
return ret == 2 ? 0 : ret;
}
-int stv0299_enable_plli2c (struct dvb_frontend* fe)
-{
- struct stv0299_state* state = fe->demodulator_priv;
-
- return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
-}
-
static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
@@ -457,12 +449,6 @@ static int stv0299_init (struct dvb_frontend* fe)
for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
- if (state->config->pll_init) {
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_init(fe, state->i2c);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
- }
-
return 0;
}
@@ -560,9 +546,10 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
if (state->config->invert) invval = (~invval) & 1;
stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_set(fe, state->i2c, p);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
stv0299_set_FEC (state, p->u.qpsk.fec_inner);
stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
@@ -611,6 +598,19 @@ static int stv0299_sleep(struct dvb_frontend* fe)
return 0;
}
+static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct stv0299_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ stv0299_writeregI(state, 0x05, 0xb5);
+ } else {
+ stv0299_writeregI(state, 0x05, 0x35);
+ }
+ udelay(1);
+ return 0;
+}
+
static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
struct stv0299_state* state = fe->demodulator_priv;
@@ -647,7 +647,6 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
state->tuner_frequency = 0;
state->symbol_rate = 0;
@@ -664,7 +663,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
if (id != 0xa1 && id != 0x80) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -695,6 +694,7 @@ static struct dvb_frontend_ops stv0299_ops = {
.init = stv0299_init,
.sleep = stv0299_sleep,
+ .i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
.set_frontend = stv0299_set_frontend,
.get_frontend = stv0299_get_frontend,
@@ -721,9 +721,8 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
- "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
+ "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(stv0299_enable_plli2c);
EXPORT_SYMBOL(stv0299_writereg);
EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 32c87b4c2f13..1504828e4232 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -87,14 +87,9 @@ struct stv0299_config
/* Set the symbol rate */
int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c);
- int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params);
};
extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
-extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 21255cac9793..e83ff2104c9b 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -36,7 +36,6 @@
struct tda10021_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct tda10021_config* config;
struct dvb_frontend frontend;
@@ -90,6 +89,14 @@ static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
+int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ return tda10021_writereg(state, reg, data);
+}
+EXPORT_SYMBOL(tda10021_write_byte);
+
static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
{
u8 b0 [] = { reg };
@@ -225,13 +232,6 @@ static int tda10021_init (struct dvb_frontend *fe)
//Activate PLL
tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
-
- if (state->config->pll_init) {
- lock_tuner(state);
- state->config->pll_init(fe);
- unlock_tuner(state);
- }
-
return 0;
}
@@ -259,9 +259,10 @@ static int tda10021_set_parameters (struct dvb_frontend *fe,
//printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
- lock_tuner(state);
- state->config->pll_set(fe, p);
- unlock_tuner(state);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
tda10021_writereg (state, 0x34, state->pwm);
@@ -376,6 +377,18 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
return 0;
}
+static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ lock_tuner(state);
+ } else {
+ unlock_tuner(state);
+ }
+ return 0;
+}
+
static int tda10021_sleep(struct dvb_frontend* fe)
{
struct tda10021_state* state = fe->demodulator_priv;
@@ -407,7 +420,6 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
state->pwm = pwm;
state->reg0 = tda10021_inittab[0];
@@ -415,7 +427,7 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -448,6 +460,7 @@ static struct dvb_frontend_ops tda10021_ops = {
.init = tda10021_init,
.sleep = tda10021_sleep,
+ .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
.set_frontend = tda10021_set_parameters,
.get_frontend = tda10021_get_frontend,
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
index 53be939e8c55..b1df4259bee9 100644
--- a/drivers/media/dvb/frontends/tda10021.h
+++ b/drivers/media/dvb/frontends/tda10021.h
@@ -30,13 +30,11 @@ struct tda10021_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
struct i2c_adapter* i2c, u8 pwm);
+extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
+
#endif // TDA10021_H
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index b83dafa4e12c..59a2ed614fca 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -47,7 +47,6 @@ enum tda1004x_demod {
struct tda1004x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct tda1004x_config* config;
struct dvb_frontend frontend;
@@ -600,13 +599,6 @@ static int tda10045_init(struct dvb_frontend* fe)
tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
- // Init the PLL
- if (state->config->pll_init) {
- tda1004x_enable_tuner_i2c(state);
- state->config->pll_init(fe);
- tda1004x_disable_tuner_i2c(state);
- }
-
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
@@ -635,16 +627,6 @@ static int tda10046_init(struct dvb_frontend* fe)
return -EIO;
}
- // Init the tuner PLL
- if (state->config->pll_init) {
- tda1004x_enable_tuner_i2c(state);
- if (state->config->pll_init(fe)) {
- printk(KERN_ERR "tda1004x: pll init failed\n");
- return -EIO;
- }
- tda1004x_disable_tuner_i2c(state);
- }
-
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream
@@ -712,12 +694,10 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
}
// set frequency
- tda1004x_enable_tuner_i2c(state);
- if (state->config->pll_set(fe, fe_params)) {
- printk(KERN_ERR "tda1004x: pll set failed\n");
- return -EIO;
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fe_params);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- tda1004x_disable_tuner_i2c(state);
// Hardcoded to use auto as much as possible on the TDA10045 as it
// is very unreliable if AUTO mode is _not_ used.
@@ -1183,16 +1163,6 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
break;
case TDA1004X_DEMOD_TDA10046:
- if (state->config->pll_sleep != NULL) {
- tda1004x_enable_tuner_i2c(state);
- state->config->pll_sleep(fe);
- if (state->config->if_freq != TDA10046_FREQ_052) {
- /* special hack for Philips EUROPA Based boards:
- * keep the I2c bridge open for tuner access in analog mode
- */
- tda1004x_disable_tuner_i2c(state);
- }
- }
/* set outputs to tristate */
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
@@ -1202,6 +1172,17 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
return 0;
}
+static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda1004x_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return tda1004x_enable_tuner_i2c(state);
+ } else {
+ return tda1004x_disable_tuner_i2c(state);
+ }
+}
+
static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 800;
@@ -1235,6 +1216,7 @@ static struct dvb_frontend_ops tda10045_ops = {
.init = tda10045_init,
.sleep = tda1004x_sleep,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
.get_frontend = tda1004x_get_fe,
@@ -1260,7 +1242,6 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
state->demod_type = TDA1004X_DEMOD_TDA10045;
/* check if the demod is there */
@@ -1270,7 +1251,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
@@ -1293,6 +1274,7 @@ static struct dvb_frontend_ops tda10046_ops = {
.init = tda10046_init,
.sleep = tda1004x_sleep,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
.get_frontend = tda1004x_get_fe,
@@ -1318,7 +1300,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->demod_type = TDA1004X_DEMOD_TDA10046;
/* check if the demod is there */
@@ -1328,7 +1309,7 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index cc0c4af64067..b877b23ed734 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -66,11 +66,6 @@ struct tda1004x_config
/* AGC configuration */
enum tda10046_agc agc_config;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- void (*pll_sleep)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
/* set this to NULL if the card has a firmware EEPROM */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 91baa9cedd79..3aa45ebbac3d 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -37,7 +37,6 @@
struct tda8083_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct tda8083_config* config;
struct dvb_frontend frontend;
@@ -293,7 +292,11 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct tda8083_state* state = fe->demodulator_priv;
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
tda8083_set_inversion (state, p->inversion);
tda8083_set_fec (state, p->u.qpsk.fec_inner);
tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -334,8 +337,6 @@ static int tda8083_init(struct dvb_frontend* fe)
for (i=0; i<44; i++)
tda8083_writereg (state, i, tda8083_init_tab[i]);
- if (state->config->pll_init) state->config->pll_init(fe);
-
tda8083_writereg (state, 0x00, 0x3c);
tda8083_writereg (state, 0x00, 0x04);
@@ -395,13 +396,12 @@ struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
index 466663307bf1..e7a48f61ea2c 100644
--- a/drivers/media/dvb/frontends/tda8083.h
+++ b/drivers/media/dvb/frontends/tda8083.h
@@ -33,10 +33,6 @@ struct tda8083_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index ad8647a3c85e..6bffe85c161c 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -35,7 +35,6 @@
struct ves1820_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct ves1820_config* config;
struct dvb_frontend frontend;
@@ -204,9 +203,6 @@ static int ves1820_init(struct dvb_frontend* fe)
ves1820_writereg(state, 0x34, state->pwm);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
return 0;
}
@@ -223,7 +219,11 @@ static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_p
if (real_qam < 0 || real_qam > 4)
return -EINVAL;
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
ves1820_writereg(state, 0x34, state->pwm);
@@ -380,7 +380,6 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
goto error;
/* setup the state */
- memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
state->reg0 = ves1820_inittab[0];
state->config = config;
state->i2c = i2c;
@@ -393,12 +392,12 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
if (verbose)
printk("ves1820: pwm=0x%02x\n", state->pwm);
- state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
- state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
+ state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
state->frontend.demodulator_priv = state;
+
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
index 355f130b1be8..520f09522fbb 100644
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb/frontends/ves1820.h
@@ -39,10 +39,6 @@ struct ves1820_config
/* SELAGC control */
u8 selagc:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 821df8e839d0..54d7b07571b8 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -36,7 +36,6 @@
struct ves1x93_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct ves1x93_config* config;
struct dvb_frontend frontend;
@@ -278,12 +277,6 @@ static int ves1x93_init (struct dvb_frontend* fe)
}
}
- if (state->config->pll_init) {
- ves1x93_writereg(state, 0x00, 0x11);
- state->config->pll_init(fe);
- ves1x93_writereg(state, 0x00, 0x01);
- }
-
return 0;
}
@@ -395,9 +388,10 @@ static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct ves1x93_state* state = fe->demodulator_priv;
- ves1x93_writereg(state, 0x00, 0x11);
- state->config->pll_set(fe, p);
- ves1x93_writereg(state, 0x00, 0x01);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
ves1x93_set_inversion (state, p->inversion);
ves1x93_set_fec (state, p->u.qpsk.fec_inner);
ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -442,6 +436,17 @@ static void ves1x93_release(struct dvb_frontend* fe)
kfree(state);
}
+static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct ves1x93_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return ves1x93_writereg(state, 0x00, 0x11);
+ } else {
+ return ves1x93_writereg(state, 0x00, 0x01);
+ }
+}
+
static struct dvb_frontend_ops ves1x93_ops;
struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
@@ -457,7 +462,6 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
state->inversion = INVERSION_OFF;
/* check if the demod is there + identify it */
@@ -492,7 +496,7 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -523,6 +527,7 @@ static struct dvb_frontend_ops ves1x93_ops = {
.init = ves1x93_init,
.sleep = ves1x93_sleep,
+ .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
.set_frontend = ves1x93_set_frontend,
.get_frontend = ves1x93_get_frontend,
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
index 1627e37c57a4..ba88ae0855c9 100644
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ b/drivers/media/dvb/frontends/ves1x93.h
@@ -38,10 +38,6 @@ struct ves1x93_config
/* should PWM be inverted? */
u8 invert_pwm:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index d7d9f59d76d2..2b95e8b6cd39 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -34,7 +34,6 @@
struct zl10353_state {
struct i2c_adapter *i2c;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
struct zl10353_config config;
};
@@ -126,6 +125,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
struct dvb_frontend_parameters *param)
{
struct zl10353_state *state = fe->demodulator_priv;
+
u8 pllbuf[6] = { 0x67 };
/* These settings set "auto-everything" and start the FSM. */
@@ -142,7 +142,30 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
zl10353_single_write(fe, 0x66, 0xE9);
zl10353_single_write(fe, 0x62, 0x0A);
- state->config.pll_set(fe, param, pllbuf + 1);
+ // if there is no attached secondary tuner, we call set_params to program
+ // a potential tuner attached somewhere else
+ if (state->config.no_tuner) {
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ }
+
+ // if pllbuf is defined, retrieve the settings
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
+ pllbuf[1] <<= 1;
+ } else {
+ // fake pllbuf settings
+ pllbuf[1] = 0x61 << 1;
+ pllbuf[2] = 0;
+ pllbuf[3] = 0;
+ pllbuf[3] = 0;
+ pllbuf[4] = 0;
+ }
+
+ // there is no call to _just_ start decoding, so we send the pllbuf anyway
+ // even if there isn't a PLL attached to the secondary bus
zl10353_write(fe, pllbuf, sizeof(pllbuf));
zl10353_single_write(fe, 0x70, 0x01);
@@ -254,14 +277,13 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config, config, sizeof(struct zl10353_config));
- memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 5cc4ae718d8c..9770cb840cfc 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -29,10 +29,8 @@ struct zl10353_config
/* demodulator's I2C address */
u8 demod_address;
- /* function which configures the PLL buffer (for secondary I2C
- * connected tuner) or tunes the PLL (for direct connected tuner) */
- int (*pll_set)(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params, u8 *pllbuf);
+ /* set if no pll is connected to the secondary i2c bus */
+ int no_tuner;
};
extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,