Mailing List archive

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

[linux-dvb] Re: [rfc/patch] pll handling and cx22702 update



Hi, how about the attached example (probably won't compile BTW)

This should let simple tuners be represented as simply as Gerd had them, but 
also allow more flexibility to represent pretty much anything.

It reinstates the more complex rules for the dtt7579/dtt759x - they both 
require settings to be changed post-tuning and one requires a sleep to let 
the tuner settle.

Its also flexible enough for the more extreme examples - e.g. the TUA6120 that 
Andreas pointed out would be implemented by supplying a custom Set() 
function, which used the "int device" field to encode the exact register to 
write to.

Lemme know what you think...
/*
 * descriptions + helper functions for dvb tuners.
 *
 * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
 *
 *  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/dvb/frontend.h>
#include <asm/types.h>

#include "dvb-tuner.h"


/* ----------------------------------------------------------- */
/* generic functions                                           */

static int tuner_generic_init(struct dvb_tuner_desc* desc, dvb_tuner_ops* ops)
{
	u8* buf;

	buf = alloca(desc->tuner_data_size);
	if (buf == NULL)
		return -ENOMEM;

	memcpy(buf, desc->init_data, desc->tuner_data_size);
	return ops->write(desc, ops, 0, buf, desc->tuner_data_size);
}

static int tuner_generic_sleep(struct dvb_tuner_desc* desc, dvb_tuner_ops* ops)
{
	u8* buf;

	buf = alloca(desc->tuner_data_size);
	if (buf == NULL)
		return -ENOMEM;

	memcpy(buf, desc->sleep_data, desc->tuner_data_size);
	return ops->write(desc, ops, 0, buf, desc->tuner_data_size);
}

static int tuner_fillbuf(dvb_tuner_desc* desc, u8* buf, u32 freq)
{
	int i;

	if (freq < desc->min_freq || freq > desc->max_freq)
		return -EINVAL;

	for (i = 0; i < desc->num_entries; i++) {
		if (freq > desc->entries[i].limit)
			continue;
		break;
	}
	if (i == desc->num_entries)
		return -EINVAL;

	memcpy(buf, desc->entries[i].data, desc->tuner_data_size);
	return i;
}

static inline u32 tuner_divisor(u32 freq, u32 int_freq, u32 step)
{
	return (freq + int_freq) / step;
}

static int tuner_generic_set(struct dvb_tuner_desc* desc, dvb_tuner_ops* ops, struct dvb_frontend_parameters * params)
{
	u8* buf;
	u32 div;
	int entry;

	buf = alloca(desc->tuner_data_size);
	if (buf == NULL)
		return -ENOMEM;

	if ((entry = tuner_fillbuf(desc, buf, params->frequency)) < 0)
		return entry;

	div = tuner_divisor(params->frequency, desc->entries[entry].stepsize);
	buf[0] = div >> 8;
	buf[1] = div & 0xff;

	return ops->write(desc, ops, 0, buf, desc->tuner_data_size);
}





/* ----------------------------------------------------------- */
/* tuner descriptions                                          */

static int thomson_dtt7579_set(struct dvb_tuner_desc* desc, struct dvb_tuner_ops* ops, struct dvb_frontend_parameters * params)
{
	u8* buf;
	u32 div;
	int entry;
	int res;

	buf = alloca(desc->tuner_data_size);
	if (buf == NULL)
		return -ENOMEM;

	if ((entry = tuner_fillbuf(desc, buf, params->frequency)) < 0)
		return entry;

	div = tuner_divisor(params->frequency, desc->entries[entry].stepsize);
	buf[0] = div >> 8;
	buf[1] = div & 0xff;
	if (res = ops->write(desc, ops, 0, buf, desc->tuner_data_size))
		return res;

	/* Set the AGC to search */
	buf[2]=(buf[2] & 0xdc) | 0x9c;
	buf[3]=0xa0;
	return ops->write(desc, ops, 0, buf, desc->tuner_data_size);
}

struct dvb_tuner_desc dvb_tuner_thomson_dtt7579 = {
       .name     = "Thomson DTT7579",
       .min_freq = 177000000,
       .max_freq = 858000000,
       .int_freq = 36166667,
       .sleep = tuner_generic_sleep,
       .set = thomson_dtt7579_set,
       .tuner_data_size = 4,
       .sleep_data = { 0x00, 0x00, 0xb4, 0x03 },
       .num_entries = 5,
       .entries = {
		{  443250000, 166666, { 0x00, 0x00, 0xb4, 0x02 } },
		{  542000000, 166666, { 0x00, 0x00, 0xb4, 0x08 } },
		{  771000000, 166666, { 0x00, 0x00, 0xbc, 0x08 } },
		{  999999999, 166666, { 0x00, 0x00, 0xf4, 0x08 } },
       },
};
EXPORT_SYMBOL(dvb_tuner_thomson_dtt7579);

static int thomson_dtt759x_set(struct dvb_tuner_desc* desc, struct dvb_tuner_ops* ops, struct dvb_frontend_parameters * params)
{
	u8* buf;
	u32 div;
	int entry;
	int res;

	buf = alloca(desc->tuner_data_size);
	if (buf == NULL)
		return -ENOMEM;

	if ((entry = tuner_fillbuf(desc, buf, params->frequency)) < 0)
		return entry;

	if (params->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
		buf[3] |= 0x10;

	div = tuner_divisor(params->frequency, desc->entries[entry].stepsize);
	buf[0] = (div >> 8) & 0x7f;
	buf[1] = div & 0xff;
	if (res = ops->write(desc, ops, 0, buf, desc->tuner_data_size))
		return res;
	msleep(100);

	/* Set the AGC post-search */
	buf[3]=0x20;
	return ops->write(desc, ops, 0, buf, desc->tuner_data_size);
}

struct dvb_tuner_desc dvb_tuner_thomson_dtt759x = {
       .name     = "Thomson DTT759x",
       .min_freq = 177000000,
       .max_freq = 896000000,
       .int_freq = 36166667,
       .sleep = tuner_generic_sleep,
       .set = thomson_dtt759x_set,
       .tuner_data_size = 4,
       .sleep_data = { 0x00, 0x00, 0x84, 0x03 };
       .num_entries = 5,
       .entries = {
               {  264000000, 166666, { 0x00, 0x00, 0xb4, 0x02 } },
               {  470000000, 166666, { 0x00, 0x00, 0xbc, 0x02 } },
               {  735000000, 166666, { 0x00, 0x00, 0xbc, 0x08 } },
               {  835000000, 166666, { 0x00, 0x00, 0xf4, 0x08 } },
               {  999999999, 166666, { 0x00, 0x00, 0xfc, 0x08 } },
       },
};
EXPORT_SYMBOL(dvb_tuner_thomson_dtt759x);

struct dvb_tuner_desc dvb_tuner_lg_z201 = {
       .name     = "LG z201",
       .min_freq = 174000000,
       .max_freq = 862000000,
       .int_freq = 36166667,
       .sleep = tuner_generic_sleep,
       .set = tuner_generic_set,
       .tuner_data_size = 4,
       .sleep_data = { 0x00, 0x00, 0xbc, 0x03 };
       .count = 4,
       .entries = {
               {  443250000, 166666, { 0x00, 0x00, 0xbc, 0x01 } },
               {  542000000, 166666, { 0x00, 0x00, 0xbc, 0x02 } },
               {  830000000, 166666, { 0x00, 0x00, 0xf4, 0x02 } },
               {  999999999, 166666, { 0x00, 0x00, 0xfc, 0x02 } },
       },
};
EXPORT_SYMBOL(dvb_tuner_lg_z201);

struct dvb_tuner_desc dvb_tuner_unknown_1 = {
       .name     = "unknown 1",
       .min_freq = 174000000,
       .max_freq = 862000000,
       .int_freq = 36166667,
       .set = tuner_generic_set,
       .tuner_data_size = 4,
       .num_entries = 9,
       .entries = {
               {  150000000, 166666, { 0x00, 0x00, 0xb4, 0x01 } },
               {  173000000, 166666, { 0x00, 0x00, 0xbc, 0x01 } },
               {  250000000, 166666, { 0x00, 0x00, 0xb4, 0x02 } },
               {  400000000, 166666, { 0x00, 0x00, 0xbc, 0x02 } },
               {  420000000, 166666, { 0x00, 0x00, 0xf4, 0x02 } },
               {  470000000, 166666, { 0x00, 0x00, 0xfc, 0x02 } },
               {  600000000, 166666, { 0x00, 0x00, 0xbc, 0x08 } },
               {  730000000, 166666, { 0x00, 0x00, 0xf4, 0x08 } },
               {  999999999, 166666, { 0x00, 0x00, 0xfc, 0x08 } },
       },
};
EXPORT_SYMBOL(dvb_tuner_unknown_1);
/*
    DVB PLL definitions

    Copyright (C) 2004 Gerd Knorr, Andrew de Quincey

    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_PLL_H
#define DVB_PLL_H 1

struct dvb_tuner_ops {
	int (*read)(struct dvb_tuner_desc* desc, struct dvb_tuner_ops* ops, int device, u8* buf, int size);
	int (*write)(struct dvb_tuner_desc* desc, struct dvb_tuner_ops* ops, int device, u8* buf, int size);

	void* card_data;
};

struct dvb_tuner_desc {

	char *name;
	u32 min_freq;
	u32 max_freq;
	u32 int_freq;
	int (*init)(struct dvb_tuner_desc* desc, dvb_tuner_ops* ops);
	int (*sleep)(struct dvb_tuner_desc* desc, struct dvb_tuner_ops* ops);
	int (*set)(struct dvb_tuner_desc* desc, struct dvb_tuner_ops* ops, struct dvb_frontend_parameters * params);
	int tuner_data_size;
	int num_entries;
	struct {
		u32 max_entry_freq;
		u32 stepsize;
		u8 data[];
	} entries[];
};

extern struct dvb_tuner_desc dvb_tuner_thomson_dtt7579;
extern struct dvb_tuner_desc dvb_tuner_thomson_dtt759x;
extern struct dvb_tuner_desc dvb_tuner_lg_z201;
extern struct dvb_tuner_desc dvb_tuner_unknown_1;

#endif

Home | Main Index | Thread Index