⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 adimtv102.c

📁 asus U3100 DMBTH 電視棒反釋源碼
💻 C
字号:
/* *  Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" * *  Copyright (c) 2006 Olivier DANET <odanet@caramail.com> * *  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.= *//* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/delay.h>#include <linux/dvb/frontend.h>#include <linux/i2c.h>#include "dvb_frontend.h"#include "adimtv102.h"#include "adimtv102_priv.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 "MT2060: " args); printk("\n"); }} while (0)unsigned int LO2PLL_Freq(unsigned int freq, unsigned int *setting) {	if(freq <= 1879999) {		if(freq > 939999) {			*setting = 4;			return freq;		} else if(freq > 469999) {			*setting = 3;			return freq * 2;		} else if(freq > 234999) {			*setting = 2;			return freq * 4;		} else if(freq > 117499) {			*setting = 1;			return freq * 8;		} else if(freq > 58749) {			*setting = 0;			return freq * 16;		} // no else case, just falls through	}	switch(*setting){		case 0: return freq * 16;		case 1: return freq * 8;		case 2: return freq * 4;		case 3: return freq * 2;		case 4: return freq;		default: return freq * 2;	}/*	unsigned char tmp;	tmp = freq > 939999 ? 1 : 0;	if(freq <= 1879999) {		if(!tmp) { // freq <= 939999			if(freq > 469999) {				*setting = 3;				return freq * 2;			} else { // located @ 41				if(freq <= 234999) {					if(freq > 117499) {						*setting = 1;						return freq * 8;					} else { // located @ 89						if(freq > 58749) {							*setting = 0;							return freq * 16;						} else { // located @ 34							switch(*setting) {								case 0: return freq * 16;								case 1: return freq * 8;								case 2: return freq * 4;								case 3: return freq * 2;								case 4: return freq;								default: return freq * 2;							}						}					}				} else { // located @ 70					*setting = 2;					return freq * 4;				}			}		} else { // located @ 60			*setting = 4;			return freq;		}	} else { // located @ 28		if(tmp) { // freq > 939999, but this is always true wor...			if(freq > 469999) { // this is also always true wor.				switch(*setting){					case 0: return freq * 16;					case 1: return freq * 8;					case 2: return freq * 4;					case 3:	return freq * 2;					case 4: return freq;					default: return freq * 2;				}			} else { // located @  41// and therefore this whole else block shouldn't be here afterall...				if(freq <= 234999) {					if(freq > 117499) {						*setting = 1;						return freq * 8;					} else { // located @ 89						if(freq > 58749) {							*setting = 0;							return freq * 16;						} else { // located @ 34							switch(*setting) {								case 0: return freq * 16;								case 1: return freq * 8;								case 2: return freq * 4;								case 3: return freq * 2;								case 4: return freq;								default: return freq * 2;							}						}					}				} else { // located @ 70					*setting = 2;					return freq * 4;				}			}		} else { // located @ 16			// and else block is also useless..			if(freq > 479999) {				*setting = 3;				return freq * 2;			} else { // located @ 41				if(freq <= 234999) {					if(freq > 117499) {						*setting = 1;						return freq * 8;					} else { // located @ 89						if(freq > 58749) {							*setting = 0;							return freq * 16;						} else { // located @ 34							switch(*setting) {								case 0: return freq * 16;								case 1: return freq * 8;								case 2: return freq * 4;								case 3: return freq * 2;								case 4: return freq;								default: return freq * 2;							}						}					}				} else { // located @ 70					*setting = 2;					return freq * 4;				}			}		}	}*/}EXPORT_SYMBOL(LO2PLL_Freq);static int adimtv102_sleep(struct dvb_frontend *fe){	return 0;}static int adimtv102_init(struct dvb_frontend *fe){	printk("adimtv102_init\n");	return 0;}static int adimtv102_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth){	struct adimtv102_priv *priv = fe->tuner_priv;	*bandwidth = priv->bandwidth;	printk("adimtv102_get_bandwidth\n");	return 0;}static int adimtv102_get_frequency(struct dvb_frontend *fe, u32 *frequency){	struct adimtv102_priv *priv = fe->tuner_priv;	*frequency = priv->frequency;	printk("adimtv102_get_frequency\n");	return 0;}static int adimtv102_release(struct dvb_frontend *fe){	kfree(fe->tuner_priv);	fe->tuner_priv = NULL;	return 0;}// Writes a single registerstatic int adimtv102_writereg(struct adimtv102_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 "adimtv102 I2C write failed\n");		return -EREMOTEIO;	}	return 0;}// Reads a single registerstatic int adimtv102_readreg(struct adimtv102_priv *priv, u8 reg, u8 *val){	u8 wbuf[2] = {reg, reg};	u8 rbuf[2];	struct i2c_msg msg[2] = {		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = wbuf, .len = 2 },		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = rbuf,  .len = 2 },	};		if (i2c_transfer(priv->i2c, msg, 2) != 2) {		printk(KERN_WARNING "adimtv102 I2C read failed\n");		return -EREMOTEIO;	}	*val = rbuf[0];	return 0;}static int adimtv102_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params);static const struct dvb_tuner_ops adimtv102_tuner_ops = {	.info = {		.name           = "ADI MTV102",		.frequency_min  =  48000000,		.frequency_max  = 860000000,		.frequency_step =     50000,	},	.release       = adimtv102_release,	.init          = adimtv102_init,	.sleep         = adimtv102_sleep,	.set_params    = adimtv102_set_params,	.get_frequency = adimtv102_get_frequency,	.get_bandwidth = adimtv102_get_bandwidth};/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */struct dvb_frontend * adimtv102_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct adimtv102_config *cfg, u16 if1){	struct adimtv102_priv *priv = NULL;	u8 reg0;	u8 reg1;	u8 reg2;	priv = kzalloc(sizeof(struct adimtv102_priv), GFP_KERNEL);	if (priv == NULL)		return NULL;	priv->cfg      = cfg;	priv->i2c      = i2c;	priv->if1_freq = if1;	printk("adimtv102_readreg 0x00\n");	adimtv102_readreg(priv, 0, &reg0);	printk("adimtv102_readreg 0x01\n");	adimtv102_readreg(priv, 1, &reg1);	printk("adimtv102_readreg 0x02\n");	adimtv102_readreg(priv, 2, &reg2);	printk("adimtv102: successfully identified (%x %x %x)\n", reg1, reg2, reg0);		memcpy(&fe->ops.tuner_ops, &adimtv102_tuner_ops, sizeof(struct dvb_tuner_ops));	fe->tuner_priv = priv;	return fe;}EXPORT_SYMBOL(adimtv102_attach);struct adimtv102_addr_val_pair{	u8 reg;	u8 val;};struct adimtv102_reg_struct{	u16 frequency;	struct adimtv102_addr_val_pair settings[43]; // seriously I don't know the exact size, just wild guess.};int adimtv102_compute_regs(struct adimtv102_priv *priv, struct adimtv102_reg_struct *data_buf) {	unsigned char tmp;	unsigned int i;	unsigned int pllfreq;	unsigned int pllfreq_shr14;	unsigned int pllfreq_residue;	unsigned int LO2PLL_Freq_result; // @ 0x14	unsigned char read_buf; // @ 0x1b	unsigned char read_buf2; // @ 0x1a	LO2PLL_Freq_result = 0;// {address, data} data arrangment	data_buf->settings[0].reg = 0x10;	data_buf->settings[0].val = 0x4c;	data_buf->settings[1].reg = 0x11;	data_buf->settings[1].val = 0xd8;	data_buf->settings[2].reg = 0x12;	data_buf->settings[2].val = 0xc0;	data_buf->settings[3].reg = 0x17;	data_buf->settings[3].val = 0x9a;	data_buf->settings[4].reg = 0x1a;	data_buf->settings[4].val = 0x7c;	data_buf->settings[5].reg = 0x1b;	data_buf->settings[5].val = 0x51;	data_buf->settings[6].reg = 0x1c;	data_buf->settings[6].val = 0xb4;	data_buf->settings[7].reg = 0x1d;	data_buf->settings[7].val = 0xa4;	data_buf->settings[8].reg = 0x1e;	data_buf->settings[8].val = 0xfb;	data_buf->settings[9].reg = 0x1f;	data_buf->settings[9].val = 0x17;	data_buf->settings[10].reg = 0x20;	data_buf->settings[10].val = 0xff;	data_buf->settings[11].reg = 0x21;	data_buf->settings[11].val = 0xa4;	data_buf->settings[12].reg = 0x22;	data_buf->settings[12].val = 0xa4;	data_buf->settings[13].reg = 0x23;	data_buf->settings[13].val = 0xdf;	data_buf->settings[14].reg = 0x25;	data_buf->settings[14].val = 0x07;	data_buf->settings[15].reg = 0x26;	data_buf->settings[15].val = 0xfa;	data_buf->settings[16].reg = 0x27;	data_buf->settings[16].val = 0x00;	data_buf->settings[17].reg = 0x28;	data_buf->settings[17].val = 0xff;	data_buf->settings[18].reg = 0x29;	data_buf->settings[18].val = 0xff;	data_buf->settings[19].reg = 0x2a;	data_buf->settings[19].val = 0xff;	data_buf->settings[20].reg = 0x2b;	data_buf->settings[20].val = 0xe7;	data_buf->settings[21].reg = 0x2c;	data_buf->settings[21].val = 0xff;	data_buf->settings[22].reg = 0x2d;	data_buf->settings[22].val = 0xff;	data_buf->settings[23].reg = 0x2e;	data_buf->settings[23].val = 0xfb;	data_buf->settings[24].reg = 0x30;	data_buf->settings[24].val = 0xf8;	data_buf->settings[25].reg = 0x31;	data_buf->settings[25].val = 0x04;	data_buf->settings[26].reg = 0x32;	data_buf->settings[26].val = 0x94;	data_buf->settings[27].reg = 0x33;	data_buf->settings[27].val = 0x80;	data_buf->settings[28].reg = 0x34;	data_buf->settings[28].val = 0xec;	data_buf->settings[29].reg = 0x38;	data_buf->settings[29].val = 0x50;	data_buf->settings[30].reg = 0x39;	data_buf->settings[30].val = 0x96;	data_buf->settings[31].reg = 0x3a;	data_buf->settings[31].val = 0xa0;	data_buf->settings[32].reg = 0x3b;	data_buf->settings[32].val = 0x05;	data_buf->settings[33].reg = 0x3c;	data_buf->settings[33].val = 0xd0;	data_buf->settings[34].reg = 0x48;	data_buf->settings[34].val = 0x21;	data_buf->settings[35].reg = 0x49;	data_buf->settings[35].val = 0x08;	data_buf->settings[36].reg = 0x4a;	data_buf->settings[36].val = 0xa0;	data_buf->settings[37].reg = 0x4b;	data_buf->settings[37].val = 0x9d;	data_buf->settings[38].reg = 0x4c;	data_buf->settings[38].val = 0x9d;	data_buf->settings[39].reg = 0x4d;	data_buf->settings[39].val = 0xc3;	data_buf->settings[40].reg = 0x24;	data_buf->settings[40].val = 0x1a;	for(i = 0; i < 41; i++) {		if(!adimtv102_writereg(priv, data_buf->settings[i].reg, data_buf->settings[i].val)) {			return 0;		}	}	if(adimtv102_writereg(priv, 0x25, 0x0b))		return 0;	msleep(1);	if(adimtv102_readreg(priv, 0x0f, &read_buf))		return 0;	if(adimtv102_writereg(priv, 0x25, 0x0f))		return 0;	if(adimtv102_writereg(priv, 0x25, (read_buf<<3)|0x07))		return 0;	pllfreq = LO2PLL_Freq((data_buf->frequency)*1000, &LO2PLL_Freq_result);	if(adimtv102_readreg(priv, 0x2f, &read_buf2))		return 0;	pllfreq_shr14 = pllfreq >> 14;	tmp = read_buf2 & 0x1f;	if(pllfreq_shr14 <= 66)		read_buf2 = tmp | 0x40;	else		read_buf2 = tmp;	pllfreq_residue = (pllfreq - (pllfreq_shr14<<14)) << 6;	printk("MTV102>>tp->freq=%d PLLF=%x PLLFREQ=%d MTV10x_REFCLK=%d !\n", data_buf->frequency, pllfreq_residue, pllfreq, 0x4000);	data_buf->settings[0].val = (pllfreq_shr14 & 0xff);	data_buf->settings[1].val = ((pllfreq_shr14 & 0x300) >> 8)|0x7c;	data_buf->settings[3].val = (pllfreq_residue & 0xff00)>>8;	data_buf->settings[2].val = (pllfreq_residue & 0xff);	data_buf->settings[0].reg = 0x1b;	data_buf->settings[1].reg = 0x1a;	tmp = (pllfreq*2) > 2629999 ? 1 : 0;	tmp <<= 7;	data_buf->settings[4].val = tmp | ((pllfreq_residue & 0xf0000)>>16) | (LO2PLL_Freq_result << 4);	data_buf->settings[2].reg = 0x1e;	data_buf->settings[3].reg = 0x1d;	data_buf->settings[4].reg = 0x1c;	tmp = read_buf2;	data_buf->settings[7].val = tmp | 0x80;	data_buf->settings[5].reg = 0x15;	data_buf->settings[5].val = 0x25;	data_buf->settings[6].reg = 0x2f;	data_buf->settings[6].val = tmp; // clear -> set -> clear sequence	data_buf->settings[7].reg = 0x2f;	data_buf->settings[8].reg = 0x2f;	data_buf->settings[8].val = tmp;	return 1;}EXPORT_SYMBOL(adimtv102_compute_regs);void adimtv102_starttuner(struct adimtv102_priv *priv, unsigned short frequency) {	int i;	unsigned char read_buf;	struct adimtv102_reg_struct tp; // tuner parameters	tp.frequency = frequency;	if(!adimtv102_compute_regs(priv, &tp))		return;	for(i = 0; i < 9; i++){		if(adimtv102_writereg(priv, tp.settings[i].reg, tp.settings[i].val))			return;	}	msleep(100);	read_buf = 6;	adimtv102_readreg(priv, 0x06, &read_buf);}EXPORT_SYMBOL(adimtv102_starttuner);static int adimtv102_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params){	struct adimtv102_priv *priv = fe->tuner_priv;	int freq_div1k;	int freq_div1m;	freq_div1k = params->frequency / 1000;	printk("adimtv102_set_params freq=%d\n", freq_div1k);	freq_div1m = freq_div1k / 1000;	adimtv102_starttuner(priv, freq_div1m);	return freq_div1m;}MODULE_AUTHOR("JHA");MODULE_DESCRIPTION("ADI MTV102 silicon tuner driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -