[linux-dvb] msi digivox mini ii

Michael Krufky mkrufky at linuxtv.org
Thu Feb 22 22:29:53 CET 2007


Pierre Willenbrock wrote:
> Hi list,
> 
> I am owner of a "MSI DIGIVOX mini-II". I got it to work using the
> attached patch and firmware. The patch and firmware are the result of
> analyzing some usb logs from windows.
> 
> The patch breaks all users of tda10046, as i don't understand how that
> chip is supposed to work. The same goes for my driver implementation of
> the Philips 8275a.
> 
> So this mess needs to be fixed before it can go into the repository.
> 
> The patch is against a fresh hg checkout from
> http://linuxtv.org/hg/v4l-dvb at 2007-02-22 21:00 UTC.
> 
> Regards,
>   Pierre

Pierre-

I am very happy to hear that you got this device working...  Interestingly
enough, we have already created a new tda827x dvb fe module, which might be
better for your device...  This new tda827x module has not yet been merged into
the master v4l-dvb repository, but it will be soon.  Could you try to use the
code located in:

http://linuxtv.org/hg/~hhackmann/v4l-dvb

The tda827x module will be able to detect the difference between the tda8275 and
the tda8275a ...  You do not have to fill the callback functions in the config
struct -- that is really meant as a hack for some required GPIO handling in the
saa7134-dvb driver for input switching.

If you can generate a new patch against the repository above, it would make it
_much_ easier to integrate your patch into the sources.   After you get that
done, we can work out the tda1004x differences.

You might also want to speak to aett and friedrich, regulars of the #linuxtv irc
chat room on irc.freenode.net ... aet is the author of the m920x driver, and
friedrich has the same device that you have.  They have been working on it, but
haven't yet gotten successful results.

Good work!  Hopefully we can clean this up after you generate a new patch using
the tda827x module from hhackmann's repository.

Regards,

Mike Krufky


> diff -r 4d012cd162f5 linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	Wed Feb 21 20:23:29 2007 -0200
> +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	Tue Feb 13 18:32:45 2007 +0100
> @@ -37,6 +37,7 @@
>  #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
>  #define USB_VID_UNIWILL				0x1584
>  #define USB_VID_WIDEVIEW			0x14aa
> +#define USB_VID_ANUBIS_ELECTRONIC		0x10fd
>  
>  /* Product IDs */
>  #define USB_PID_ADSTECH_USB2_COLD			0xa333
> @@ -139,6 +140,7 @@
>  #define USB_PID_GENPIX_8PSK_COLD			0x0200
>  #define USB_PID_GENPIX_8PSK_WARM			0x0201
>  #define USB_PID_SIGMATEK_DVB_110			0x6610
> +#define USB_PID_ANUBIS_ELECTRONIC_MSI_DIGI_VOX_MINI_II  0x1513
>  
>  
>  #endif
> diff -r 4d012cd162f5 linux/drivers/media/dvb/dvb-usb/m920x.c
> --- a/linux/drivers/media/dvb/dvb-usb/m920x.c	Wed Feb 21 20:23:29 2007 -0200
> +++ b/linux/drivers/media/dvb/dvb-usb/m920x.c	Mon Feb 19 16:29:43 2007 +0100
> @@ -14,6 +14,8 @@
>  #include "mt352.h"
>  #include "mt352_priv.h"
>  #include "qt1010.h"
> +#include "tda1004x.h"
> +#include "tda8275.h"
>  
>  /* debug */
>  static int dvb_usb_m920x_debug;
> @@ -39,19 +41,33 @@ static struct dvb_usb_rc_key megasky_rc_
>  	{ 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
>  };
>  
> +static struct dvb_usb_rc_key digivox_rc_keys [] = {
> +};
> +
>  static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\
>  			     u16 index, void *data, int size)
>  {
>  	int ret;
> +
> +	deb_rc("m9206_read(..., %x, %x, %x, %p, %x)\n",
> +	       request, value, index, data, size);
>  
>  	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
>  			      request, USB_TYPE_VENDOR | USB_DIR_IN,
>  			      value, index, data, size, 2000);
> -	if (ret < 0)
> -		return ret;
> -
> -	if (ret != size)
> +	if (ret < 0) {
> +		printk(KERN_INFO "m9206_read = error: %d\n", ret);
> +		return ret;
> +	}
> +
> +	if (ret != size) {
> +		deb_rc("m9206_read = no data\n");
>  		return -EIO;
> +	}
> +	
> +
> +	deb_rc("m9206_read = %x\n",
> +	       ((unsigned char*)data)[0]);
>  
>  	return 0;
>  }
> @@ -60,6 +76,9 @@ static inline int m9206_write(struct usb
>  			      u16 value, u16 index)
>  {
>  	int ret;
> +
> +	deb_rc("m9206_write(..., %x, %x, %x)\n",
> +	       request, value, index);
>  
>  	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
>  			      request, USB_TYPE_VENDOR | USB_DIR_OUT,
> @@ -75,8 +94,8 @@ static int m9206_rc_init(struct usb_devi
>  	if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
>  		return ret;
>  
> -	if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
> -		return ret;
> +	if ((ret = m9206_write(udev, M9206_CORE, 0x51,
> +	M9206_RC_INIT1)) != 0) return ret;
>  
>  	return ret;
>  }
> @@ -331,6 +350,7 @@ static int m9206_firmware_download(struc
>  			i += size;
>  		}
>  		if (i != fw->size) {
> +			deb_rc("bad firmware file!\n");
>  			ret = -EINVAL;
>  			goto done;
>  		}
> @@ -350,6 +370,20 @@ static int m9206_firmware_download(struc
>  
>  /* Callbacks for DVB USB */
>  static int megasky_identify_state(struct usb_device *udev,
> +				  struct dvb_usb_device_properties *props,
> +				  struct dvb_usb_device_description **desc,
> +				  int *cold)
> +{
> +	struct usb_host_interface *alt;
> +
> +	alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
> +	*cold = (alt == NULL) ? 1 : 0;
> +
> +	return 0;
> +}
> +
> +/* Callbacks for DVB USB */
> +static int digivox_identify_state(struct usb_device *udev,
>  				  struct dvb_usb_device_properties *props,
>  				  struct dvb_usb_device_description **desc,
>  				  int *cold)
> @@ -426,8 +460,67 @@ static int megasky_qt1010_tuner_attach(s
>  	return 0;
>  }
>  
> +static struct tda1004x_config digivox_tda10046_config = {
> +        /* the demodulator's i2c address */
> +	.demod_address = 0x10,
> +
> +        /* does the "inversion" need inverted? */
> +        .invert = 0,
> +
> +        /* Does the OCLK signal need inverted? */
> +        .invert_oclk = 0,
> +
> +        /* Xtal frequency, 4 or 16MHz*/
> +        .xtal_freq = TDA10046_XTAL_16M,
> +
> +        /* IF frequency */
> +        .if_freq = TDA10046_FREQ_045,/*currently doing our own*/
> +
> +        /* AGC configuration */
> +        .agc_config = TDA10046_AGC_DIGIVOX,
> +
> +        /* request firmware for device */
> +        /* set this to NULL if the card has a firmware EEPROM */
> +        .request_firmware = NULL,/*uses firmware EEPROM - TODO: invalid revision*/
> +};
> +
> +static int digivox_tda10046_frontend_attach(struct dvb_usb_adapter *adap)
> +{
> +	struct m9206_state *m = adap->dev->priv;
> +
> +	deb_rc("digivox_tda10046_frontend_attach!\n");
> +
> +	m->i2c_r[M9206_I2C_DEMOD].addr = digivox_tda10046_config.demod_address;
> +	m->i2c_r[M9206_I2C_DEMOD].magic = 0x11;
> +
> +	if ((adap->fe = dvb_attach(tda10046_attach, &digivox_tda10046_config, &adap->dev->i2c_adap)) == NULL)
> +		return -EIO;
> +
> +	return 0;
> +}
> +
> +static struct tda8275_config digivox_tda8275_config = {
> +    .i2c_address = 0xc0
> +/*todo: more parameters*/
> +};
> +
> +static int digivox_tda8275_tuner_attach(struct dvb_usb_adapter *adap)
> +{
> +	struct m9206_state *m = adap->dev->priv;
> +
> +	m->i2c_r[M9206_I2C_TUNER].addr = digivox_tda8275_config.i2c_address;
> +	m->i2c_r[M9206_I2C_TUNER].magic = 0xc5;
> +
> +	if (dvb_attach(tda8275_attach, adap->fe, &adap->dev->i2c_adap,
> +		       &digivox_tda8275_config) == NULL)
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
>  /* DVB USB Driver stuff */
>  static struct dvb_usb_device_properties megasky_properties;
> +static struct dvb_usb_device_properties digivox_properties;
>  
>  static int m920x_probe(struct usb_interface *intf,
>  		       const struct usb_device_id *id)
> @@ -454,12 +547,31 @@ static int m920x_probe(struct usb_interf
>  
>  		if ((ret = m9206_rc_init(d->udev)) != 0)
>  			return ret;
> -	}
> +	} else 	if ((ret = dvb_usb_device_init(intf, &digivox_properties, THIS_MODULE, &d)) == 0) {
> +		deb_rc("probed!\n");
> +
> +		alt = usb_altnum_to_altsetting(intf, 1);
> +		if (alt == NULL) {
> +			deb_rc("not alt found!\n");
> +			return -ENODEV;
> +		}
> +
> +		ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
> +					alt->desc.bAlternateSetting);
> +		if (ret < 0)
> +			return ret;
> +
> +		if ((ret = m9206_rc_init(d->udev)) != 0)
> +			return ret;
> +	}
> +
>  	return ret;
>  }
>  
>  static struct usb_device_id m920x_table [] = {
>  		{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
> +		{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, 
> +			     USB_PID_ANUBIS_ELECTRONIC_MSI_DIGI_VOX_MINI_II) },
>  		{ }		/* Terminating entry */
>  };
>  MODULE_DEVICE_TABLE (usb, m920x_table);
> @@ -509,6 +621,55 @@ static struct dvb_usb_device_properties 
>  		{   "MSI Mega Sky 580 DVB-T USB2.0",
>  			{ &m920x_table[0], NULL },
>  			{ NULL },
> +		}
> +	}
> +};
> +
> +static struct dvb_usb_device_properties digivox_properties = {
> +	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
> +
> +	.usb_ctrl = DEVICE_SPECIFIC,
> +	.firmware = "dvb-usb-digivox-02.fw",
> +	.download_firmware = m9206_firmware_download,
> +
> +/*	.rc_interval      = 100,
> +	.rc_key_map       = digivox_rc_keys,
> +	.rc_key_map_size  = ARRAY_SIZE(digivox_rc_keys),
> +	.rc_query         = m9206_rc_query,*/
> +
> +	.size_of_priv     = sizeof(struct m9206_state),
> +
> +	.identify_state   = digivox_identify_state,
> +	.num_adapters = 1,
> +	.adapter = {{
> +/*		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
> +		DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,*/
> +
> +		.pid_filter_count = 8,
> +		.pid_filter       = m9206_pid_filter,
> +		.pid_filter_ctrl  = m9206_pid_filter_ctrl,
> +
> +		.frontend_attach  = digivox_tda10046_frontend_attach,
> +		.tuner_attach     = digivox_tda8275_tuner_attach,
> +
> +		.stream = {
> +			.type = USB_BULK,
> +			.count = 8,
> +			.endpoint = 0x81,
> +			.u = {
> +				.bulk = {
> +					.buffersize = 0x4000,
> +				}
> +			}
> +		},
> +	}},
> +	.i2c_algo         = &m9206_i2c_algo,
> +
> +	.num_device_descs = 1,
> +	.devices = {
> +		{   "MSI DIGI VOX mini II DVB-T USB2.0",
> +			{ &m920x_table[1], NULL },
> +			{ NULL },
>  		},
>  	}
>  };
> diff -r 4d012cd162f5 linux/drivers/media/dvb/frontends/Kconfig
> --- a/linux/drivers/media/dvb/frontends/Kconfig	Wed Feb 21 20:23:29 2007 -0200
> +++ b/linux/drivers/media/dvb/frontends/Kconfig	Tue Feb 13 19:17:31 2007 +0100
> @@ -312,6 +312,13 @@ config DVB_TUNER_LGH06XF
>  	help
>  	  A driver for the LG TDVS-H06xF ATSC tuner family.
>  
> +config DVB_TUNER_TDA8275
> +	tristate "Philips TDA8275 silicon tuner"
> +	depends on DVB_CORE && I2C
> +	default m if DVB_FE_CUSTOMISE
> +	help
> +	  A driver for the silicon tuner TDA8275 from Philips.
> +
>  comment "Miscellaneous devices"
>  	depends on DVB_CORE
>  
> diff -r 4d012cd162f5 linux/drivers/media/dvb/frontends/Makefile
> --- a/linux/drivers/media/dvb/frontends/Makefile	Wed Feb 21 20:23:29 2007 -0200
> +++ b/linux/drivers/media/dvb/frontends/Makefile	Tue Feb 13 19:16:34 2007 +0100
> @@ -41,3 +41,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010
>  obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
>  obj-$(CONFIG_DVB_TUA6100) += tua6100.o
>  obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
> +obj-$(CONFIG_DVB_TUNER_TDA8275) += tda8275.o
> diff -r 4d012cd162f5 linux/drivers/media/dvb/frontends/tda1004x.c
> --- a/linux/drivers/media/dvb/frontends/tda1004x.c	Wed Feb 21 20:23:29 2007 -0200
> +++ b/linux/drivers/media/dvb/frontends/tda1004x.c	Thu Feb 22 21:23:15 2007 +0100
> @@ -270,14 +270,24 @@ static int tda10046h_set_bandwidth(struc
>  static int tda10046h_set_bandwidth(struct tda1004x_state *state,
>  				   fe_bandwidth_t bandwidth)
>  {
> -	static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
> +/*	static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
>  	static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
>  	static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d };
>  
>  	static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 };
>  	static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab };
> -	static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };
> -	int tda10046_clk53m;
> +	static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 };*/
> +
> +	static u8 digivox_vhf[] = { 0x79, 0x16, 0x1c, 0x21, 0xc2 };
> +	static u8 digivox_uhf[] = { 0x5b, 0x02, 0xd0, 0x2d, 0x03 };
> +
> +	tda1004x_write_buf(state, TDA10046H_TIME_WREF1, digivox_uhf,
> +			   sizeof(digivox_uhf));
> +/*for vhf: 0x09, 0xd9*/
> +	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
> +	tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xb2);
> +
> +/*	int tda10046_clk53m;
>  
>  	if ((state->config->if_freq == TDA10046_FREQ_045) ||
>  	    (state->config->if_freq == TDA10046_FREQ_052))
> @@ -326,7 +336,7 @@ static int tda10046h_set_bandwidth(struc
>  
>  	default:
>  		return -EINVAL;
> -	}
> +		}*/
>  
>  	return 0;
>  }
> @@ -451,13 +461,15 @@ static void tda10046_init_plls(struct dv
>  		tda10046_clk53m = 1;
>  
>  	tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
> -	if(tda10046_clk53m) {
> +	printk(KERN_INFO "tda1004x: setting up plls for 52MHz sampling clock\n");
> +	tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x07); // PLL M = 7
> +/*	if(tda10046_clk53m) {
>  		printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n");
>  		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8
>  	} else {
>  		printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n");
>  		tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3
> -	}
> +		}*/
>  	if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
>  		dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
>  		tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
> @@ -536,7 +548,10 @@ static int tda10046_fwupload(struct dvb_
>  		tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
>  		msleep(300);
>  	}
> -	return tda1004x_check_upload_ok(state);
> +	if (state->config->request_firmware != NULL)
> +	    return tda1004x_check_upload_ok(state);
> +	else
> +	    return 0;
>  }
>  
>  static int tda1004x_encode_fec(int fec)
> @@ -630,9 +645,16 @@ static int tda10046_init(struct dvb_fron
>  			return -EIO;
>  	}
>  
> +/*from windows driver*/
> +	tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x00);
> +	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x2f);
> +	tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcf);
> +/*from windows driver*/
> +
>  	// tda setup
>  	tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
> -	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);    // 100 ppm crystal, select HP stream
> +/*	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87);*/    // 100 ppm crystal, select HP stream
> +	tda1004x_write_byteI(state, TDA1004X_AUTO, 0x57);
>  	tda1004x_write_byteI(state, TDA1004X_CONFC1, 0x88);      // enable pulse killer
>  
>  	switch (state->config->agc_config) {
> @@ -666,9 +688,16 @@ static int tda10046_init(struct dvb_fron
>  		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
>  		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x62); // set AGC polarities
>  		break;
> -	}
> -	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
> -	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
> +	case TDA10046_AGC_DIGIVOX:
> +		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
> +		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // set AGC threshold
> +		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x24); // set AGC polarities
> +		break;
> +	}
> +/*	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);*/
> +	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x34);
> +/*	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61);*/ // Turn both AGC outputs on
> +	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xa1); 
>  	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
>  	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
>  	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
> diff -r 4d012cd162f5 linux/drivers/media/dvb/frontends/tda1004x.h
> --- a/linux/drivers/media/dvb/frontends/tda1004x.h	Wed Feb 21 20:23:29 2007 -0200
> +++ b/linux/drivers/media/dvb/frontends/tda1004x.h	Fri Feb 16 00:53:57 2007 +0100
> @@ -38,6 +38,7 @@ enum tda10046_agc {
>  	TDA10046_AGC_TDA827X_GP11,	/* IF AGC only, special setup for tda827x */
>  	TDA10046_AGC_TDA827X_GP00,	/* same as above, but GPIOs 0 */
>  	TDA10046_AGC_TDA827X_GP01,	/* same as above, but GPIO3=0 GPIO1=1*/
> +	TDA10046_AGC_DIGIVOX,           /* setup for msi digivox mini ii*/
>  };
>  
>  enum tda10046_if {
> diff -r 4d012cd162f5 linux/drivers/media/dvb/frontends/tda8275.c
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/linux/drivers/media/dvb/frontends/tda8275.c	Thu Feb 22 21:44:27 2007 +0100
> @@ -0,0 +1,345 @@
> +/*
> + *  Driver for Philips tda8275 silicon tuner
> + *
> + *  Copyright (C) 2007 Pierre Willenbrock <pierre at pirsoft.dnsalias.org>
> + *  Based on qt1010 and tda8290 driver
> + *
> + *  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 "tda8275.h"
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
> +
> +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "TDA8275: " args); printk("\n"); }} while (0)
> +
> +
> +struct tda8275_priv {
> +	struct tda8275_config *cfg;
> +	struct i2c_adapter   *i2c;
> +
> +	u32 frequency;
> +	u32 bandwidth;
> +};
> +
> +/* read single register */
> +static int tda8275_readreg(struct tda8275_priv *priv, u8 reg, u8 *val)
> +{
> +	struct i2c_msg msg[2] = {
> +		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
> +		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
> +	};
> +
> +	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
> +		printk(KERN_WARNING "tda8275 I2C read failed\n");
> +		return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +/* write single register */
> +static int tda8275_writereg(struct tda8275_priv *priv, u8 reg, u8 val)
> +{
> +	u8 buf[2] = { reg, val };
> +	struct i2c_msg msg = {
> +		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
> +	};
> +
> +	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
> +		printk(KERN_WARNING "tda8275 I2C write failed\n");
> +		return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +/*from tda8290.c*/
> +struct tda827xa_data {
> +	u32 lomax;
> +	u8  svco;
> +	u8  spd;
> +	u8  scr;
> +	u8  sbs;
> +	u8  gc3;
> +};
> +
> +static struct tda827xa_data tda827xa_analog[] = {
> +	{ .lomax =   910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},  /*  56.875 MHz */
> +	{ .lomax =  1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  67.25 MHz */
> +	{ .lomax =  1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  81.25 MHz */
> +	{ .lomax =  1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  97.5  MHz */
> +	{ .lomax =  1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},  /* 113.75 MHz */
> +	{ .lomax =  2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 134.5 MHz */
> +	{ .lomax =  2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 154   MHz */
> +	{ .lomax =  2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 162.5 MHz */
> +	{ .lomax =  2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 183   MHz */
> +	{ .lomax =  3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},  /* 195   MHz */
> +	{ .lomax =  3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},  /* 227.5 MHz */
> +	{ .lomax =  4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},  /* 269   MHz */
> +	{ .lomax =  5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},  /* 325   MHz */
> +	{ .lomax =  6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 390   MHz */
> +	{ .lomax =  7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 455   MHz */
> +	{ .lomax =  8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 520   MHz */
> +	{ .lomax =  8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},  /* 538   MHz */
> +	{ .lomax =  8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 554   MHz */
> +	{ .lomax =  9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 620   MHz */
> +	{ .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 650   MHz */
> +	{ .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 700   MHz */
> +	{ .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 780   MHz */
> +	{ .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 820   MHz */
> +	{ .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 870   MHz */
> +	{ .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},  /* 911   MHz */
> +	{ .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
> +};
> +/*
> +static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
> +{
> +	unsigned char tuner_reg[14];
> +	unsigned char reg2[2];
> +	u32 N;
> +	int i;
> +	struct tuner *t = i2c_get_clientdata(c);
> +	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
> +
> +	if (t->mode == V4L2_TUNER_RADIO)
> +		freq = freq / 1000;
> +
> +	N = freq + ifc;
> +	i = 0;
> +	while (tda827xa_analog[i].lomax < N) {
> +		if(tda827xa_analog[i + 1].lomax == 0)
> +			break;
> +		i++;
> +	}
> +
> +	N = N << tda827xa_analog[i].spd;
> +
> +	tuner_reg[0] = 0;
> +	tuner_reg[1] = (unsigned char)(N>>8);
> +	tuner_reg[2] = (unsigned char) N;
> +	tuner_reg[3] = 0;
> +	tuner_reg[4] = 0x16;
> +	tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
> +			tda827xa_analog[i].sbs;
> +	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
> +	tuner_reg[7] = 0x0c;
> +	tuner_reg[8] = 4;
> +	tuner_reg[9] = 0x20;
> +	tuner_reg[10] = 0xff;
> +	tuner_reg[11] = 0xe0;
> +	tuner_reg[12] = 0;
> +	tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1);
> +
> +	msg.buf = tuner_reg;
> +	msg.len = 14;
> +	i2c_transfer(c->adapter, &msg, 1);
> +
> +	msg.buf= reg2;
> +	msg.len = 2;
> +	reg2[0] = 0x60;
> +	reg2[1] = 0x3c;
> +	i2c_transfer(c->adapter, &msg, 1);
> +
> +	reg2[0] = 0xa0;
> +	reg2[1] = 0xc0;
> +	i2c_transfer(c->adapter, &msg, 1);
> +
> +	msleep(2);
> +	reg2[0] = 0x30;
> +	reg2[1] = 0x10 + tda827xa_analog[i].scr;
> +	i2c_transfer(c->adapter, &msg, 1);
> +
> +	msleep(550);
> +	reg2[0] = 0x50;
> +	reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
> +	i2c_transfer(c->adapter, &msg, 1);
> +
> +	reg2[0] = 0x80;
> +	reg2[1] = 0x28;
> +	i2c_transfer(c->adapter, &msg, 1);
> +
> +	reg2[0] = 0xb0;
> +	reg2[1] = 0x01;
> +	i2c_transfer(c->adapter, &msg, 1);
> +
> +	reg2[0] = 0xc0;
> +	reg2[1] = 0x19 + (t->tda827x_lpsel << 1);
> +	i2c_transfer(c->adapter, &msg, 1);
> +}
> +
> +static void tda827xa_agcf(struct i2c_client *c)
> +{
> +	struct tuner *t = i2c_get_clientdata(c);
> +	unsigned char data[] = {0x80, 0x2c};
> +	struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
> +			      .flags = 0, .len = 2};
> +	i2c_transfer(c->adapter, &msg, 1);
> +}
> +*/
> +static int tda8275_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
> +{
> +	struct tda8275_priv *priv;
> +	u32 freq;
> +	u32 N;
> +	int i;
> +	u16 ifc = 76;//4.75MHz
> +
> +	priv = fe->tuner_priv;
> +	freq = params->frequency;
> +	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
> +	priv->frequency = freq;
> +
> +	freq = freq / (1000000/16);
> +	
> +
> +	N = freq + ifc;
> +	i = 0;
> +	while (tda827xa_analog[i].lomax < N) {
> +		if(tda827xa_analog[i + 1].lomax == 0)
> +			break;
> +		i++;
> +	}
> +
> +	N = N << tda827xa_analog[i].spd;
> +
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
> +
> +//	n11ton0 = freq/250000;//using spd==0
> +
> +	printk(KERN_INFO "tda8275: request to tune to %d\n", freq);
> +
> +/*	tda8275_writereg(priv, 0x00, 0x2e);*/
> +/*	tda8275_writereg(priv, 0x10, 0xec);*/
> +	tda8275_writereg(priv, 0x00, (N >> 8) & 0x3f);
> +	tda8275_writereg(priv, 0x10, (N) & 0xfc);
> +	tda8275_writereg(priv, 0x20, 0x00);
> +	tda8275_writereg(priv, 0x30, 0x16);
> +/*	tda8275_writereg(priv, 0x40, 0x14);*/
> +	tda8275_writereg(priv, 0x40, 
> +			 (tda827xa_analog[i].spd << 5) + 
> +			 (tda827xa_analog[i].svco << 3) + 
> +			 tda827xa_analog[i].sbs);
> +/*	tda8275_writereg(priv, 0x50, 0x4b);*/
> +	tda8275_writereg(priv, 0x50, 0x4b + (tda827xa_analog[i].gc3 << 4));
> +	tda8275_writereg(priv, 0x60, 0x2c);
> +	tda8275_writereg(priv, 0x70, 0x06);
> +	tda8275_writereg(priv, 0x80, 0x26);
> +	tda8275_writereg(priv, 0x90, 0xff);
> +	tda8275_writereg(priv, 0xa0, 0x60);
> +	tda8275_writereg(priv, 0xb0, 0x00);
> +	tda8275_writereg(priv, 0xc0, 0x39);
> +
> +	tda8275_writereg(priv, 0xa0, 0x40);
> +
> +	tda8275_writereg(priv, 0x30, 0x10 + tda827xa_analog[i].scr);
> +
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
> +
> +	return 0;
> +}
> +
> +static int tda8275_init(struct dvb_frontend *fe)
> +{
> +	struct dvb_frontend_parameters params;
> +
> +	params.frequency = 545000000; 
> +				      
> +	return tda8275_set_params(fe, &params);
> +}
> +
> +static int tda8275_release(struct dvb_frontend *fe)
> +{
> +	kfree(fe->tuner_priv);
> +	fe->tuner_priv = NULL;
> +	return 0;
> +}
> +
> +static int tda8275_get_frequency(struct dvb_frontend *fe, u32 *frequency)
> +{
> +	struct tda8275_priv *priv = fe->tuner_priv;
> +	*frequency = priv->frequency;
> +	return 0;
> +}
> +
> +static int tda8275_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
> +{
> +	struct tda8275_priv *priv = fe->tuner_priv;
> +	*bandwidth = priv->bandwidth;
> +	return 0;
> +}
> +
> +#define TDA8275_MIN_FREQ 0
> +#define TDA8275_MAX_FREQ 1023750000
> +#define TDA8275_STEP 250000
> +
> +static const struct dvb_tuner_ops tda8275_tuner_ops = {
> +	.info = {
> +		.name           = "Philips TDA8275",
> +		.frequency_min  = TDA8275_MIN_FREQ,
> +		.frequency_max  = TDA8275_MAX_FREQ,
> +		.frequency_step = TDA8275_STEP,
> +	},
> +
> +	.release       = tda8275_release,
> +	.init          = tda8275_init,
> +	/* TODO: implement sleep */
> +
> +	.set_params    = tda8275_set_params,
> +	.get_frequency = tda8275_get_frequency,
> +	.get_bandwidth = tda8275_get_bandwidth
> +};
> +
> +struct dvb_frontend * tda8275_attach(struct dvb_frontend *fe,
> +				    struct i2c_adapter *i2c,
> +				    struct tda8275_config *cfg)
> +{
> +	struct tda8275_priv *priv = NULL;
> +	u8 id;
> +
> +	priv = kzalloc(sizeof(struct tda8275_priv), GFP_KERNEL);
> +	if (priv == NULL)
> +		return NULL;
> +
> +	priv->cfg      = cfg;
> +	priv->i2c      = i2c;
> +
> +	if(0) {/*don't know how to detect*/
> +		if (fe->ops.i2c_gate_ctrl)
> +			fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
> +		
> +		/* Try to detect tuner chip. Probably this is not correct register. */
> +		if (tda8275_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
> +			kfree(priv);
> +			return NULL;
> +		}
> +		
> +		if (fe->ops.i2c_gate_ctrl)
> +			fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
> +	}
> +
> +	printk(KERN_INFO "Philips TDA8275 probably identified.\n");
> +	memcpy(&fe->ops.tuner_ops, &tda8275_tuner_ops, sizeof(struct dvb_tuner_ops));
> +
> +	fe->tuner_priv = priv;
> +	return fe;
> +}
> +EXPORT_SYMBOL(tda8275_attach);
> +
> +MODULE_DESCRIPTION("Philips TDA8275 silicon tuner driver");
> +MODULE_AUTHOR("Pierre Willenbrock <pierre at pirsoft.dnsalias.org>");
> +MODULE_VERSION("0.1");
> +MODULE_LICENSE("GPL");
> diff -r 4d012cd162f5 linux/drivers/media/dvb/frontends/tda8275.h
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/linux/drivers/media/dvb/frontends/tda8275.h	Thu Feb 22 21:43:32 2007 +0100
> @@ -0,0 +1,53 @@
> +/*
> + *  Driver for Philips tda8275 silicon tuner
> + *
> + *  Copyright (C) 2007 Pierre Willenbrock <pierre at pirsoft.dnsalias.org>
> + *  Based on qt1010 driver
> + *
> + *  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 TDA8275_H
> +#define TDA8275_H
> +
> +#include "dvb_frontend.h"
> +
> +struct tda8275_config {
> +	u8 i2c_address;
> +};
> +
> +/**
> + * Attach a tda8275 tuner to the supplied frontend structure.
> + *
> + * @param fe   frontend to attach to
> + * @param i2c  i2c adapter to use
> + * @param cfg  tuner hw based configuration
> + * @return fe  pointer on success, NULL on failure
> + */
> +#if defined(CONFIG_DVB_TUNER_TDA8275) || (defined(CONFIG_DVB_TUNER_TDA8275_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *tda8275_attach(struct dvb_frontend *fe,
> +					  struct i2c_adapter *i2c,
> +					  struct tda8275_config *cfg);
> +#else
> +static inline struct dvb_frontend *tda8275_attach(struct dvb_frontend *fe,
> +						 struct i2c_adapter *i2c,
> +						 struct tda8275_config *cfg)
> +{
> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
> +	return NULL;
> +}
> +#endif // CONFIG_DVB_TUNER_TDA8275
> +
> +#endif
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> linux-dvb mailing list
> linux-dvb at linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb


-- 
Michael Krufky




More information about the linux-dvb mailing list