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@xxxxxxxxxxxxxxxxxxxx> > + * 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 = ®, .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, ¶ms); > +} > + > +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@xxxxxxxxxxxxxxxxxxxx>"); > +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@xxxxxxxxxxxxxxxxxxxx> > + * 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@xxxxxxxxxxx > http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb -- Michael Krufky _______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb