<ralph@convergence.de>,
<holger@convergence.de>,
<js@convergence.de>
-
+
Philips SU1278/SH
LG TDQF-S001F
Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
- & Andreas Oberritter <obi@linuxtv.org>
+ & Andreas Oberritter <obi@linuxtv.org>
Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+*/
#include <linux/init.h>
#include <linux/kernel.h>
#include "stv0299.h"
struct stv0299_state {
-
struct i2c_adapter* i2c;
-
struct dvb_frontend_ops ops;
-
const struct stv0299_config* config;
-
struct dvb_frontend frontend;
u8 initialised:1;
#define STATUS_UCBLOCKS 1
static int debug;
+static int debug_legacy_dish_switch;
#define dprintk(args...) \
do { \
if (debug) printk(KERN_DEBUG "stv0299: " args); \
ret = i2c_transfer (state->i2c, &msg, 1);
- if (ret != 1)
+ if (ret != 1)
dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
"ret == %i)\n", __FUNCTION__, reg, data, ret);
int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
return stv0299_writeregI(state, reg, data);
}
-
static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
{
int ret;
{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
ret = i2c_transfer (state->i2c, msg, 2);
-
- if (ret != 2)
+
+ if (ret != 2)
dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n",
__FUNCTION__, reg, ret);
return b1[0];
}
-
static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len)
{
- int ret;
+ int ret;
struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
ret = i2c_transfer (state->i2c, msg, 2);
- if (ret != 2)
- dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+ if (ret != 2)
+ dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
- return ret == 2 ? 0 : ret;
+ return ret == 2 ? 0 : ret;
}
-
static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
{
return -EINVAL;
}
+ }
}
-}
-
static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state)
{
return fec_tab [index];
}
-
static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout)
{
unsigned long start = jiffies;
return 0;
}
-
static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout)
{
unsigned long start = jiffies;
static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
u64 big = srate;
u32 ratio;
return state->config->set_symbol_rate(fe, srate, ratio);
}
-
static int stv0299_get_symbolrate (struct stv0299_state* state)
{
u32 Mclk = state->config->mclk / 4096L;
return srate;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
static int stv0299_send_diseqc_msg (struct dvb_frontend* fe,
- struct dvb_diseqc_master_cmd *m)
+ struct dvb_diseqc_master_cmd *m)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
u8 val;
int i;
return 0;
}
-
static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
u8 val;
dprintk ("%s\n", __FUNCTION__);
return 0;
}
-
static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
u8 val;
if (stv0299_wait_diseqc_idle (state, 100) < 0)
}
}
-
static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
u8 reg0x08;
u8 reg0x0c;
dprintk("%s: %s\n", __FUNCTION__,
- voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+ voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
reg0x08 = stv0299_readreg (state, 0x08);
stv0299_writeregI (state, 0x0c, 0x00); /* LNB power off! */
return stv0299_writeregI (state, 0x08, 0x00); /* LNB power off! */
}
-
+
stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
switch (voltage) {
};
}
+static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime)
+{
+ return ((curtime.tv_usec < lasttime.tv_usec) ?
+ 1000000 - lasttime.tv_usec + curtime.tv_usec :
+ curtime.tv_usec - lasttime.tv_usec);
+}
-static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd)
+static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec)
{
+ struct timeval lasttime;
+ s32 delta, newdelta;
+
+ waketime->tv_usec += add_usec;
+ if (waketime->tv_usec >= 1000000) {
+ waketime->tv_usec -= 1000000;
+ waketime->tv_sec++;
+ }
+
+ do_gettimeofday (&lasttime);
+ delta = stv0299_calc_usec_delay (lasttime, *waketime);
+ if (delta > 2500) {
+ msleep ((delta - 1500) / 1000);
+ do_gettimeofday (&lasttime);
+ newdelta = stv0299_calc_usec_delay (lasttime, *waketime);
+ delta = (newdelta > delta) ? 0 : newdelta;
+ }
+ if (delta > 0)
+ udelay (delta);
+}
+
+static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
+{
+ struct stv0299_state* state = fe->demodulator_priv;
+ u8 reg0x08;
+ u8 reg0x0c;
+ u8 lv_mask = 0x40;
u8 last = 1;
int i;
+ struct timeval nexttime;
+ struct timeval tv[10];
- /* reset voltage at the end
- if((0x50 & stv0299_readreg (i2c, 0x0c)) == 0x50)
- cmd |= 0x80;
- else
- cmd &= 0x7F;
- */
+ reg0x08 = stv0299_readreg (state, 0x08);
+ reg0x0c = stv0299_readreg (state, 0x0c);
+ reg0x0c &= 0x0f;
+ stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6));
+ if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0)
+ lv_mask = 0x10;
cmd = cmd << 1;
- dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
+ if (debug_legacy_dish_switch)
+ printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd);
+
+ do_gettimeofday (&nexttime);
+ if (debug_legacy_dish_switch)
+ memcpy (&tv[0], &nexttime, sizeof (struct timeval));
+ stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
- stv0299_set_voltage(fe,SEC_VOLTAGE_18);
- msleep(32);
+ stv0299_sleep_until (&nexttime, 32000);
for (i=0; i<9; i++) {
+ if (debug_legacy_dish_switch)
+ do_gettimeofday (&tv[i+1]);
if((cmd & 0x01) != last) {
- stv0299_set_voltage(fe,
- last ? SEC_VOLTAGE_13 :
- SEC_VOLTAGE_18);
+ /* set voltage to (last ? 13V : 18V) */
+ stv0299_writeregI (state, 0x0c, reg0x0c | (last ? lv_mask : 0x50));
last = (last) ? 0 : 1;
}
cmd = cmd >> 1;
if (i != 8)
- msleep(8);
+ stv0299_sleep_until (&nexttime, 8000);
+ }
+ if (debug_legacy_dish_switch) {
+ printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
+ __FUNCTION__, fe->dvb->num);
+ for (i=1; i < 10; i++)
+ printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i]));
}
return 0;
}
-
static int stv0299_init (struct dvb_frontend* fe)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
int i;
dprintk("stv0299: init chip\n");
return 0;
}
-
static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status)
- {
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+ struct stv0299_state* state = fe->demodulator_priv;
u8 signal = 0xff - stv0299_readreg (state, 0x18);
u8 sync = stv0299_readreg (state, 0x1b);
- dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
- *status = 0;
+ dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync);
+ *status = 0;
- if (signal > 10)
- *status |= FE_HAS_SIGNAL;
+ if (signal > 10)
+ *status |= FE_HAS_SIGNAL;
- if (sync & 0x80)
- *status |= FE_HAS_CARRIER;
+ if (sync & 0x80)
+ *status |= FE_HAS_CARRIER;
- if (sync & 0x10)
- *status |= FE_HAS_VITERBI;
+ if (sync & 0x10)
+ *status |= FE_HAS_VITERBI;
- if (sync & 0x08)
- *status |= FE_HAS_SYNC;
+ if (sync & 0x08)
+ *status |= FE_HAS_SYNC;
- if ((sync & 0x98) == 0x98)
- *status |= FE_HAS_LOCK;
+ if ((sync & 0x98) == 0x98)
+ *status |= FE_HAS_LOCK;
return 0;
- }
+}
static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
if (state->errmode != STATUS_BER) return 0;
*ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
return 0;
- }
+}
static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength)
- {
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+ struct stv0299_state* state = fe->demodulator_priv;
s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8)
| stv0299_readreg (state, 0x19));
- dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__,
+ dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__,
stv0299_readreg (state, 0x18),
stv0299_readreg (state, 0x19), (int) signal);
- signal = signal * 5 / 4;
+ signal = signal * 5 / 4;
*strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal;
return 0;
- }
+}
static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr)
- {
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+ struct stv0299_state* state = fe->demodulator_priv;
s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8)
| stv0299_readreg (state, 0x25));
static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- int invval = 0;
+ struct stv0299_state* state = fe->demodulator_priv;
+ int invval = 0;
- dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
+ dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__);
- // set the inversion
- if (p->inversion == INVERSION_OFF) invval = 0;
- else if (p->inversion == INVERSION_ON) invval = 1;
- else {
- printk("stv0299 does not support auto-inversion\n");
- return -EINVAL;
- }
+ // set the inversion
+ if (p->inversion == INVERSION_OFF) invval = 0;
+ else if (p->inversion == INVERSION_ON) invval = 1;
+ else {
+ printk("stv0299 does not support auto-inversion\n");
+ return -EINVAL;
+ }
if (state->config->invert) invval = (~invval) & 1;
stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
if (state->config->enhanced_tuning) {
- /* check if we should do a finetune */
- int frequency_delta = p->frequency - state->tuner_frequency;
- int minmax = p->u.qpsk.symbol_rate / 2000;
- if (minmax < 5000) minmax = 5000;
-
- if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
- (state->fec_inner == p->u.qpsk.fec_inner) &&
- (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+ /* check if we should do a finetune */
+ int frequency_delta = p->frequency - state->tuner_frequency;
+ int minmax = p->u.qpsk.symbol_rate / 2000;
+ if (minmax < 5000) minmax = 5000;
+
+ if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
+ (state->fec_inner == p->u.qpsk.fec_inner) &&
+ (state->symbol_rate == p->u.qpsk.symbol_rate)) {
int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000);
- // zap the derotator registers first
+ // zap the derotator registers first
stv0299_writeregI(state, 0x22, 0x00);
stv0299_writeregI(state, 0x23, 0x00);
- // now set them as we want
+ // now set them as we want
stv0299_writeregI(state, 0x22, Drot_freq >> 8);
stv0299_writeregI(state, 0x23, Drot_freq);
- } else {
- /* A "normal" tune is requested */
+ } else {
+ /* A "normal" tune is requested */
stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
state->config->pll_set(fe, p);
stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
stv0299_writeregI(state, 0x23, 0x00);
stv0299_readreg (state, 0x23);
stv0299_writeregI(state, 0x12, 0xb9);
- }
+ }
- state->tuner_frequency = p->frequency;
- state->fec_inner = p->u.qpsk.fec_inner;
- state->symbol_rate = p->u.qpsk.symbol_rate;
+ state->tuner_frequency = p->frequency;
+ state->fec_inner = p->u.qpsk.fec_inner;
+ state->symbol_rate = p->u.qpsk.symbol_rate;
return 0;
- }
+}
static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
- {
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
- s32 derot_freq;
- int invval;
+{
+ struct stv0299_state* state = fe->demodulator_priv;
+ s32 derot_freq;
+ int invval;
derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8)
| stv0299_readreg (state, 0x23));
derot_freq *= (state->config->mclk >> 16);
- derot_freq += 500;
- derot_freq /= 1000;
+ derot_freq += 500;
+ derot_freq /= 1000;
- p->frequency += derot_freq;
+ p->frequency += derot_freq;
invval = stv0299_readreg (state, 0x0c) & 1;
if (state->config->invert) invval = (~invval) & 1;
- p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
+ p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
p->u.qpsk.fec_inner = stv0299_get_fec (state);
p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state);
return 0;
- }
+}
static int stv0299_sleep(struct dvb_frontend* fe)
{
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+ struct stv0299_state* state = fe->demodulator_priv;
stv0299_writeregI(state, 0x02, 0x80);
state->initialised = 0;
}
static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
- {
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+ struct stv0299_state* state = fe->demodulator_priv;
fesettings->min_delay_ms = state->config->min_delay_ms;
- if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
- fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
- fesettings->max_drift = 5000;
- } else {
- fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
- fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
- }
+ if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
+ fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
+ fesettings->max_drift = 5000;
+ } else {
+ fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
+ fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
+ }
return 0;
}
static void stv0299_release(struct dvb_frontend* fe)
- {
- struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv;
+{
+ struct stv0299_state* state = fe->demodulator_priv;
kfree(state);
}
{
struct stv0299_state* state = NULL;
int id;
-
+
/* allocate memory for the internal state */
- state = (struct stv0299_state*) kmalloc(sizeof(struct stv0299_state), GFP_KERNEL);
+ state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL);
if (state == NULL) goto error;
/* setup the state */
return &state->frontend;
error:
- if (state) kfree(state);
+ kfree(state);
return NULL;
}
.dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd,
};
+module_param(debug_legacy_dish_switch, int, 0444);
+MODULE_PARM_DESC(debug_legacy_dish_switch, "Enable timing analysis for Dish Network legacy switches");
+
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");