summaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/frontends/ds3000.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-24 09:50:13 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-24 09:50:13 -0700
commit76d21c563569bcea6bc67d65cc2c460cff643058 (patch)
tree4dd2c9846ea7838077099646418978e354df1680 /drivers/media/dvb/frontends/ds3000.c
parent6e50e9f9f4a8277b4d76de417ca77cf3921bd524 (diff)
parent472af2b05bdefcaee7e754e22cbf131110017ad6 (diff)
downloadlinux-76d21c563569bcea6bc67d65cc2c460cff643058.tar.gz
linux-76d21c563569bcea6bc67d65cc2c460cff643058.tar.bz2
linux-76d21c563569bcea6bc67d65cc2c460cff643058.zip
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (442 commits) [media] videobuf2-dma-contig: make cookie() return a pointer to dma_addr_t [media] sh_mobile_ceu_camera: Do not call vb2's mem_ops directly [media] V4L: soc-camera: explicitly require V4L2_BUF_TYPE_VIDEO_CAPTURE [media] v4l: soc-camera: Store negotiated buffer settings [media] rc: interim support for 32-bit NEC-ish scancodes [media] mceusb: topseed 0x0011 needs gen3 init for tx to work [media] lirc_zilog: error out if buffer read bytes != chunk size [media] lirc: silence some compile warnings [media] hdpvr: use same polling interval as other OS [media] ir-kbd-i2c: pass device code w/key in hauppauge case [media] rc/keymaps: Remove the obsolete rc-rc5-tv keymap [media] remove the old RC_MAP_HAUPPAUGE_NEW RC map [media] rc/keymaps: Rename Hauppauge table as rc-hauppauge [media] rc-rc5-hauppauge-new: Fix Hauppauge Grey mapping [media] rc-rc5-hauppauge-new: Add support for the old Black RC [media] rc-rc5-hauppauge-new: Add the old control to the table [media] rc-winfast: Fix the keycode tables [media] a800: Fix a few wrong IR key assignments [media] opera1: Use multimedia keys instead of an app-specific mapping [media] dw2102: Use multimedia keys instead of an app-specific mapping ... Fix up trivial conflicts (remove/modify and some real conflicts) in: arch/arm/mach-omap2/devices.c drivers/staging/Kconfig drivers/staging/Makefile drivers/staging/dabusb/dabusb.c drivers/staging/dabusb/dabusb.h drivers/staging/easycap/easycap_ioctl.c drivers/staging/usbvideo/usbvideo.c drivers/staging/usbvideo/vicam.c
Diffstat (limited to 'drivers/media/dvb/frontends/ds3000.c')
-rw-r--r--drivers/media/dvb/frontends/ds3000.c645
1 files changed, 304 insertions, 341 deletions
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
index fc61d9230db8..90bf573308b0 100644
--- a/drivers/media/dvb/frontends/ds3000.c
+++ b/drivers/media/dvb/frontends/ds3000.c
@@ -229,31 +229,11 @@ static u8 ds3000_dvbs2_init_tab[] = {
0xb8, 0x00,
};
-/* DS3000 doesn't need some parameters as input and auto-detects them */
-/* save input from the application of those parameters */
-struct ds3000_tuning {
- u32 frequency;
- u32 symbol_rate;
- fe_spectral_inversion_t inversion;
- enum fe_code_rate fec;
-
- /* input values */
- u8 inversion_val;
- fe_modulation_t delivery;
- u8 rolloff;
-};
-
struct ds3000_state {
struct i2c_adapter *i2c;
const struct ds3000_config *config;
-
struct dvb_frontend frontend;
-
- struct ds3000_tuning dcur;
- struct ds3000_tuning dnxt;
-
u8 skip_fw_load;
-
/* previous uncorrected block counter for DVB-S2 */
u16 prevUCBS2;
};
@@ -305,7 +285,7 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
struct i2c_msg msg;
u8 *buf;
- buf = kmalloc(3, GFP_KERNEL);
+ buf = kmalloc(33, GFP_KERNEL);
if (buf == NULL) {
printk(KERN_ERR "Unable to kmalloc\n");
ret = -ENOMEM;
@@ -317,10 +297,10 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
msg.addr = state->config->demod_address;
msg.flags = 0;
msg.buf = buf;
- msg.len = 3;
+ msg.len = 33;
- for (i = 0; i < len; i += 2) {
- memcpy(buf + 1, data + i, 2);
+ for (i = 0; i < len; i += 32) {
+ memcpy(buf + 1, data + i, 32);
dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);
@@ -401,45 +381,6 @@ static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg)
return b1[0];
}
-static int ds3000_set_inversion(struct ds3000_state *state,
- fe_spectral_inversion_t inversion)
-{
- dprintk("%s(%d)\n", __func__, inversion);
-
- switch (inversion) {
- case INVERSION_OFF:
- case INVERSION_ON:
- case INVERSION_AUTO:
- break;
- default:
- return -EINVAL;
- }
-
- state->dnxt.inversion = inversion;
-
- return 0;
-}
-
-static int ds3000_set_symbolrate(struct ds3000_state *state, u32 rate)
-{
- int ret = 0;
-
- dprintk("%s()\n", __func__);
-
- dprintk("%s() symbol_rate = %d\n", __func__, state->dnxt.symbol_rate);
-
- /* check if symbol rate is within limits */
- if ((state->dnxt.symbol_rate >
- state->frontend.ops.info.symbol_rate_max) ||
- (state->dnxt.symbol_rate <
- state->frontend.ops.info.symbol_rate_min))
- ret = -EOPNOTSUPP;
-
- state->dnxt.symbol_rate = rate;
-
- return ret;
-}
-
static int ds3000_load_firmware(struct dvb_frontend *fe,
const struct firmware *fw);
@@ -509,23 +450,31 @@ static int ds3000_load_firmware(struct dvb_frontend *fe,
return 0;
}
-static void ds3000_dump_registers(struct dvb_frontend *fe)
+static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct ds3000_state *state = fe->demodulator_priv;
- int x, y, reg = 0, val;
-
- for (y = 0; y < 16; y++) {
- dprintk("%s: %02x: ", __func__, y);
- for (x = 0; x < 16; x++) {
- reg = (y << 4) + x;
- val = ds3000_readreg(state, reg);
- if (x != 15)
- dprintk("%02x ", val);
- else
- dprintk("%02x\n", val);
- }
+ u8 data;
+
+ dprintk("%s(%d)\n", __func__, voltage);
+
+ data = ds3000_readreg(state, 0xa2);
+ data |= 0x03; /* bit0 V/H, bit1 off/on */
+
+ switch (voltage) {
+ case SEC_VOLTAGE_18:
+ data &= ~0x03;
+ break;
+ case SEC_VOLTAGE_13:
+ data &= ~0x03;
+ data |= 0x01;
+ break;
+ case SEC_VOLTAGE_OFF:
+ break;
}
- dprintk("%s: -- DS3000 DUMP DONE --\n", __func__);
+
+ ds3000_writereg(state, 0xa2, data);
+
+ return 0;
}
static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
@@ -562,16 +511,6 @@ static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
return 0;
}
-#define FE_IS_TUNED (FE_HAS_SIGNAL + FE_HAS_LOCK)
-static int ds3000_is_tuned(struct dvb_frontend *fe)
-{
- fe_status_t tunerstat;
-
- ds3000_read_status(fe, &tunerstat);
-
- return ((tunerstat & FE_IS_TUNED) == FE_IS_TUNED);
-}
-
/* read DS3000 BER value */
static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
{
@@ -792,13 +731,6 @@ static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
return 0;
}
-/* Overwrite the current tuning params, we are about to tune */
-static void ds3000_clone_params(struct dvb_frontend *fe)
-{
- struct ds3000_state *state = fe->demodulator_priv;
- memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
-}
-
static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
struct ds3000_state *state = fe->demodulator_priv;
@@ -1016,287 +948,298 @@ static int ds3000_get_property(struct dvb_frontend *fe,
return 0;
}
-static int ds3000_tune(struct dvb_frontend *fe,
+static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
+ s32 carrier_offset_khz)
+{
+ struct ds3000_state *state = fe->demodulator_priv;
+ s32 tmp;
+
+ tmp = carrier_offset_khz;
+ tmp *= 65536;
+ tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE);
+
+ if (tmp < 0)
+ tmp += 65536;
+
+ ds3000_writereg(state, 0x5f, tmp >> 8);
+ ds3000_writereg(state, 0x5e, tmp & 0xff);
+
+ return 0;
+}
+
+static int ds3000_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct ds3000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int ret = 0, retune, i;
- u8 status, mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf;
+ int i;
+ fe_status_t status;
+ u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4;
+ s32 offset_khz;
u16 value, ndiv;
u32 f3db;
dprintk("%s() ", __func__);
- /* Load the firmware if required */
- ret = ds3000_firmware_ondemand(fe);
- if (ret != 0) {
- printk(KERN_ERR "%s: Unable initialise the firmware\n",
- __func__);
- return ret;
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, 0);
+ /* Tune */
+ /* unknown */
+ ds3000_tuner_writereg(state, 0x07, 0x02);
+ ds3000_tuner_writereg(state, 0x10, 0x00);
+ ds3000_tuner_writereg(state, 0x60, 0x79);
+ ds3000_tuner_writereg(state, 0x08, 0x01);
+ ds3000_tuner_writereg(state, 0x00, 0x01);
+ div4 = 0;
+
+ /* calculate and set freq divider */
+ if (p->frequency < 1146000) {
+ ds3000_tuner_writereg(state, 0x10, 0x11);
+ div4 = 1;
+ ndiv = ((p->frequency * (6 + 8) * 4) +
+ (DS3000_XTAL_FREQ / 2)) /
+ DS3000_XTAL_FREQ - 1024;
+ } else {
+ ds3000_tuner_writereg(state, 0x10, 0x01);
+ ndiv = ((p->frequency * (6 + 8) * 2) +
+ (DS3000_XTAL_FREQ / 2)) /
+ DS3000_XTAL_FREQ - 1024;
}
- state->dnxt.delivery = c->modulation;
- state->dnxt.frequency = c->frequency;
- state->dnxt.rolloff = 2; /* fixme */
- state->dnxt.fec = c->fec_inner;
+ ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
+ ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
+
+ /* set pll */
+ ds3000_tuner_writereg(state, 0x03, 0x06);
+ ds3000_tuner_writereg(state, 0x51, 0x0f);
+ ds3000_tuner_writereg(state, 0x51, 0x1f);
+ ds3000_tuner_writereg(state, 0x50, 0x10);
+ ds3000_tuner_writereg(state, 0x50, 0x00);
+ msleep(5);
+
+ /* unknown */
+ ds3000_tuner_writereg(state, 0x51, 0x17);
+ ds3000_tuner_writereg(state, 0x51, 0x1f);
+ ds3000_tuner_writereg(state, 0x50, 0x08);
+ ds3000_tuner_writereg(state, 0x50, 0x00);
+ msleep(5);
+
+ value = ds3000_tuner_readreg(state, 0x3d);
+ value &= 0x0f;
+ if ((value > 4) && (value < 15)) {
+ value -= 3;
+ if (value < 4)
+ value = 4;
+ value = ((value << 3) | 0x01) & 0x79;
+ }
- ret = ds3000_set_inversion(state, p->inversion);
- if (ret != 0)
- return ret;
+ ds3000_tuner_writereg(state, 0x60, value);
+ ds3000_tuner_writereg(state, 0x51, 0x17);
+ ds3000_tuner_writereg(state, 0x51, 0x1f);
+ ds3000_tuner_writereg(state, 0x50, 0x08);
+ ds3000_tuner_writereg(state, 0x50, 0x00);
+
+ /* set low-pass filter period */
+ ds3000_tuner_writereg(state, 0x04, 0x2e);
+ ds3000_tuner_writereg(state, 0x51, 0x1b);
+ ds3000_tuner_writereg(state, 0x51, 0x1f);
+ ds3000_tuner_writereg(state, 0x50, 0x04);
+ ds3000_tuner_writereg(state, 0x50, 0x00);
+ msleep(5);
+
+ f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000;
+ if ((c->symbol_rate / 1000) < 5000)
+ f3db += 3000;
+ if (f3db < 7000)
+ f3db = 7000;
+ if (f3db > 40000)
+ f3db = 40000;
+
+ /* set low-pass filter baseband */
+ value = ds3000_tuner_readreg(state, 0x26);
+ mlpf = 0x2e * 207 / ((value << 1) + 151);
+ mlpf_max = mlpf * 135 / 100;
+ mlpf_min = mlpf * 78 / 100;
+ if (mlpf_max > 63)
+ mlpf_max = 63;
+
+ /* rounded to the closest integer */
+ nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
+ / (2766 * DS3000_XTAL_FREQ);
+ if (nlpf > 23)
+ nlpf = 23;
+ if (nlpf < 1)
+ nlpf = 1;
+
+ /* rounded to the closest integer */
+ mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+ (1000 * f3db / 2)) / (1000 * f3db);
+
+ if (mlpf_new < mlpf_min) {
+ nlpf++;
+ mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+ (1000 * f3db / 2)) / (1000 * f3db);
+ }
- ret = ds3000_set_symbolrate(state, c->symbol_rate);
- if (ret != 0)
- return ret;
+ if (mlpf_new > mlpf_max)
+ mlpf_new = mlpf_max;
+
+ ds3000_tuner_writereg(state, 0x04, mlpf_new);
+ ds3000_tuner_writereg(state, 0x06, nlpf);
+ ds3000_tuner_writereg(state, 0x51, 0x1b);
+ ds3000_tuner_writereg(state, 0x51, 0x1f);
+ ds3000_tuner_writereg(state, 0x50, 0x04);
+ ds3000_tuner_writereg(state, 0x50, 0x00);
+ msleep(5);
+
+ /* unknown */
+ ds3000_tuner_writereg(state, 0x51, 0x1e);
+ ds3000_tuner_writereg(state, 0x51, 0x1f);
+ ds3000_tuner_writereg(state, 0x50, 0x01);
+ ds3000_tuner_writereg(state, 0x50, 0x00);
+ msleep(60);
+
+ offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
+ / (6 + 8) / (div4 + 1) / 2 - p->frequency;
+
+ /* ds3000 global reset */
+ ds3000_writereg(state, 0x07, 0x80);
+ ds3000_writereg(state, 0x07, 0x00);
+ /* ds3000 build-in uC reset */
+ ds3000_writereg(state, 0xb2, 0x01);
+ /* ds3000 software reset */
+ ds3000_writereg(state, 0x00, 0x01);
- /* discard the 'current' tuning parameters and prepare to tune */
- ds3000_clone_params(fe);
-
- retune = 1; /* try 1 times */
- dprintk("%s: retune = %d\n", __func__, retune);
- dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
- dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
- dprintk("%s: FEC = %d \n", __func__,
- state->dcur.fec);
- dprintk("%s: Inversion = %d\n", __func__, state->dcur.inversion);
-
- do {
- /* Reset status register */
- status = 0;
- /* Tune */
- /* TS2020 init */
- ds3000_tuner_writereg(state, 0x42, 0x73);
- ds3000_tuner_writereg(state, 0x05, 0x01);
- ds3000_tuner_writereg(state, 0x62, 0xf5);
- /* unknown */
- ds3000_tuner_writereg(state, 0x07, 0x02);
- ds3000_tuner_writereg(state, 0x10, 0x00);
- ds3000_tuner_writereg(state, 0x60, 0x79);
- ds3000_tuner_writereg(state, 0x08, 0x01);
- ds3000_tuner_writereg(state, 0x00, 0x01);
- /* calculate and set freq divider */
- if (state->dcur.frequency < 1146000) {
- ds3000_tuner_writereg(state, 0x10, 0x11);
- ndiv = ((state->dcur.frequency * (6 + 8) * 4) +
- (DS3000_XTAL_FREQ / 2)) /
- DS3000_XTAL_FREQ - 1024;
- } else {
- ds3000_tuner_writereg(state, 0x10, 0x01);
- ndiv = ((state->dcur.frequency * (6 + 8) * 2) +
- (DS3000_XTAL_FREQ / 2)) /
- DS3000_XTAL_FREQ - 1024;
- }
+ switch (c->delivery_system) {
+ case SYS_DVBS:
+ /* initialise the demod in DVB-S mode */
+ for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
+ ds3000_writereg(state,
+ ds3000_dvbs_init_tab[i],
+ ds3000_dvbs_init_tab[i + 1]);
+ value = ds3000_readreg(state, 0xfe);
+ value &= 0xc0;
+ value |= 0x1b;
+ ds3000_writereg(state, 0xfe, value);
+ break;
+ case SYS_DVBS2:
+ /* initialise the demod in DVB-S2 mode */
+ for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
+ ds3000_writereg(state,
+ ds3000_dvbs2_init_tab[i],
+ ds3000_dvbs2_init_tab[i + 1]);
+ ds3000_writereg(state, 0xfe, 0x98);
+ break;
+ default:
+ return 1;
+ }
- ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
- ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
-
- /* set pll */
- ds3000_tuner_writereg(state, 0x03, 0x06);
- ds3000_tuner_writereg(state, 0x51, 0x0f);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x10);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- /* unknown */
- ds3000_tuner_writereg(state, 0x51, 0x17);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x08);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- value = ds3000_tuner_readreg(state, 0x3d);
- value &= 0x0f;
- if ((value > 4) && (value < 15)) {
- value -= 3;
- if (value < 4)
- value = 4;
- value = ((value << 3) | 0x01) & 0x79;
- }
+ /* enable 27MHz clock output */
+ ds3000_writereg(state, 0x29, 0x80);
+ /* enable ac coupling */
+ ds3000_writereg(state, 0x25, 0x8a);
+
+ /* enhance symbol rate performance */
+ if ((c->symbol_rate / 1000) <= 5000) {
+ value = 29777 / (c->symbol_rate / 1000) + 1;
+ if (value % 2 != 0)
+ value++;
+ ds3000_writereg(state, 0xc3, 0x0d);
+ ds3000_writereg(state, 0xc8, value);
+ ds3000_writereg(state, 0xc4, 0x10);
+ ds3000_writereg(state, 0xc7, 0x0e);
+ } else if ((c->symbol_rate / 1000) <= 10000) {
+ value = 92166 / (c->symbol_rate / 1000) + 1;
+ if (value % 2 != 0)
+ value++;
+ ds3000_writereg(state, 0xc3, 0x07);
+ ds3000_writereg(state, 0xc8, value);
+ ds3000_writereg(state, 0xc4, 0x09);
+ ds3000_writereg(state, 0xc7, 0x12);
+ } else if ((c->symbol_rate / 1000) <= 20000) {
+ value = 64516 / (c->symbol_rate / 1000) + 1;
+ ds3000_writereg(state, 0xc3, value);
+ ds3000_writereg(state, 0xc8, 0x0e);
+ ds3000_writereg(state, 0xc4, 0x07);
+ ds3000_writereg(state, 0xc7, 0x18);
+ } else {
+ value = 129032 / (c->symbol_rate / 1000) + 1;
+ ds3000_writereg(state, 0xc3, value);
+ ds3000_writereg(state, 0xc8, 0x0a);
+ ds3000_writereg(state, 0xc4, 0x05);
+ ds3000_writereg(state, 0xc7, 0x24);
+ }
- ds3000_tuner_writereg(state, 0x60, value);
- ds3000_tuner_writereg(state, 0x51, 0x17);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x08);
- ds3000_tuner_writereg(state, 0x50, 0x00);
-
- /* set low-pass filter period */
- ds3000_tuner_writereg(state, 0x04, 0x2e);
- ds3000_tuner_writereg(state, 0x51, 0x1b);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x04);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- f3db = ((state->dcur.symbol_rate / 1000) << 2) / 5 + 2000;
- if ((state->dcur.symbol_rate / 1000) < 5000)
- f3db += 3000;
- if (f3db < 7000)
- f3db = 7000;
- if (f3db > 40000)
- f3db = 40000;
-
- /* set low-pass filter baseband */
- value = ds3000_tuner_readreg(state, 0x26);
- mlpf = 0x2e * 207 / ((value << 1) + 151);
- mlpf_max = mlpf * 135 / 100;
- mlpf_min = mlpf * 78 / 100;
- if (mlpf_max > 63)
- mlpf_max = 63;
-
- /* rounded to the closest integer */
- nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
- / (2766 * DS3000_XTAL_FREQ);
- if (nlpf > 23)
- nlpf = 23;
- if (nlpf < 1)
- nlpf = 1;
-
- /* rounded to the closest integer */
- mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
- (1000 * f3db / 2)) / (1000 * f3db);
+ /* normalized symbol rate rounded to the closest integer */
+ value = (((c->symbol_rate / 1000) << 16) +
+ (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
+ ds3000_writereg(state, 0x61, value & 0x00ff);
+ ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
- if (mlpf_new < mlpf_min) {
- nlpf++;
- mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
- (1000 * f3db / 2)) / (1000 * f3db);
- }
+ /* co-channel interference cancellation disabled */
+ ds3000_writereg(state, 0x56, 0x00);
+
+ /* equalizer disabled */
+ ds3000_writereg(state, 0x76, 0x00);
- if (mlpf_new > mlpf_max)
- mlpf_new = mlpf_max;
-
- ds3000_tuner_writereg(state, 0x04, mlpf_new);
- ds3000_tuner_writereg(state, 0x06, nlpf);
- ds3000_tuner_writereg(state, 0x51, 0x1b);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x04);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(5);
-
- /* unknown */
- ds3000_tuner_writereg(state, 0x51, 0x1e);
- ds3000_tuner_writereg(state, 0x51, 0x1f);
- ds3000_tuner_writereg(state, 0x50, 0x01);
- ds3000_tuner_writereg(state, 0x50, 0x00);
- msleep(60);
-
- /* ds3000 global reset */
- ds3000_writereg(state, 0x07, 0x80);
- ds3000_writereg(state, 0x07, 0x00);
- /* ds3000 build-in uC reset */
- ds3000_writereg(state, 0xb2, 0x01);
- /* ds3000 software reset */
- ds3000_writereg(state, 0x00, 0x01);
+ /*ds3000_writereg(state, 0x08, 0x03);
+ ds3000_writereg(state, 0xfd, 0x22);
+ ds3000_writereg(state, 0x08, 0x07);
+ ds3000_writereg(state, 0xfd, 0x42);
+ ds3000_writereg(state, 0x08, 0x07);*/
+ if (state->config->ci_mode) {
switch (c->delivery_system) {
case SYS_DVBS:
- /* initialise the demod in DVB-S mode */
- for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
- ds3000_writereg(state,
- ds3000_dvbs_init_tab[i],
- ds3000_dvbs_init_tab[i + 1]);
- value = ds3000_readreg(state, 0xfe);
- value &= 0xc0;
- value |= 0x1b;
- ds3000_writereg(state, 0xfe, value);
- break;
+ default:
+ ds3000_writereg(state, 0xfd, 0x80);
+ break;
case SYS_DVBS2:
- /* initialise the demod in DVB-S2 mode */
- for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
- ds3000_writereg(state,
- ds3000_dvbs2_init_tab[i],
- ds3000_dvbs2_init_tab[i + 1]);
- ds3000_writereg(state, 0xfe, 0x54);
+ ds3000_writereg(state, 0xfd, 0x01);
break;
- default:
- return 1;
}
+ }
- /* enable 27MHz clock output */
- ds3000_writereg(state, 0x29, 0x80);
- /* enable ac coupling */
- ds3000_writereg(state, 0x25, 0x8a);
-
- /* enhance symbol rate performance */
- if ((state->dcur.symbol_rate / 1000) <= 5000) {
- value = 29777 / (state->dcur.symbol_rate / 1000) + 1;
- if (value % 2 != 0)
- value++;
- ds3000_writereg(state, 0xc3, 0x0d);
- ds3000_writereg(state, 0xc8, value);
- ds3000_writereg(state, 0xc4, 0x10);
- ds3000_writereg(state, 0xc7, 0x0e);
- } else if ((state->dcur.symbol_rate / 1000) <= 10000) {
- value = 92166 / (state->dcur.symbol_rate / 1000) + 1;
- if (value % 2 != 0)
- value++;
- ds3000_writereg(state, 0xc3, 0x07);
- ds3000_writereg(state, 0xc8, value);
- ds3000_writereg(state, 0xc4, 0x09);
- ds3000_writereg(state, 0xc7, 0x12);
- } else if ((state->dcur.symbol_rate / 1000) <= 20000) {
- value = 64516 / (state->dcur.symbol_rate / 1000) + 1;
- ds3000_writereg(state, 0xc3, value);
- ds3000_writereg(state, 0xc8, 0x0e);
- ds3000_writereg(state, 0xc4, 0x07);
- ds3000_writereg(state, 0xc7, 0x18);
- } else {
- value = 129032 / (state->dcur.symbol_rate / 1000) + 1;
- ds3000_writereg(state, 0xc3, value);
- ds3000_writereg(state, 0xc8, 0x0a);
- ds3000_writereg(state, 0xc4, 0x05);
- ds3000_writereg(state, 0xc7, 0x24);
- }
+ /* ds3000 out of software reset */
+ ds3000_writereg(state, 0x00, 0x00);
+ /* start ds3000 build-in uC */
+ ds3000_writereg(state, 0xb2, 0x00);
- /* normalized symbol rate rounded to the closest integer */
- value = (((state->dcur.symbol_rate / 1000) << 16) +
- (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
- ds3000_writereg(state, 0x61, value & 0x00ff);
- ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
-
- /* co-channel interference cancellation disabled */
- ds3000_writereg(state, 0x56, 0x00);
-
- /* equalizer disabled */
- ds3000_writereg(state, 0x76, 0x00);
-
- /*ds3000_writereg(state, 0x08, 0x03);
- ds3000_writereg(state, 0xfd, 0x22);
- ds3000_writereg(state, 0x08, 0x07);
- ds3000_writereg(state, 0xfd, 0x42);
- ds3000_writereg(state, 0x08, 0x07);*/
-
- /* ds3000 out of software reset */
- ds3000_writereg(state, 0x00, 0x00);
- /* start ds3000 build-in uC */
- ds3000_writereg(state, 0xb2, 0x00);
-
- /* TODO: calculate and set carrier offset */
-
- /* wait before retrying */
- for (i = 0; i < 30 ; i++) {
- if (ds3000_is_tuned(fe)) {
- dprintk("%s: Tuned\n", __func__);
- ds3000_dump_registers(fe);
- goto tuned;
- }
- msleep(1);
- }
+ ds3000_set_carrier_offset(fe, offset_khz);
- dprintk("%s: Not tuned\n", __func__);
- ds3000_dump_registers(fe);
+ for (i = 0; i < 30 ; i++) {
+ ds3000_read_status(fe, &status);
+ if (status && FE_HAS_LOCK)
+ break;
- } while (--retune);
+ msleep(10);
+ }
-tuned:
- return ret;
+ return 0;
+}
+
+static int ds3000_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p,
+ unsigned int mode_flags,
+ unsigned int *delay,
+ fe_status_t *status)
+{
+ if (p) {
+ int ret = ds3000_set_frontend(fe, p);
+ if (ret)
+ return ret;
+ }
+
+ *delay = HZ / 5;
+
+ return ds3000_read_status(fe, status);
}
static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
{
dprintk("%s()\n", __func__);
- return DVBFE_ALGO_SW;
+ return DVBFE_ALGO_HW;
}
/*
@@ -1306,7 +1249,25 @@ static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
*/
static int ds3000_initfe(struct dvb_frontend *fe)
{
+ struct ds3000_state *state = fe->demodulator_priv;
+ int ret;
+
dprintk("%s()\n", __func__);
+ /* hard reset */
+ ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
+ msleep(1);
+
+ /* TS2020 init */
+ ds3000_tuner_writereg(state, 0x42, 0x73);
+ ds3000_tuner_writereg(state, 0x05, 0x01);
+ ds3000_tuner_writereg(state, 0x62, 0xf5);
+ /* Load the firmware if required */
+ ret = ds3000_firmware_ondemand(fe);
+ if (ret != 0) {
+ printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
+ return ret;
+ }
+
return 0;
}
@@ -1345,6 +1306,7 @@ static struct dvb_frontend_ops ds3000_ops = {
.read_signal_strength = ds3000_read_signal_strength,
.read_snr = ds3000_read_snr,
.read_ucblocks = ds3000_read_ucblocks,
+ .set_voltage = ds3000_set_voltage,
.set_tone = ds3000_set_tone,
.diseqc_send_master_cmd = ds3000_send_diseqc_msg,
.diseqc_send_burst = ds3000_diseqc_send_burst,
@@ -1352,7 +1314,8 @@ static struct dvb_frontend_ops ds3000_ops = {
.set_property = ds3000_set_property,
.get_property = ds3000_get_property,
- .set_frontend = ds3000_tune,
+ .set_frontend = ds3000_set_frontend,
+ .tune = ds3000_tune,
};
module_param(debug, int, 0644);