Re: [patch 0/5] mt312: Add support for zl10313 demod

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

 



On Sunday 27 April 2008 05:51:30 Matthias Schwarzott wrote:
> On Samstag, 26. April 2008, Jan Louw wrote:
> > Hi Matthias,
> >
> > It still works. I combined your zl10313 modulator patch  with my earlier
> > zl10039 frontend patch. The additional modifications necesary are in (see
> > previous patch):
> >
> > ~/schwarzottv4l/v4l-dvb $ hg status
> > M linux/drivers/media/dvb/frontends/Kconfig
> > M linux/drivers/media/dvb/frontends/Makefile
> > M linux/drivers/media/video/saa7134/Kconfig
> > M linux/drivers/media/video/saa7134/saa7134-cards.c
> > M linux/drivers/media/video/saa7134/saa7134-dvb.c
> > M linux/drivers/media/video/saa7134/saa7134.h
> > A linux/drivers/media/dvb/frontends/zl10039.c
> > A linux/drivers/media/dvb/frontends/zl10039.h
> > A linux/drivers/media/dvb/frontends/zl10039_priv.h
> >
> > To keep it simple I omitted the previous remote control code.
>
> As you see here my zl10036 driver seems to work to some point:
> http://thread.gmane.org/gmane.linux.drivers.dvb/41015/focus=41303
>
> Could you please mail your current driver for zl10039.
> Maybe it is worth merging both.
>
> Regards
> Matthias

Hi Matthias,

Here's the zl10039 driver. With the zl10039 I did not bother with offsets or 
gains - even the weak channels lock stable :-)

I used a constant bandwidth resolution of 200KHz (reference divider of 10) and 
a PLL frequency divider of 80.

Regards
JD




/*
 *  Driver for Zarlink ZL10039 DVB-S tuner
 *
 *  Copyright 2007 Jan Dani�Louw <jd.louw@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
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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.=
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/dvb/frontend.h>

#include "dvb_frontend.h"
#include "zl10039.h"
#include "zl10039_priv.h"


static int zl10039_read(const struct zl10039_state *state,
			const enum zl10039_reg_addr reg, u8 *buf,
			const size_t count)
{
	struct i2c_msg msg[2];
	u8 regbuf[1] = { reg };
	int i;

	io_printk("%s\n", __FUNCTION__);
	/* Write register address */
	msg[0].addr = state->config.tuner_address;
	msg[0].flags = 0;
	msg[0].buf = regbuf;
	msg[0].len = 1;
	/* Read count bytes */
	msg[1].addr = state->config.tuner_address;
	msg[1].flags = I2C_M_RD;
	msg[1].buf = buf;
	msg[1].len = count;
	if (i2c_transfer(state->i2c, msg, 2) != 2) {
		eprintk("%s: i2c read error\n", __FUNCTION__);
		return -EREMOTEIO;
	}
	for (i = 0; i < count; i++) {
		io_printk("R[%s] = 0x%x\n", zl10039_reg_names[reg + i], buf[i]);
	}
	return 0; /* Success */
}

static int zl10039_write(struct zl10039_state *state,
			const enum zl10039_reg_addr reg, const u8 *src,
			const size_t count)
{
	u8 buf[count + 1];
	struct i2c_msg msg;
	int i;

	io_printk("%s\n", __FUNCTION__);
	for (i = 0; i < count; i++) {
		io_printk("W[%s] = 0x%x\n", zl10039_reg_names[reg + i], src[i]);
	}
	/* Write register address and data in one go */
	buf[0] = reg;
	memcpy(&buf[1], src, count);
	msg.addr = state->config.tuner_address;
	msg.flags = 0;
	msg.buf = buf;
	msg.len = count + 1;
	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
		eprintk("%s: i2c write error\n", __FUNCTION__);
		return -EREMOTEIO;
	}
	return 0; /* Success */
}

static inline int zl10039_readreg(struct zl10039_state *state,
				const enum zl10039_reg_addr reg, u8 *val)
{
	return zl10039_read(state, reg, val, 1);
}

static inline int zl10039_writereg(struct zl10039_state *state,
				const enum zl10039_reg_addr reg,
				const u8 val)
{
	return zl10039_write(state, reg, &val, 1);
}

static int zl10039_init(struct dvb_frontend *fe)
{
	struct zl10039_state *state = fe->tuner_priv;
	int ret;

	trace_printk("%s\n", __FUNCTION__);
	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
	/* Reset logic */
	ret = zl10039_writereg(state, GENERAL, 0x40);
	if (ret < 0) {
		eprintk("Note: i2c write error normal when resetting the "
			"tuner\n");
	}
	/* Wake up */
	ret = zl10039_writereg(state, GENERAL, 0x01);
	if (ret < 0) {
		eprintk("Tuner power up failed\n");
		return ret;
	}
	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
	return 0;
}

static int zl10039_sleep(struct dvb_frontend *fe)
{
	struct zl10039_state *state = fe->tuner_priv;
	int ret;

	trace_printk("%s\n", __FUNCTION__);
	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
	ret = zl10039_writereg(state, GENERAL, 0x80);
	if (ret < 0) {
		eprintk("Tuner sleep failed\n");
		return ret;
	}
	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
	return 0;
}

static int zl10039_set_params(struct dvb_frontend *fe,
			struct dvb_frontend_parameters *params)
{
	struct zl10039_state *state = fe->tuner_priv;
	u8 buf[6];
	u8 bf;
	u32 fbw;
	u32 div;
	int ret;

	trace_printk("%s\n", __FUNCTION__);
	params_printk("Set frequency = %d, symbol rate = %d\n",
			params->frequency, params->u.qpsk.symbol_rate);

	/* Assumed 10.111 MHz crystal oscillator */
	/* Cancelled num/den 80 to prevent overflow */
	div = (params->frequency * 1000) / 126387;
	fbw = (params->u.qpsk.symbol_rate * 27) / 32000;
	/* Cancelled num/den 10 to prevent overflow */
	bf = ((fbw * 5088) / 1011100) - 1;

	/*PLL divider*/
	buf[0] = (div >> 8) & 0x7f;
	buf[1] = (div >> 0) & 0xff;
	/*Reference divider*/
	/* Select reference ratio of 80 */
	buf[2] = 0x1D;
	/*PLL test modes*/
	buf[3] = 0x40;
	/*RF Control register*/
	buf[4] = 0x6E; /* Bypass enable */
	/*Baseband filter cutoff */
	buf[5] = bf;

	/* Open i2c gate */
	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
	/* BR = 10, Enable filter adjustment */
	ret = zl10039_writereg(state, BASE1, 0x0A);
	if (ret < 0) goto error;
	/* Write new config values */
	ret = zl10039_write(state, PLL0, buf, sizeof(buf));
	if (ret < 0) goto error;
	/* BR = 10, Disable filter adjustment */
	ret = zl10039_writereg(state, BASE1, 0x6A);
	if (ret < 0) goto error;

	zl10039_dump_registers(state);
	/* Close i2c gate */
	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
	return 0;
error:
	eprintk("Error setting tuner\n");
	return ret;
}

static struct dvb_tuner_ops zl10039_ops;

struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
		const struct zl10039_config *config, struct i2c_adapter *i2c)
{
	struct zl10039_state *state = NULL;

	trace_printk("%s\n", __FUNCTION__);
	state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL);
	if (state == NULL) goto error;

	state->i2c = i2c;
	state->config.tuner_address = config->tuner_address;

	/* Open i2c gate */
	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
	/* check if this is a valid tuner */
	if (zl10039_readreg(state, GENERAL, &state->id) < 0) {
		/* Close i2c gate */
		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
		goto error;
	}
	/* Close i2c gate */
	if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);

	state->id = state->id & 0x0F;
	switch (state->id) {
	case ID_ZL10039:
		strcpy(fe->ops.tuner_ops.info.name,
			"Zarlink ZL10039 DVB-S tuner");
		break;
	default:
		eprintk("Chip ID does not match a known type\n");
		goto error;
	}
	memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops));
	fe->tuner_priv = state;
	iprintk("Tuner attached @ i2c address 0x%02x\n", config->tuner_address);
	return fe;
error:
	kfree(state);
	return NULL;
}

static int zl10039_release(struct dvb_frontend *fe)
{
	struct zl10039_state *state = fe->tuner_priv;

	trace_printk("%s\n", __FUNCTION__);
	kfree(state);
	fe->tuner_priv = NULL;
	return 0;
}

static struct dvb_tuner_ops zl10039_ops = {
	.release = zl10039_release,
	.init = zl10039_init,
	.sleep = zl10039_sleep,
	.set_params = zl10039_set_params,
};

EXPORT_SYMBOL(zl10039_attach);

MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver");
MODULE_AUTHOR("Jan Dani�Louw <jd.louw@xxxxxxxxxx>");
MODULE_LICENSE("GPL");
/*
    Driver for Zarlink ZL10039 DVB-S tuner

    Copyright (C) 2007 Jan Dani�Louw <jd.louw@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
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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 ZL10039_H
#define ZL10039_H

struct zl10039_config
{
	/* tuner's i2c address */
	u8 tuner_address;
};

#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \
	    && defined(MODULE))
struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
					const struct zl10039_config *config,
					struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
					const struct zl10039_config *config,
					struct i2c_adapter *i2c)
{
	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
	return NULL;
}
#endif /* CONFIG_DVB_ZL10039 */

#endif /* ZL10039_H */
/*
 *  Driver for Zarlink ZL10039 DVB-S tuner
 *
 *  Copyright 2007 Jan Dani�Louw <jd.louw@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
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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_FRONTENDS_ZL10039_PRIV
#define DVB_FRONTENDS_ZL10039_PRIV

/* Trace function calls */
#define DEBUG_CALL_TRACE	0
/* Trace read/write function calls - information overload */
#define DEBUG_IO_TRACE		0
/* Print register values at critical points */
#define DEBUG_DUMP_REGISTERS	0
/* Print important params passed to functions */
#define DEBUG_PRINT_PARAMS	0

#if DEBUG_CALL_TRACE
	#define trace_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " args)
#else
	#define trace_printk(args...)
#endif

#if DEBUG_IO_TRACE
	#define io_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " args)
#else
	#define io_printk(args...)
#endif

#if DEBUG_PRINT_PARAMS
	#define params_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " \
						args)
#else
	#define params_printk(args...)
#endif

#define eprintk(args...) printk(KERN_ERR "tuner: zl10039: " args)
#define iprintk(args...) printk(KERN_INFO "tuner: zl10039: " args)

enum zl10039_model_id {
	ID_ZL10039 = 1
};

struct zl10039_state {
	struct i2c_adapter *i2c;
	struct zl10039_config config;
	u8 id;
};

enum zl10039_reg_addr {
	PLL0 = 0,
	PLL1,
	PLL2,
	PLL3,
	RFFE,
	BASE0,
	BASE1,
	BASE2,
	LO0,
	LO1,
	LO2,
	LO3,
	LO4,
	LO5,
	LO6,
	GENERAL
};

#if DEBUG_DUMP_REGISTERS || DEBUG_IO_TRACE
static const char *zl10039_reg_names[] = {
	"PLL_0", "PLL_1", "PLL_2", "PLL_3",
	"RF_FRONT_END", "BASE_BAND_0", "BASE_BAND_1", "BASE_BAND_2",
	"LOCAL_OSC_0", "LOCAL_OSC_1", "LOCAL_OSC_2", "LOCAL_OSC_3",
	"LOCAL_OSC_4", "LOCAL_OSC_5", "LOCAL_OSC_6", "GENERAL"
};
#endif

#if DEBUG_DUMP_REGISTERS
static int zl10039_read(const struct zl10039_state *state,
			const enum zl10039_reg_addr reg, u8 *buf,
			const size_t count);

static void zl10039_dump_registers(const struct zl10039_state *state)
{
	u8 buf[16];
	int ret;
	u8 reg;

	trace_printk("%s\n", __FUNCTION__);
	ret = zl10039_read(state, PLL0, buf, sizeof(buf));
	if (ret < 0) return;
	for (reg = PLL0; reg <= GENERAL; reg += 4) {
		printk(KERN_DEBUG "%03x: [%02x %13s] [%02x %13s] [%02x %13s] "
			"[%02x %13s]\n", reg, buf[reg], zl10039_reg_names[reg],
			buf[reg+1], zl10039_reg_names[reg+1], buf[reg+2],
			zl10039_reg_names[reg+2], buf[reg+3],
			zl10039_reg_names[reg+3]);
	}
}
#else
static inline void zl10039_dump_registers(const struct zl10039_state *state) {}
#endif /* DEBUG_DUMP_REGISTERS */

#endif /* DVB_FRONTENDS_ZL10039_PRIV */

_______________________________________________
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