[PATCH] add support for zl10313 into mt312-driver

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

 



Hi there!

The attached patches should add support for zl10313 chip to mt312-driver.

This driver now works for my A700 dvb-s card.

@Jan D. Louw: I used register write logs of your driver to compare them to 
mt312 driver. Maybe this driver works also for your Compro card.


01_mt312-fix-22k: Sets the correct diseqc frequency.
02_mt312-var-types: changes data types for read/write functions to u8* instead 
of void*.
03_mt312-changable-xtal: Handle xtal freq. and multiplicator in state instead 
of hardcoding them
04_mt312-add-zl10313-support.diff: Adds basic support for zl10313

Regards
Matthias
-- 
Matthias Schwarzott (zzam)
Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c
===================================================================
--- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312.c
+++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c
@@ -1,7 +1,8 @@
 /*
-    Driver for Zarlink VP310/MT312 Satellite Channel Decoder
+    Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder
 
     Copyright (C) 2003 Andreas Oberritter <obi@xxxxxxxxxxx>
+    Copyright (C) 2008 Matthias Schwarzott <zzam@xxxxxxxxxx>
 
     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
@@ -55,6 +56,7 @@ static int debug;
 	} while (0)
 
 #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
+#define MT312_PLL_CLK_10_111	10111000UL	/* 10.111 MHz */
 
 static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
 		      u8 *buf, const size_t count)
@@ -264,6 +266,32 @@ static int mt312_initfe(struct dvb_front
 			return ret;
 	}
 
+	switch (state->id) {
+	case ID_ZL10313:
+		/* enable ADC */
+		ret = mt312_writereg(state, GPP_CTRL, 0x80);
+		if (ret < 0)
+			return ret;
+
+		/* for optimal ADC performance according to datasheet */
+		buf[0] = 0x80;
+		buf[1] = 0xB0;
+		ret = mt312_write(state, HW_CTRL, buf, 2);
+		if (ret < 0)
+			return ret;
+
+		/* enable MPEG output */
+		ret = mt312_writereg(state, HW_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		ret = mt312_writereg(state, MPEG_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		break;
+	}
+
 	/* SYS_CLK */
 	buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000);
 
@@ -278,21 +306,28 @@ static int mt312_initfe(struct dvb_front
 	if (ret < 0)
 		return ret;
 
-	ret = mt312_writereg(state, OP_CTRL, 0x53);
-	if (ret < 0)
-		return ret;
+	switch (state->id) {
+	case ID_VP310:
+	case ID_MT312:
+		/* this code seems to prevent zl10313 from delivering useful data */
 
-	/* TS_SW_LIM */
-	buf[0] = 0x8c;
-	buf[1] = 0x98;
+		ret = mt312_writereg(state, OP_CTRL, 0x53);
+		if (ret < 0)
+			return ret;
 
-	ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
-	if (ret < 0)
-		return ret;
+		/* TS_SW_LIM */
+		buf[0] = 0x8c;
+		buf[1] = 0x98;
 
-	ret = mt312_writereg(state, CS_SW_LIM, 0x69);
-	if (ret < 0)
-		return ret;
+		ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
+		if (ret < 0)
+			return ret;
+
+		ret = mt312_writereg(state, CS_SW_LIM, 0x69);
+		if (ret < 0)
+			return ret;
+		break;
+	}
 
 	return 0;
 }
@@ -321,6 +356,9 @@ static int mt312_send_master_cmd(struct 
 	if (ret < 0)
 		return ret;
 
+	/* is this needed? */
+	msleep(100);
+
 	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
 	if (c->msg[0] & 0x02) {
 		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
@@ -492,6 +530,9 @@ static int mt312_set_frontend(struct dvb
 	int ret;
 	u8 buf[5], config_val;
 	u16 sr;
+	u32 real_frequency;
+	s16 foffset = 0;
+	s8 fr_off;
 
 	const u8 fec_tab[10] =
 	    { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f };
@@ -549,6 +590,7 @@ static int mt312_set_frontend(struct dvb
 		break;
 
 	case ID_MT312:
+	case ID_ZL10313:
 		break;
 
 	default:
@@ -561,6 +603,20 @@ static int mt312_set_frontend(struct dvb
 			fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
+#if 0
+	// should a demod handle this - or a tune algo call demod functions?
+	if (state->id == ID_ZL10313 && fe->ops.tuner_ops.get_frequency) {
+		fe->ops.tuner_ops.get_frequency(fe, &real_frequency);
+		foffset = p->frequency - real_frequency;
+		fr_off = foffset / 32;
+		dprintk("%s: Foffset %d -> %i\n", __FUNCTION__,
+			foffset, fr_off);
+		ret = mt312_writereg(state, FR_OFF, fr_off);
+		if (ret < 0)
+			return ret;
+	}
+#endif
+
 	/* sr = (u16)(sr * 256.0 / 1000000.0) */
 	sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
 
@@ -614,11 +670,25 @@ static int mt312_i2c_gate_ctrl(struct dv
 {
 	struct mt312_state *state = fe->demodulator_priv;
 
-	if (enable) {
-		return mt312_writereg(state, GPP_CTRL, 0x40);
-	} else {
-		return mt312_writereg(state, GPP_CTRL, 0x00);
-	}
+	u8 val = 0x00;
+	int ret;
+
+	ret = mt312_readreg(state, GPP_CTRL, &val);
+	if (ret < 0)
+		goto error;
+
+	/* just preserver this bit for now */
+//	val &= 0x80;
+
+	if (enable)
+		val |= 0x40;
+	else
+		val &= ~0x40;
+
+	ret = mt312_writereg(state, GPP_CTRL, val);
+
+error:
+	return ret;
 }
 
 static int mt312_sleep(struct dvb_frontend *fe)
@@ -632,6 +702,18 @@ static int mt312_sleep(struct dvb_fronte
 	if (ret < 0)
 		return ret;
 
+	if (state->id == ID_ZL10313) {
+		/* reset ADC */
+		ret = mt312_writereg(state, GPP_CTRL, 0x00);
+		if (ret < 0)
+			return ret;
+
+		/* shutdown ADCs and set mpeg bus to tristated */
+		ret = mt312_writereg(state, HW_CTRL, 0x0d);
+		if (ret < 0)
+			return ret;
+	}
+
 	ret = mt312_readreg(state, CONFIG, &config);
 	if (ret < 0)
 		return ret;
@@ -675,6 +757,7 @@ static struct dvb_frontend_ops vp310_mt3
 		    FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
 		    FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS |
 		    FE_CAN_RECOVER
+		    //| FE_CAN_INVERSION_AUTO
 	},
 
 	.release = mt312_release,
@@ -733,8 +816,13 @@ struct dvb_frontend *vp310_mt312_attach(
 		state->xtal = MT312_PLL_CLK;
 		state->freq_mult = 6;
 		break;
+	case ID_ZL10313:
+		strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
+		state->xtal = MT312_PLL_CLK_10_111;
+		state->freq_mult = 9;
+		break;
 	default:
-		printk(KERN_WARNING "Only Zarlink VP310/MT312"
+		printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313"
 			" are supported chips.\n");
 		goto error;
 	}
@@ -750,7 +838,7 @@ EXPORT_SYMBOL(vp310_mt312_attach);
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
-MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
+MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@xxxxxxxxxxx>");
 MODULE_LICENSE("GPL");
 
Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312_priv.h
===================================================================
--- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312_priv.h
+++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312_priv.h
@@ -110,6 +110,8 @@ enum mt312_reg_addr {
 	VIT_ERRPER_H = 83,
 	VIT_ERRPER_M = 84,
 	VIT_ERRPER_L = 85,
+	HW_CTRL = 84,	/* ZL10313 only */
+	MPEG_CTRL = 85,	/* ZL10313 only */
 	VIT_SETUP = 86,
 	VIT_REF0 = 87,
 	VIT_REF1 = 88,
@@ -156,7 +158,8 @@ enum mt312_reg_addr {
 
 enum mt312_model_id {
 	ID_VP310 = 1,
-	ID_MT312 = 3
+	ID_MT312 = 3,
+	ID_ZL10313 = 5,
 };
 
 #endif				/* DVB_FRONTENDS_MT312_PRIV */
Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c
===================================================================
--- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312.c
+++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c
@@ -43,7 +43,8 @@ struct mt312_state {
 	struct dvb_frontend frontend;
 
 	u8 id;
-	u8 frequency;
+	unsigned long xtal;
+	u8 freq_mult;
 };
 
 static int debug;
@@ -53,8 +54,6 @@ static int debug;
 			printk(KERN_DEBUG "mt312: " args); \
 	} while (0)
 
-#define MT312_SYS_CLK		90000000UL	/* 90 MHz */
-#define MT312_LPOWER_SYS_CLK	60000000UL	/* 60 MHz */
 #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
 
 static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
@@ -209,7 +208,7 @@ static int mt312_get_symbol_rate(struct 
 		dprintk("sym_rat_op=%d dec_ratio=%d\n",
 		       sym_rat_op, dec_ratio);
 		dprintk("*sr(manual) = %lu\n",
-		       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
+		       (((state->xtal * 8192) / (sym_rat_op + 8192)) *
 			2) - dec_ratio);
 	}
 
@@ -242,7 +241,7 @@ static int mt312_initfe(struct dvb_front
 
 	/* wake up */
 	ret = mt312_writereg(state, CONFIG,
-			(state->frequency == 60 ? 0x88 : 0x8c));
+			(state->freq_mult == 6 ? 0x88 : 0x8c));
 	if (ret < 0)
 		return ret;
 
@@ -266,11 +265,10 @@ static int mt312_initfe(struct dvb_front
 	}
 
 	/* SYS_CLK */
-	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK :
-				MT312_SYS_CLK) * 2, 1000000);
+	buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000);
 
 	/* DISEQC_RATIO */
-	buf[1] = mt312_div(MT312_PLL_CLK, 22000 * 4);
+	buf[1] = mt312_div(state->xtal, 22000 * 4);
 
 	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
 	if (ret < 0)
@@ -532,17 +530,17 @@ static int mt312_set_frontend(struct dvb
 			return ret;
 		if (p->u.qpsk.symbol_rate >= 30000000) {
 			/* Note that 30MS/s should use 90MHz */
-			if ((config_val & 0x0c) == 0x08) {
+			if (state->freq_mult == 6) {
 				/* We are running 60MHz */
-				state->frequency = 90;
+				state->freq_mult = 9;
 				ret = mt312_initfe(fe);
 				if (ret < 0)
 					return ret;
 			}
 		} else {
-			if ((config_val & 0x0c) == 0x0C) {
+			if (state->freq_mult == 9) {
 				/* We are running 90MHz */
-				state->frequency = 60;
+				state->freq_mult = 6;
 				ret = mt312_initfe(fe);
 				if (ret < 0)
 					return ret;
@@ -661,6 +659,7 @@ static void mt312_release(struct dvb_fro
 	kfree(state);
 }
 
+#define MT312_SYS_CLK		90000000UL	/* 90 MHz */
 static struct dvb_frontend_ops vp310_mt312_ops = {
 
 	.info = {
@@ -668,8 +667,8 @@ static struct dvb_frontend_ops vp310_mt3
 		.type = FE_QPSK,
 		.frequency_min = 950000,
 		.frequency_max = 2150000,
-		.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
-		.symbol_rate_min = MT312_SYS_CLK / 128,
+		.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, /* FIXME: adjust freq to real used xtal */
+		.symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
 		.symbol_rate_max = MT312_SYS_CLK / 2,
 		.caps =
 		    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
@@ -726,11 +725,13 @@ struct dvb_frontend *vp310_mt312_attach(
 	switch (state->id) {
 	case ID_VP310:
 		strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
-		state->frequency = 90;
+		state->xtal = MT312_PLL_CLK;
+		state->freq_mult = 9;
 		break;
 	case ID_MT312:
 		strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
-		state->frequency = 60;
+		state->xtal = MT312_PLL_CLK;
+		state->freq_mult = 6;
 		break;
 	default:
 		printk(KERN_WARNING "Only Zarlink VP310/MT312"
Corrects the frequency of the
emitted diseqc signal to 22kHz.

Signed-off-by: Matthias Schwarzott <zzam@xxxxxxxxxx>

Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c
===================================================================
--- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312.c
+++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c
@@ -270,7 +270,7 @@ static int mt312_initfe(struct dvb_front
 				MT312_SYS_CLK) * 2, 1000000);
 
 	/* DISEQC_RATIO */
-	buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
+	buf[1] = mt312_div(MT312_PLL_CLK, 22000 * 4);
 
 	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
 	if (ret < 0)
Index: v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c
===================================================================
--- v4l-dvb.orig/linux/drivers/media/dvb/frontends/mt312.c
+++ v4l-dvb/linux/drivers/media/dvb/frontends/mt312.c
@@ -58,7 +58,7 @@ static int debug;
 #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
 
 static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
-		      void *buf, const size_t count)
+		      u8 *buf, const size_t count)
 {
 	int ret;
 	struct i2c_msg msg[2];
@@ -84,7 +84,7 @@ static int mt312_read(struct mt312_state
 		int i;
 		dprintk("R(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
-			printk(" %02x", ((const u8 *) buf)[i]);
+			printk(" %02x", buf[i]);
 		printk("\n");
 	}
 
@@ -92,7 +92,7 @@ static int mt312_read(struct mt312_state
 }
 
 static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
-		       const void *src, const size_t count)
+		       const u8 *src, const size_t count)
 {
 	int ret;
 	u8 buf[count + 1];
@@ -102,7 +102,7 @@ static int mt312_write(struct mt312_stat
 		int i;
 		dprintk("W(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
-			printk(" %02x", ((const u8 *) src)[i]);
+			printk(" %02x", src[i]);
 		printk("\n");
 	}
 
@@ -463,7 +463,7 @@ static int mt312_read_snr(struct dvb_fro
 	int ret;
 	u8 buf[2];
 
-	ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf));
+	ret = mt312_read(state, M_SNR_H, buf, sizeof(buf));
 	if (ret < 0)
 		return ret;
 
@@ -478,7 +478,7 @@ static int mt312_read_ucblocks(struct dv
 	int ret;
 	u8 buf[2];
 
-	ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf));
+	ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf));
 	if (ret < 0)
 		return ret;
 
_______________________________________________
linux-dvb mailing list
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