zl10036 driver

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

 



Hi Tino! Hi list!

The crash was not in my code. So I can announce it now.

This is a driver for zl10036 tuner chip.
It works as far that I get a lock (with zl10313 demod).

Maybe the bandwidth handling may be improved (like feeding demod freq drift 
back into tuner and enlarging bandwidth with that value).

At least for this large tuning step size (2MHz for now, we maybe need to add 
2MHz or real difference to wanted freq to bandwidth filter).

Or just setting bandwidth to maximum for tuning and lower it once locked.
Implementing this can create a new tune algo instead of zig-zag: faster tuning 
in just one step :)

Regards
Matthias

-- 
Matthias Schwarzott (zzam)
Index: v4l-dvb/linux/drivers/media/dvb/frontends/Kconfig
===================================================================
--- v4l-dvb.orig/linux/drivers/media/dvb/frontends/Kconfig
+++ v4l-dvb/linux/drivers/media/dvb/frontends/Kconfig
@@ -330,6 +330,13 @@ config DVB_TUNER_QT1010
 	help
 	  A driver for the silicon tuner QT1010 from Quantek.
 
+config DVB_ZL1003X
+	tristate "Zarlink ZL1003X silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
 config DVB_TUNER_MT2060
 	tristate "Microtune MT2060 silicon IF tuner"
 	depends on I2C
Index: v4l-dvb/linux/drivers/media/dvb/frontends/Makefile
===================================================================
--- v4l-dvb.orig/linux/drivers/media/dvb/frontends/Makefile
+++ v4l-dvb/linux/drivers/media/dvb/frontends/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o
 obj-$(CONFIG_DVB_SP887X) += sp887x.o
 obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
 obj-$(CONFIG_DVB_MT352) += mt352.o
+obj-$(CONFIG_DVB_ZL1003X) += zl1003x.o
 obj-$(CONFIG_DVB_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_CX22702) += cx22702.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
Index: v4l-dvb/linux/drivers/media/dvb/frontends/zl1003x.c
===================================================================
--- /dev/null
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl1003x.c
@@ -0,0 +1,692 @@
+/**
+ * Driver for Zarlink zl1003x DVB-S silicon tuner
+ *
+ * Copyright (C) 2006 Tino Reichardt
+ * Copyright (C) 2007 Matthias Schwarzott <zzam@xxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **
+ * The data sheet for this tuner can be found at:
+ *    http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf
+ *
+ * This one is working: (at my Avermedia DVB-S Pro)
+ * - zl10036 (40pin, FTA)
+ *
+ * These are planned:
+ * - zl10038 (40pin, FTA with DVB-S2 - nearly the same as zl10036)
+ * - zl10037 (28pin, with pay tv support)
+ * - zl10039 (28pin, FTA)
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "zl1003x.h"
+
+static int zl1003x_debug;
+#define dprintk(level, args...) \
+	do { if (zl1003x_debug & level) printk(KERN_DEBUG "zl1003x: " args); \
+	} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define deb_i2c(args...)  dprintk(0x02, args)
+
+struct zl1003x_state {
+	struct i2c_adapter *i2c;
+	const struct zl1003x_config *config;
+	u32 frequency;
+	u8 br, bf;
+};
+
+
+/* This driver assumes the tuner is driven by a 10.111MHz Cristal */
+#define _XTAL 10111
+
+#if 0
+/* Using a divider of 64 leads to a reference Frequency/step size of 158kHz */
+#define _RDIV 64
+#define _RDIV_REG 0x05
+#elif 0
+/* Using a divider of 10 leads to a reference Frequency/step size of 1011kHz */
+#define _RDIV 10
+#define _RDIV_REG 0x0a
+#else
+/* Using a divider of 10 leads to a reference Frequency/step size of 2022kHz */
+#define _RDIV 5
+#define _RDIV_REG 0x09
+#endif
+
+#define _FR   (_XTAL/_RDIV)
+
+#define STATUS_POR 0x80
+#define STATUS_FL  0x40
+
+/* read/write for zl10036 and zl10038 */
+
+static int zl10036_read_status_reg(struct zl1003x_state *state)
+{
+	u8 status;
+	struct i2c_msg msg[1] = {
+		{ .addr = state->config->tuner_address, .flags = I2C_M_RD,
+		  .buf = &status, .len = sizeof(status) },
+	};
+
+	if (i2c_transfer(state->i2c, msg, 1) != 1) {
+		printk(KERN_ERR "%s: i2c read failed at addr=%02x\n",
+			__FUNCTION__, state->config->tuner_address);
+		return -EIO;
+	}
+
+	deb_i2c("R(status): %02x  [FL=%d]\n", status,
+		(status & STATUS_FL) ? 1 : 0);
+	if (status & STATUS_POR)
+		deb_info("zl1003x: Power-On-Reset bit enabled - "
+			"may need to reinitialize tuner\n");
+
+	return status;
+}
+
+
+static int zl10036_write(struct zl1003x_state *state, u8 buf[], u8 count)
+{
+	struct i2c_msg msg[1] = {
+		{ .addr = state->config->tuner_address, .flags = 0,
+		  .buf = buf, .len = count },
+	};
+	u8 reg = 0;
+	int ret;
+
+	if (zl1003x_debug & 0x02) {
+		/* every 8bit-value satisifes this!
+		 * so only do on debug */
+		     if ((buf[0] & 0x80) == 0x00) reg = 2;
+		else if ((buf[0] & 0xc0) == 0x80) reg = 4;
+		else if ((buf[0] & 0xf0) == 0xc0) reg = 6;
+		else if ((buf[0] & 0xf0) == 0xd0) reg = 8;
+		else if ((buf[0] & 0xf0) == 0xe0) reg = 10;
+		else if ((buf[0] & 0xf0) == 0xf0) reg = 12;
+
+		deb_i2c("W(%d):", reg);
+		{
+			int i;
+			for (i = 0; i < count; i++)
+				printk(" %02x", buf[i]);
+			printk("\n");
+		}
+	}
+
+	ret = i2c_transfer(state->i2c, msg, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "%s: i2c error, ret=%d\n", __FUNCTION__, ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#if 0
+/* read/write for zl10037, zl10039 and Intel CE503x */
+static int zl10037_readreg(struct zl1003x_state *state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg[2] = {
+		{ .addr = state->config->tuner_address, .flags = 0,
+		  .buf = b0, .len = 1 },
+		{ .addr = state->config->tuner_address, .flags = I2C_M_RD,
+		  .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2) {
+		printk(KERN_ERR "%s: i2c read failed at addr=%02x reg=%d\n",
+			__FUNCTION__, state->config->tuner_address, reg);
+		return ret;
+	}
+
+	deb_i2c("R(%d): %02x\n", reg, b1[0]);
+
+	return b1[0];
+}
+
+static int zl10037_write(struct zl1003x_state *state, u8 buf[], u8 count)
+{
+	struct i2c_msg msg[1] = {
+		{ .addr = state->config->tuner_address, .flags = 0,
+		  .buf = buf, .len = count },
+	};
+	int ret;
+
+	if (zl1003x_debug & 0x02) {
+		deb_i2c("W(%d):", buf[0]);
+		{
+			int i;
+			for (i = 1; i < count; i++)
+				printk(" %02x", buf[i]);
+			printk("\n");
+		}
+	}
+	ret = i2c_transfer(state->i2c, msg, 1);
+	if (ret != 1) {
+		printk(KERN_ERR "%s: i2c error, ret=%d\n", __FUNCTION__, ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+#endif
+
+static int zl1003x_release(struct dvb_frontend *fe)
+{
+	struct zl1003x_state *state = fe->tuner_priv;
+
+	deb_info("%s\n", __FUNCTION__);
+
+	fe->tuner_priv = NULL;
+	kfree(state);
+
+	return 0;
+}
+
+static int zl1003x_sleep(struct dvb_frontend *fe)
+{
+	struct zl1003x_state *state = fe->tuner_priv;
+	u8 buf[] = { 0xf0, 0x80 }; /* regs 12/13 */
+	int ret;
+
+	deb_info("%s\n", __FUNCTION__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = zl10036_write(state, buf, sizeof(buf));
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+/**
+ * register map of the ZL10036/ZL10038
+ *
+ * reg[default] content
+ *  2[0x00]:   0 | N14 | N13 | N12 | N11 | N10 |  N9 |  N8
+ *  3[0x00]:  N7 |  N6 |  N5 |  N4 |  N3 |  N2 |  N1 |  N0
+ *  4[0x80]:   1 |   0 | RFG | BA1 | BA0 | BG1 | BG0 | LEN
+ *  5[0x00]:  P0 |  C1 |  C0 |  R4 |  R3 |  R2 |  R1 |  R0
+ *  6[0xc0]:   1 |   1 |   0 |   0 | RSD |   0 |   0 |   0
+ *  7[0x20]:  P1 | BF6 | BF5 | BF4 | BF3 | BF2 | BF1 |   0
+ *  8[0xdb]:   1 |   1 |   0 |   1 |   0 |  CC |   1 |   1
+ *  9[0x30]: VSD |  V2 |  V1 |  V0 |  S3 |  S2 |  S1 |  S0
+ * 10[0xe1]:   1 |   1 |   1 |   0 |   0 | LS2 | LS1 | LS0
+ * 11[0xf5]:  WS | WH2 | WH1 | WH0 | WL2 | WL1 | WL0 | WRE
+ * 12[0xf0]:   1 |   1 |   1 |   1 |   0 |   0 |   0 |   0
+ * 13[0x28]:  PD | BR4 | BR3 | BR2 | BR1 | BR0 | CLR |  TL
+ */
+
+
+static int zl1003x_set_frequency(struct zl1003x_state *state, u32 frequency)
+{
+	u8 buf[2];
+	u32 div, foffset;
+
+	div = (frequency + _FR/2) / _FR;
+	state->frequency = div * _FR;
+
+	foffset = frequency - state->frequency;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = (div >> 0) & 0xff;
+
+	deb_info("%s: ftodo=%u fpriv=%u ferr=%d div=%u\n", __FUNCTION__,
+		frequency, state->frequency, foffset, div);
+
+	return zl10036_write(state, buf, sizeof(buf));
+}
+
+static int zl1003x_set_bandwidth(struct zl1003x_state *state, u32 fbw)
+{
+	/* fbw is measured in kHz */
+	u8 br, bf;
+	int ret;
+	u8 buf_bf[] = {
+		0xc0, 0x00, /*   6/7: rsd=0 bf=0 */
+	};
+	u8 buf_br[] = {
+		0xf0, 0x00, /* 12/13: br=0xa clr=0 tl=0*/
+	};
+	u8 zl10036_rsd_off[] = { 0xc8 }; /* set RSD=1 */
+
+	/* ensure correct values */
+	if (fbw > 35000)
+		fbw = 35000;
+	if (fbw <  8000)
+		fbw =  8000;
+
+#define _BR_MAXIMUM (_XTAL/575) /* _XTAL / 575kHz = 17 */
+
+	/* <= 28,82 MHz */
+	if (fbw <= 28820) {
+		br = _BR_MAXIMUM;
+	} else {
+		/**
+		 *  f(bw)=34,6MHz f(xtal)=10.111MHz
+		 *  br = (10111/34600) * 63 * 1/K = 14;
+		 */
+#if 0
+		br = ((_XTAL * 63 * 1000) / (fbw * 1257));
+#endif
+		br = ((_XTAL * 21 * 1000) / (fbw * 419));
+	}
+
+	/* ensure correct values */
+	if (br < 4)
+		br = 4;
+	if (br > _BR_MAXIMUM)
+		br = _BR_MAXIMUM;
+
+	/*
+	 * k = 1.257
+	 * bf = fbw/_XTAL * br * k - 1 */
+
+	bf = (fbw * br * 1257) / (_XTAL * 1000) - 1;
+
+	/* ensure correct values */
+	if (bf > 62)
+		bf = 62;
+
+	buf_bf[1] = (bf << 1) & 0x7e;
+	buf_br[1] = (br << 2) & 0x7c;
+	deb_info("%s: BW=%d br=%u bf=%u\n", __FUNCTION__, fbw, br, bf);
+
+	if (br != state->br) {
+		ret = zl10036_write(state, buf_br, sizeof(buf_br));
+		if (ret < 0)
+			return ret;
+	}
+
+	if (bf != state->bf) {
+		ret = zl10036_write(state, buf_bf, sizeof(buf_bf));
+		if (ret < 0)
+			return ret;
+
+		/* time = br/(32* fxtal) */
+		/* minimal sleep time to be calculated
+		 * maximum br is 63 -> max time = 2 /10 MHz = 2e-7 */
+		msleep(1);
+
+		ret = zl10036_write(state, zl10036_rsd_off,
+			sizeof(zl10036_rsd_off));
+		if (ret < 0)
+			return ret;
+	}
+
+	/* disable this optimization for now */
+#if 0
+	state->br = br;
+	state->bf = bf;
+#endif
+
+	return 0;
+}
+
+static int zl1003x_set_gain_params(struct zl1003x_state *state,
+	int c)
+{
+	u8 buf[2];
+	u8 rfg, ba, bg;
+
+	/* default values */
+	rfg = 0;
+	ba = 0;
+	bg = 0;
+
+	/* reg 4 */
+	buf[0] = 0x80 | ((rfg << 5) & 0x20)
+		| ((ba  << 3) & 0x18) | ((bg  << 1) & 0x06);
+
+	if (!state->config->rf_loop_enable)
+		buf[0] |= 0x01;
+
+	/* P0=0 */
+	buf[1] = _RDIV_REG | ((c << 5) & 0x60);
+
+	deb_info("%s: c=%u\n", __FUNCTION__, c);
+	return zl10036_write(state, buf, sizeof(buf));
+}
+
+static int zl1003x_set_params(struct dvb_frontend *fe, struct
+		dvb_frontend_parameters *params)
+{
+	struct zl1003x_state *state = fe->tuner_priv;
+	int ret = 0;
+	u32 frequency = params->frequency;
+	u32 fbw;
+	int i;
+	u8 c;
+
+	/* ensure correct values
+	 * maybe redundant as core already checks this */
+	if ((frequency < fe->ops.info.frequency_min)
+	||  (frequency > fe->ops.info.frequency_max))
+		return -EINVAL;
+
+	/**
+	 * alpha = 1.35 for dvb-s
+	 * fBW = (alpha*symbolrate)/(2*0.8)
+	 * 1.35 / (2*0.8) = 1.35 / 1.6 = 135 / 160 = 27 / 32
+	 */
+	fbw = (27 * params->u.qpsk.symbol_rate) / 32;
+
+	/* scale to kHz */
+	fbw /= 1000;
+
+	/* Maybe usefull later: add freq drift */
+	// fbw += 1000;
+
+
+	/* Set maximal bandwidth */
+	//fbw = 35000;
+
+	/* setting the charge pump - guessed values!  */
+	if (frequency < 950000)
+		return -EINVAL;
+	else if (frequency < 1250000)
+		c = 0;
+	else if (frequency < 1750000)
+		c = 1;
+	else if (frequency < 2175000)
+		c = 2;
+	else
+		return -EINVAL;
+
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = zl1003x_set_gain_params(state, c);
+	if (ret < 0)
+		goto error;
+
+	ret = zl1003x_set_frequency(state, params->frequency);
+	if (ret < 0)
+		goto error;
+
+	ret = zl1003x_set_bandwidth(state, fbw);
+	if (ret < 0)
+		goto error;
+
+	/* wait for tuner lock - no idea if this is really needed */
+	for (i = 0; i < 20; i++) {
+		ret = zl10036_read_status_reg(state);
+		if (ret < 0)
+			goto error;
+
+		/* check Frequency & Phase Lock Bit */
+		if (ret & STATUS_FL)
+			break;
+
+		msleep(10);
+	}
+
+error:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+static int zl1003x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct zl1003x_state *state = fe->tuner_priv;
+
+	*frequency = state->frequency;
+
+	return 0;
+}
+
+#if 0
+static int zl10036_set_voltage_windows(struct dvb_frontend *fe)
+{
+	struct zl1003x_state *state = fe->tuner_priv;
+
+	/* 10/11: from datasheet - lock window levels */
+	u8 buf1[2] = { 0xe3, 0x5b };
+
+	/* 10/11: from datasheet - unlock window levels */
+	u8 buf2[2] = { 0xe3, 0xf9 };
+	int ret;
+
+	ret = zl10036_write(state, buf1, sizeof(buf1));
+	if (ret < 0)
+		return ret;
+
+	ret = zl10036_write(state, buf2, sizeof(buf2));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int zl10036_init_regs(struct dvb_frontend *fe)
+{
+	struct zl1003x_state *state = fe->tuner_priv;
+	int ret;
+
+	u8 init_tab[] = { 0xd3, 0x40 }; /* 8/9: from datasheet */
+
+	/* invalid values to trigger writing */
+	state->br = 0xff;
+	state->bf = 0xff;
+
+	deb_info("%s\n", __FUNCTION__);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	/* write a valid frequency - 1000MHz */
+	ret = zl1003x_set_frequency(fe, 1000000);
+	if (ret < 0)
+		return ret;
+
+	/* set maximum bandwidth */
+	ret = zl1003x_set_bandwidth(fe, 35000);
+	if (ret < 0)
+		return ret;
+
+	ret = zl1003x_set_gain_params(fe, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = zl10036_set_voltage_windows(fe);
+	if (ret < 0)
+		return ret;
+
+	ret = zl10036_write(state, init_tab, sizeof(init_tab));
+	if (ret < 0)
+		return ret;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return 0;
+}
+#else
+
+static int zl10036_init_regs(struct zl1003x_state *state)
+{
+	int ret;
+	int i;
+
+	/* could also be one block from 2 to 13 and additional 10/11 */
+	u8 zl10036_init_tab[][2] = {
+		{ 0x04, 0x00 },		/*   2/3: div=0x400 - arbitrary value */
+		{ 0x8b, _RDIV_REG },	/*   4/5: rfg=0 ba=1 bg=1 len=? */
+					/*        p0=0 c=0 r=_RDIV_REG */
+		{ 0xc0, 0x20 },		/*   6/7: rsd=0 bf=0x10 */
+		{ 0xd3, 0x40 },		/*   8/9: from datasheet */
+		{ 0xe3, 0x5b },		/* 10/11: lock window level */
+		{ 0xf0, 0x28 },		/* 12/13: br=0xa clr=0 tl=0*/
+		{ 0xe3, 0xf9 },		/* 10/11: unlock window level */
+	};
+
+
+
+	/* invalid values to trigger writing */
+	state->br = 0xff;
+	state->bf = 0xff;
+
+	if (!state->config->rf_loop_enable)
+		zl10036_init_tab[1][2] |= 0x01;
+
+	deb_info("%s\n", __FUNCTION__);
+
+	for (i = 0; i < ARRAY_SIZE(zl10036_init_tab); i++) {
+		ret = zl10036_write(state, zl10036_init_tab[i], 2);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+#endif
+
+static int zl10036_init(struct dvb_frontend *fe)
+{
+	struct zl1003x_state *state = fe->tuner_priv;
+	int ret = 0;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	/* error handling? */
+	ret = zl10036_read_status_reg(state);
+
+#if 0
+	/* only init if Power-on-Reset bit is set */
+	if (ret & STATUS_POR)
+		zl10036_init_regs(fe);
+#else
+	ret = zl10036_init_regs(state);
+#endif
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	return ret;
+}
+
+static struct dvb_tuner_ops zl1003x_tuner_ops = {
+	.info = {
+		.name = "Unknown Tuner",
+		.frequency_min = 950000,
+		.frequency_max = 2175000
+	},
+	.init = zl10036_init,
+	.release = zl1003x_release,
+	.sleep = zl1003x_sleep,
+	.set_params = zl1003x_set_params,
+	.get_frequency = zl1003x_get_frequency,
+};
+
+static char *zl1003x_part[] = {
+	[ZL1003X_TYPE_ZL10036] = "Zarlink ZL10036",
+	[ZL1003X_TYPE_ZL10037] = "Zarlink ZL10037",
+	[ZL1003X_TYPE_ZL10038] = "Zarlink ZL10038",
+	[ZL1003X_TYPE_ZL10039] = "Zarlink ZL10039",
+	[ZL1003X_TYPE_CE5037]  = "Intel CE5037",
+	[ZL1003X_TYPE_CE5039]  = "Intel CE5039",
+};
+
+struct dvb_frontend *zl1003x_attach(struct dvb_frontend *fe,
+				    const struct zl1003x_config *config,
+				    struct i2c_adapter *i2c)
+{
+	struct zl1003x_state *state = NULL;
+	int ret;
+	const char *name = NULL;
+
+	if (NULL == config) {
+		printk(KERN_ERR "%s: no config specified", __FUNCTION__);
+		goto error;
+	}
+
+	if (config->type < ARRAY_SIZE(zl1003x_part))
+		name = zl1003x_part[config->type];
+
+	if (NULL == name)
+		name = "Missing name";
+
+	switch (config->type) {
+	case ZL1003X_TYPE_ZL10036:
+		break;
+	default:
+		printk(KERN_WARNING "%s: Warning, unsupported silicon tuner"
+			" (type: %s)!\n", __FUNCTION__, name);
+		goto error;
+	}
+
+	state = kzalloc(sizeof(struct zl1003x_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->config = config;
+	state->i2c = i2c;
+
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+	ret = zl10036_read_status_reg(state);
+	if (ret < 0) {
+		printk(KERN_ERR "%s: No zl1003x found\n", __FUNCTION__);
+		goto error;
+	}
+
+	ret = zl10036_init_regs(state);
+	if (ret < 0) {
+		printk(KERN_ERR "%s: tuner initialization failed\n",
+			__FUNCTION__);
+		goto error;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+	fe->tuner_priv = state;
+
+	memcpy(&fe->ops.tuner_ops, &zl1003x_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+	strcpy(fe->ops.tuner_ops.info.name, name);
+	printk(KERN_INFO "%s: tuner initialization (%s addr=0x%02x) ok\n",
+		__FUNCTION__, name, config->tuner_address);
+
+	return fe;
+
+error:
+	zl1003x_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL(zl1003x_attach);
+
+module_param_named(debug, zl1003x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("DVB ZL1003X driver");
+MODULE_AUTHOR("Tino Reichardt");
+MODULE_AUTHOR("Matthias Schwarzott");
+MODULE_LICENSE("GPL");
Index: v4l-dvb/linux/drivers/media/dvb/frontends/zl1003x.h
===================================================================
--- /dev/null
+++ v4l-dvb/linux/drivers/media/dvb/frontends/zl1003x.h
@@ -0,0 +1,65 @@
+/**
+ * Driver for Zarlink ZL10036 DVB-S silicon tuner
+ *
+ * Copyright (C) 2006 Tino Reichardt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DVB_ZL1003X_H
+#define DVB_ZL1003X_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a zl10036 tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param config zl1003x_config structure
+ * @return FE pointer on success, NULL on failure.
+ */
+
+enum zl1003x_chip_type {
+	UNDEFINED,
+	ZL1003X_TYPE_ZL10036,
+	ZL1003X_TYPE_ZL10037,
+	ZL1003X_TYPE_ZL10038,
+	ZL1003X_TYPE_ZL10039,
+	ZL1003X_TYPE_CE5037,
+	ZL1003X_TYPE_CE5039,
+};
+
+struct zl1003x_config {
+	u8 tuner_address;
+	int rf_loop_enable;
+	enum zl1003x_chip_type type;
+#if 0
+	uint output_ports:2;
+#endif
+};
+
+#if defined(CONFIG_DVB_ZL1003X) || (defined(CONFIG_DVB_ZL1003X_MODULE) && defined(MODULE))
+extern struct dvb_frontend *zl1003x_attach(struct dvb_frontend *fe,
+	const struct zl1003x_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *zl1003x_attach(struct dvb_frontend *fe,
+	const struct zl1003x_config *config, struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* DVB_ZL1003X_H */
_______________________________________________
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