PATCH 28/44 multiproto + backward compatibility [S5H1420]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



--- v4l-dvb/linux/drivers/media/dvb/frontends/s5h1420.c	2006-06-30 19:59:10.000000000 +0400
+++ mp-bc1/linux/drivers/media/dvb/frontends/s5h1420.c	2006-07-23 11:40:07.000000000 +0400
@@ -419,8 +419,8 @@ static void s5h1420_reset(struct s5h1420
 	udelay(10);
 }
 
-static void s5h1420_setsymbolrate(struct s5h1420_state* state,
-				  struct dvb_frontend_parameters *p)
+static void s5h1420_setsymbolrate_compat(struct s5h1420_state* state,
+					 struct dvb_frontend_parameters *p)
 {
 	u64 val;
 
@@ -437,6 +437,24 @@ static void s5h1420_setsymbolrate(struct
 	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80);
 }
 
+static void s5h1420_setsymbolrate(struct s5h1420_state* state,
+				  struct dvbfe_params *p)
+{
+	u64 val;
+
+	val = ((u64) p->delsys.dvbs.symbol_rate / 1000ULL) * (1ULL<<24);
+	if (p->delsys.dvbs.symbol_rate <= 21000000) {
+		val *= 2;
+	}
+	do_div(val, (state->fclk / 1000));
+
+	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f);
+	s5h1420_writereg(state, 0x11, val >> 16);
+	s5h1420_writereg(state, 0x12, val >> 8);
+	s5h1420_writereg(state, 0x13, val & 0xff);
+	s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80);
+}
+
 static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
 {
 	u64 val = 0;
@@ -492,8 +510,8 @@ static int s5h1420_getfreqoffset(struct 
 	return val;
 }
 
-static void s5h1420_setfec_inversion(struct s5h1420_state* state,
-				     struct dvb_frontend_parameters *p)
+static void s5h1420_setfec_inversion_compat(struct s5h1420_state* state,
+					    struct dvb_frontend_parameters *p)
 {
 	u8 inversion = 0;
 
@@ -544,7 +562,61 @@ static void s5h1420_setfec_inversion(str
 	}
 }
 
-static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
+static void s5h1420_setfec_inversion(struct s5h1420_state* state,
+				     struct dvbfe_params *p)
+{
+	u8 inversion = 0;
+
+	if (p->inversion == INVERSION_OFF) {
+		inversion = state->config->invert ? 0x08 : 0;
+	} else if (p->inversion == INVERSION_ON) {
+		inversion = state->config->invert ? 0 : 0x08;
+	}
+
+	if ((p->delsys.dvbs.fec == DVBFE_FEC_AUTO) ||
+	    (p->inversion == INVERSION_AUTO)) {
+
+		s5h1420_writereg(state, 0x30, 0x3f);
+		s5h1420_writereg(state, 0x31, 0x00 | inversion);
+	} else {
+		switch (p->delsys.dvbs.fec) {
+		case DVBFE_FEC_1_2:
+			s5h1420_writereg(state, 0x30, 0x01);
+			s5h1420_writereg(state, 0x31, 0x10 | inversion);
+			break;
+
+		case DVBFE_FEC_2_3:
+			s5h1420_writereg(state, 0x30, 0x02);
+			s5h1420_writereg(state, 0x31, 0x11 | inversion);
+			break;
+
+		case DVBFE_FEC_3_4:
+			s5h1420_writereg(state, 0x30, 0x04);
+			s5h1420_writereg(state, 0x31, 0x12 | inversion);
+			break;
+
+		case DVBFE_FEC_5_6:
+			s5h1420_writereg(state, 0x30, 0x08);
+			s5h1420_writereg(state, 0x31, 0x13 | inversion);
+			break;
+
+		case DVBFE_FEC_6_7:
+			s5h1420_writereg(state, 0x30, 0x10);
+			s5h1420_writereg(state, 0x31, 0x14 | inversion);
+			break;
+
+		case DVBFE_FEC_7_8:
+			s5h1420_writereg(state, 0x30, 0x20);
+			s5h1420_writereg(state, 0x31, 0x15 | inversion);
+			break;
+
+		default:
+			return;
+		}
+	}
+}
+
+static fe_code_rate_t s5h1420_getfec_compat(struct s5h1420_state* state)
 {
 	switch(s5h1420_readreg(state, 0x32) & 0x07) {
 	case 0:
@@ -569,6 +641,31 @@ static fe_code_rate_t s5h1420_getfec(str
 	return FEC_NONE;
 }
 
+static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
+{
+	switch(s5h1420_readreg(state, 0x32) & 0x07) {
+	case 0:
+		return DVBFE_FEC_1_2;
+
+	case 1:
+		return DVBFE_FEC_2_3;
+
+	case 2:
+		return DVBFE_FEC_3_4;
+
+	case 3:
+		return DVBFE_FEC_5_6;
+
+	case 4:
+		return DVBFE_FEC_6_7;
+
+	case 5:
+		return DVBFE_FEC_7_8;
+	}
+
+	return DVBFE_FEC_NONE;
+}
+
 static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
 {
 	if (s5h1420_readreg(state, 0x32) & 0x08)
@@ -594,9 +691,10 @@ static int s5h1420_set_frontend(struct d
 	    (state->fec_inner == p->u.qpsk.fec_inner) &&
 	    (state->symbol_rate == p->u.qpsk.symbol_rate)) {
 
-		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.set_params_compat) {
+			fe->ops.tuner_ops.set_params_compat(fe, p);
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
 		}
 		if (fe->ops.tuner_ops.get_frequency) {
 			u32 tmp;
@@ -651,9 +749,104 @@ static int s5h1420_set_frontend(struct d
 	s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
 
 	/* set tuner PLL */
+	if (fe->ops.tuner_ops.set_params_compat) {
+		fe->ops.tuner_ops.set_params_compat(fe, p);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+		s5h1420_setfreqoffset(state, 0);
+	}
+
+	/* set the reset of the parameters */
+	s5h1420_setsymbolrate_compat(state, p);
+	s5h1420_setfec_inversion_compat(state, p);
+
+	state->fec_inner = p->u.qpsk.fec_inner;
+	state->symbol_rate = p->u.qpsk.symbol_rate;
+	state->postlocked = 0;
+	state->tunedfreq = p->frequency;
+	return 0;
+}
+
+static int s5h1420_set_params(struct dvb_frontend* fe,
+			      struct dvbfe_params *p)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+	int frequency_delta;
+	struct dvb_frontend_tune_settings fesettings;
+
+	/* check if we should do a fast-tune */
+//	memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
+	memcpy(&fesettings.fe_params, p, sizeof(struct dvb_frontend_parameters));
+	s5h1420_get_tune_settings(fe, &fesettings);
+	frequency_delta = p->frequency - state->tunedfreq;
+	if ((frequency_delta > -fesettings.max_drift) &&
+	    (frequency_delta < fesettings.max_drift) &&
+	    (frequency_delta != 0) &&
+	    (state->fec_inner == p->delsys.dvbs.fec) &&
+	    (state->symbol_rate == p->delsys.dvbs.symbol_rate)) {
+
+		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;
+	}
+
+	/* first of all, software reset */
+	s5h1420_reset(state);
+
+	/* set s5h1420 fclk PLL according to desired symbol rate */
+	if (p->delsys.dvbs.symbol_rate > 28000000) {
+		state->fclk = 88000000;
+		s5h1420_writereg(state, 0x03, 0x50);
+		s5h1420_writereg(state, 0x04, 0x40);
+		s5h1420_writereg(state, 0x05, 0xae);
+	} else if (p->delsys.dvbs.symbol_rate > 21000000) {
+		state->fclk = 59000000;
+		s5h1420_writereg(state, 0x03, 0x33);
+		s5h1420_writereg(state, 0x04, 0x40);
+		s5h1420_writereg(state, 0x05, 0xae);
+	} else {
+		state->fclk = 88000000;
+		s5h1420_writereg(state, 0x03, 0x50);
+		s5h1420_writereg(state, 0x04, 0x40);
+		s5h1420_writereg(state, 0x05, 0xac);
+	}
+
+	/* set misc registers */
+	s5h1420_writereg(state, 0x02, 0x00);
+	s5h1420_writereg(state, 0x06, 0x00);
+	s5h1420_writereg(state, 0x07, 0xb0);
+	s5h1420_writereg(state, 0x0a, 0xe7);
+	s5h1420_writereg(state, 0x0b, 0x78);
+	s5h1420_writereg(state, 0x0c, 0x48);
+	s5h1420_writereg(state, 0x0d, 0x6b);
+	s5h1420_writereg(state, 0x2e, 0x8e);
+	s5h1420_writereg(state, 0x35, 0x33);
+	s5h1420_writereg(state, 0x38, 0x01);
+	s5h1420_writereg(state, 0x39, 0x7d);
+	s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
+	s5h1420_writereg(state, 0x3c, 0x00);
+	s5h1420_writereg(state, 0x45, 0x61);
+	s5h1420_writereg(state, 0x46, 0x1d);
+
+	/* start QPSK */
+	s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
+
+	/* set tuner PLL */
 	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.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
 		s5h1420_setfreqoffset(state, 0);
 	}
 
@@ -661,8 +854,8 @@ static int s5h1420_set_frontend(struct d
 	s5h1420_setsymbolrate(state, p);
 	s5h1420_setfec_inversion(state, p);
 
-	state->fec_inner = p->u.qpsk.fec_inner;
-	state->symbol_rate = p->u.qpsk.symbol_rate;
+	state->fec_inner = p->delsys.dvbs.fec;
+	state->symbol_rate = p->delsys.dvbs.symbol_rate;
 	state->postlocked = 0;
 	state->tunedfreq = p->frequency;
 	return 0;
@@ -676,7 +869,20 @@ static int s5h1420_get_frontend(struct d
 	p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
 	p->inversion = s5h1420_getinversion(state);
 	p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state);
-	p->u.qpsk.fec_inner = s5h1420_getfec(state);
+	p->u.qpsk.fec_inner = s5h1420_getfec_compat(state);
+
+	return 0;
+}
+
+static int s5h1420_get_params(struct dvb_frontend* fe,
+			      struct dvbfe_params *p)
+{
+	struct s5h1420_state* state = fe->demodulator_priv;
+
+	p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
+	p->inversion = s5h1420_getinversion(state);
+	p->delsys.dvbs.symbol_rate = s5h1420_getsymbolrate(state);
+	p->delsys.dvbs.fec = s5h1420_getfec(state);
 
 	return 0;
 }
@@ -684,32 +890,59 @@ static int s5h1420_get_frontend(struct d
 static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
 				     struct dvb_frontend_tune_settings* fesettings)
 {
-	if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
-		fesettings->min_delay_ms = 50;
-		fesettings->step_size = 2000;
-		fesettings->max_drift = 8000;
-	} else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 1500;
-		fesettings->max_drift = 9000;
-	} else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 1000;
-		fesettings->max_drift = 8000;
-	} else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
-		fesettings->min_delay_ms = 100;
-		fesettings->step_size = 500;
-		fesettings->max_drift = 7000;
-	} else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
-		fesettings->min_delay_ms = 200;
-		fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
-		fesettings->max_drift = 14 * fesettings->step_size;
+	if (fe->legacy) {
+		if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+			fesettings->min_delay_ms = 50;
+			fesettings->step_size = 2000;
+			fesettings->max_drift = 8000;
+		} else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+			fesettings->min_delay_ms = 100;
+			fesettings->step_size = 1500;
+			fesettings->max_drift = 9000;
+		} else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+			fesettings->min_delay_ms = 100;
+			fesettings->step_size = 1000;
+			fesettings->max_drift = 8000;
+		} else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+			fesettings->min_delay_ms = 100;
+			fesettings->step_size = 500;
+			fesettings->max_drift = 7000;
+		} else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+			fesettings->min_delay_ms = 200;
+			fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+			fesettings->max_drift = 14 * fesettings->step_size;
+		} else {
+			fesettings->min_delay_ms = 200;
+			fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+			fesettings->max_drift = 18 * fesettings->step_size;
+		}
 	} else {
-		fesettings->min_delay_ms = 200;
-		fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
-		fesettings->max_drift = 18 * fesettings->step_size;
+		if (fesettings->fe_params.delsys.dvbs.symbol_rate > 20000000) {
+			fesettings->min_delay_ms = 50;
+			fesettings->step_size = 2000;
+			fesettings->max_drift = 8000;
+		} else if (fesettings->fe_params.delsys.dvbs.symbol_rate > 12000000) {
+			fesettings->min_delay_ms = 100;
+			fesettings->step_size = 1500;
+			fesettings->max_drift = 9000;
+		} else if (fesettings->fe_params.delsys.dvbs.symbol_rate > 8000000) {
+			fesettings->min_delay_ms = 100;
+			fesettings->step_size = 1000;
+			fesettings->max_drift = 8000;
+		} else if (fesettings->fe_params.delsys.dvbs.symbol_rate > 4000000) {
+			fesettings->min_delay_ms = 100;
+			fesettings->step_size = 500;
+			fesettings->max_drift = 7000;
+		} else if (fesettings->fe_params.delsys.dvbs.symbol_rate > 2000000) {
+			fesettings->min_delay_ms = 200;
+			fesettings->step_size = (fesettings->fe_params.delsys.dvbs.symbol_rate / 8000);
+			fesettings->max_drift = 14 * fesettings->step_size;
+		} else {
+			fesettings->min_delay_ms = 200;
+			fesettings->step_size = (fesettings->fe_params.delsys.dvbs.symbol_rate / 8000);
+			fesettings->max_drift = 18 * fesettings->step_size;
+		}
 	}
-
 	return 0;
 }
 
@@ -786,6 +1019,38 @@ error:
 	return NULL;
 }
 
+static struct dvbfe_info dvbs_info	= {
+	.name				= "Samsung S5H1420 DVB-S",
+	.delivery			= DVBFE_DELSYS_DVBS,
+	.delsys				= {
+		.dvbs.modulation	= DVBFE_DELSYS_DVBS,
+		.dvbs.fec		= DVBFE_FEC_1_2 | DVBFE_FEC_2_3 |
+					  DVBFE_FEC_3_4 | DVBFE_FEC_5_6 |
+					  DVBFE_FEC_7_8 | DVBFE_FEC_AUTO
+	},
+
+	.frequency_min			= 950000,
+	.frequency_max			= 2150000,
+	.frequency_step			= 125,
+	.frequency_tolerance		= 29500,
+	.symbol_rate_min		= 1000000,
+	.symbol_rate_max		= 45000000,
+};
+
+static int s5h1420_get_info(struct dvb_frontend *fe, struct dvbfe_info *fe_info)
+{
+	memcpy(fe_info, &dvbs_info, sizeof (dvbs_info));
+
+	return 0;
+}
+
+static int s5h1420_get_delsys(struct dvb_frontend *fe, enum dvbfe_delsys *fe_delsys)
+{
+	*fe_delsys = DVBFE_DELSYS_DVBS;
+
+	return 0;
+}
+
 static struct dvb_frontend_ops s5h1420_ops = {
 
 	.info = {
@@ -824,6 +1089,11 @@ static struct dvb_frontend_ops s5h1420_o
 	.diseqc_send_burst = s5h1420_send_burst,
 	.set_tone = s5h1420_set_tone,
 	.set_voltage = s5h1420_set_voltage,
+
+	.set_params	= s5h1420_set_params,
+	.get_params	= s5h1420_get_params,
+	.get_info	= s5h1420_get_info,
+	.get_delsys	= s5h1420_get_delsys,
 };
 
 module_param(debug, int, 0644);
_______________________________________________

linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux