提交 cd20ca9f 编写于 作者: A Andrew de Quincey 提交者: Mauro Carvalho Chehab

V4L/DVB (4012): Fix cx24123 diseqc

Rework diseqc support to be more in line with the other demod drivers.
Fix Nova-S-Plus/Nova-SE2 diseqc.
Cleanup API.
Signed-off-by: NAndrew de Quincey <adq_dvb@lidskialf.net>
Signed-off-by: NMauro Carvalho Chehab <mchehab@infradead.org>
上级 9a10655f
...@@ -48,7 +48,6 @@ struct cx24123_state ...@@ -48,7 +48,6 @@ struct cx24123_state
u32 lastber; u32 lastber;
u16 snr; u16 snr;
u8 lnbreg;
/* Some PLL specifics for tuning */ /* Some PLL specifics for tuning */
u32 VCAarg; u32 VCAarg;
...@@ -249,29 +248,6 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data) ...@@ -249,29 +248,6 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
return 0; 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) static int cx24123_readreg(struct cx24123_state* state, u8 reg)
{ {
int ret; int ret;
...@@ -295,11 +271,6 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg) ...@@ -295,11 +271,6 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg)
return b1[0]; 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) static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
{ {
u8 nom_reg = cx24123_readreg(state, 0x0e); u8 nom_reg = cx24123_readreg(state, 0x0e);
...@@ -687,10 +658,6 @@ static int cx24123_initfe(struct dvb_frontend* fe) ...@@ -687,10 +658,6 @@ static int cx24123_initfe(struct dvb_frontend* fe)
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++) for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data); cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
/* Configure the LNB for 14V */
if (state->config->use_isl6421)
cx24123_writelnbreg(state, 0x0, 0x2a);
return 0; return 0;
} }
...@@ -699,50 +666,18 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage ...@@ -699,50 +666,18 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
struct cx24123_state *state = fe->demodulator_priv; struct cx24123_state *state = fe->demodulator_priv;
u8 val; u8 val;
switch (state->config->use_isl6421) { val = cx24123_readreg(state, 0x29) & ~0x40;
case 1:
val = cx24123_readlnbreg(state, 0x0); switch (voltage) {
case SEC_VOLTAGE_13:
switch (voltage) { dprintk("%s: setting voltage 13V\n", __FUNCTION__);
case SEC_VOLTAGE_13: return cx24123_writereg(state, 0x29, val | 0x80);
dprintk("%s: isl6421 voltage = 13V\n",__FUNCTION__); case SEC_VOLTAGE_18:
return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */ dprintk("%s: setting voltage 18V\n", __FUNCTION__);
case SEC_VOLTAGE_18: return cx24123_writereg(state, 0x29, val & 0x7f);
dprintk("%s: isl6421 voltage = 18V\n",__FUNCTION__); default:
return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */ return -EINVAL;
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;
};
}
return 0; return 0;
} }
...@@ -763,27 +698,20 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state) ...@@ -763,27 +698,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) static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
{ {
struct cx24123_state *state = fe->demodulator_priv; struct cx24123_state *state = fe->demodulator_priv;
int i, val; int i, val, tone;
dprintk("%s:\n",__FUNCTION__); dprintk("%s:\n",__FUNCTION__);
/* check if continuous tone has been stopped */ /* stop continuous tone if enabled */
if (state->config->use_isl6421) tone = cx24123_readreg(state, 0x29);
val = cx24123_readlnbreg(state, 0x00) & 0x10; if (tone & 0x10)
else cx24123_writereg(state, 0x29, tone & ~0x50);
val = cx24123_readreg(state, 0x29) & 0x10;
if (val) {
printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
return -ENOTSUPP;
}
/* wait for diseqc queue ready */ /* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state); cx24123_wait_for_diseqc(state);
/* select tone mode */ /* 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++) for (i = 0; i < cmd->msg_len; i++)
cx24123_writereg(state, 0x2C + i, cmd->msg[i]); cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
...@@ -794,36 +722,33 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma ...@@ -794,36 +722,33 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
/* wait for diseqc message to finish sending */ /* wait for diseqc message to finish sending */
cx24123_wait_for_diseqc(state); cx24123_wait_for_diseqc(state);
/* restart continuous tone if enabled */
if (tone & 0x10) {
cx24123_writereg(state, 0x29, tone & ~0x40);
}
return 0; return 0;
} }
static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
{ {
struct cx24123_state *state = fe->demodulator_priv; struct cx24123_state *state = fe->demodulator_priv;
int val; int val, tone;
dprintk("%s:\n", __FUNCTION__); dprintk("%s:\n", __FUNCTION__);
/* check if continuous tone has been stoped */ /* stop continuous tone if enabled */
if (state->config->use_isl6421) tone = cx24123_readreg(state, 0x29);
val = cx24123_readlnbreg(state, 0x00) & 0x10; if (tone & 0x10)
else cx24123_writereg(state, 0x29, tone & ~0x50);
val = cx24123_readreg(state, 0x29) & 0x10;
if (val) {
printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
return -ENOTSUPP;
}
/* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state); cx24123_wait_for_diseqc(state);
/* select tone mode */ /* select tone mode */
val = cx24123_readreg(state, 0x2a) & 0xf8; cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
cx24123_writereg(state, 0x2a, val | 0x04); msleep(30);
val = cx24123_readreg(state, 0x29); val = cx24123_readreg(state, 0x29);
if (burst == SEC_MINI_A) if (burst == SEC_MINI_A)
cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00)); cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
else if (burst == SEC_MINI_B) else if (burst == SEC_MINI_B)
...@@ -832,7 +757,12 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t ...@@ -832,7 +757,12 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
return -EINVAL; return -EINVAL;
cx24123_wait_for_diseqc(state); 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; return 0;
} }
...@@ -973,38 +903,21 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) ...@@ -973,38 +903,21 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
struct cx24123_state *state = fe->demodulator_priv; struct cx24123_state *state = fe->demodulator_priv;
u8 val; u8 val;
switch (state->config->use_isl6421) { /* wait for diseqc queue ready */
case 1: cx24123_wait_for_diseqc(state);
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:
val = cx24123_readreg(state, 0x29); val = cx24123_readreg(state, 0x29) & ~0x40;
switch (tone) { switch (tone) {
case SEC_TONE_ON: case SEC_TONE_ON:
dprintk("%s: setting tone on\n", __FUNCTION__); dprintk("%s: setting tone on\n", __FUNCTION__);
return cx24123_writereg(state, 0x29, val | 0x10); return cx24123_writereg(state, 0x29, val | 0x10);
case SEC_TONE_OFF: case SEC_TONE_OFF:
dprintk("%s: setting tone off\n",__FUNCTION__); dprintk("%s: setting tone off\n",__FUNCTION__);
return cx24123_writereg(state, 0x29, val & 0xef); return cx24123_writereg(state, 0x29, val & 0xef);
default: default:
printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
return -EINVAL; return -EINVAL;
}
} }
return 0; return 0;
...@@ -1040,7 +953,6 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, ...@@ -1040,7 +953,6 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops)); memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0; state->lastber = 0;
state->snr = 0; state->snr = 0;
state->lnbreg = 0;
state->VCAarg = 0; state->VCAarg = 0;
state->VGAarg = 0; state->VGAarg = 0;
state->bandselectarg = 0; state->bandselectarg = 0;
......
...@@ -28,17 +28,8 @@ struct cx24123_config ...@@ -28,17 +28,8 @@ struct cx24123_config
/* the demodulator's i2c address */ /* the demodulator's i2c address */
u8 demod_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;
/* Need to set device param for start_dma */ /* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); 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, extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
......
...@@ -61,6 +61,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS ...@@ -61,6 +61,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
select DVB_LGDT330X select DVB_LGDT330X
select DVB_NXT200X select DVB_NXT200X
select DVB_CX24123 select DVB_CX24123
select DVB_ISL6421
---help--- ---help---
This builds cx88-dvb with all currently supported frontend This builds cx88-dvb with all currently supported frontend
demodulators. If you wish to tweak your configuration, and demodulators. If you wish to tweak your configuration, and
...@@ -139,6 +140,7 @@ config VIDEO_CX88_DVB_CX24123 ...@@ -139,6 +140,7 @@ config VIDEO_CX88_DVB_CX24123
default y default y
depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
select DVB_CX24123 select DVB_CX24123
select DVB_ISL6421
---help--- ---help---
This adds DVB-S support for cards based on the This adds DVB-S support for cards based on the
Connexant 2388x chip and the CX24123 demodulator. Connexant 2388x chip and the CX24123 demodulator.
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#ifdef HAVE_CX24123 #ifdef HAVE_CX24123
# include "cx24123.h" # include "cx24123.h"
#endif #endif
#include "isl6421.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
...@@ -479,28 +480,30 @@ static int cx24123_set_ts_param(struct dvb_frontend* fe, ...@@ -479,28 +480,30 @@ static int cx24123_set_ts_param(struct dvb_frontend* fe,
return 0; return 0;
} }
static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on) static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{ {
struct cx8802_dev *dev= fe->dvb->priv; struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core; struct cx88_core *core = dev->core;
if (on) if (voltage == SEC_VOLTAGE_OFF) {
cx_write(MO_GP0_IO, 0x000006f9);
else
cx_write(MO_GP0_IO, 0x000006fB); cx_write(MO_GP0_IO, 0x000006fB);
} else {
cx_write(MO_GP0_IO, 0x000006f9);
}
if (core->prev_set_voltage)
return core->prev_set_voltage(fe, voltage);
return 0;
} }
static struct cx24123_config hauppauge_novas_config = { static struct cx24123_config hauppauge_novas_config = {
.demod_address = 0x55, .demod_address = 0x55,
.use_isl6421 = 1,
.set_ts_params = cx24123_set_ts_param, .set_ts_params = cx24123_set_ts_param,
}; };
static struct cx24123_config kworld_dvbs_100_config = { static struct cx24123_config kworld_dvbs_100_config = {
.demod_address = 0x15, .demod_address = 0x15,
.use_isl6421 = 0,
.set_ts_params = cx24123_set_ts_param, .set_ts_params = cx24123_set_ts_param,
.enable_lnb_voltage = cx24123_enable_lnb_voltage,
}; };
#endif #endif
...@@ -710,10 +713,17 @@ static int dvb_register(struct cx8802_dev *dev) ...@@ -710,10 +713,17 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config, dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
&dev->core->i2c_adap); &dev->core->i2c_adap);
if (dev->dvb.frontend) {
isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap, 0x08, 0x00, 0x00);
}
break; break;
case CX88_BOARD_KWORLD_DVBS_100: case CX88_BOARD_KWORLD_DVBS_100:
dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config, dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
&dev->core->i2c_adap); &dev->core->i2c_adap);
if (dev->dvb.frontend) {
dev->core->prev_set_voltage = dev->dvb.frontend->ops->set_voltage;
dev->dvb.frontend->ops->set_voltage = kworld_dvbs_100_set_voltage;
}
break; break;
#endif #endif
default: default:
......
...@@ -298,6 +298,7 @@ struct cx88_core { ...@@ -298,6 +298,7 @@ struct cx88_core {
/* config info -- dvb */ /* config info -- dvb */
struct dvb_pll_desc *pll_desc; struct dvb_pll_desc *pll_desc;
unsigned int pll_addr; unsigned int pll_addr;
int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
/* state info */ /* state info */
struct task_struct *kthread; struct task_struct *kthread;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册