154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET/*
254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *
454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *
654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  This program is free software; you can redistribute it and/or modify
754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  it under the terms of the GNU General Public License as published by
854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  the Free Software Foundation; either version 2 of the License, or
954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  (at your option) any later version.
1054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *
1154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  This program is distributed in the hope that it will be useful,
1254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET *  GNU General Public License for more details.
1554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET */
1654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
1754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#include <linux/module.h>
1854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#include <linux/delay.h>
1954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#include <linux/dvb/frontend.h>
2054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#include <linux/i2c.h>
215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
2254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
2354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#include "dvb_frontend.h"
2454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#include "mt2266.h"
2554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
2654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define I2C_ADDRESS 0x60
2754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
2854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define REG_PART_REV   0
2954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define REG_TUNE       1
3054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define REG_BAND       6
3154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define REG_BANDWIDTH  8
3254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define REG_LOCK       0x12
3354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
3454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define PART_REV 0x85
3554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
3654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstruct mt2266_priv {
3754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct mt2266_config *cfg;
3854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct i2c_adapter   *i2c;
3954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
4054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	u32 frequency;
4154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	u32 bandwidth;
42542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	u8 band;
4354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET};
4454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
45542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET#define MT2266_VHF 1
46542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET#define MT2266_UHF 0
47542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
4854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
4954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
5054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int debug;
5154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETmodule_param(debug, int, 0644);
5254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
5354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
5454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
5554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
5654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET// Reads a single register
5754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
5854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
5954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct i2c_msg msg[2] = {
6054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
6154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
6254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	};
6354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
6454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		printk(KERN_WARNING "MT2266 I2C read failed\n");
6554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		return -EREMOTEIO;
6654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	}
6754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return 0;
6854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
6954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
7054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET// Writes a single register
7154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
7254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
7354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	u8 buf[2] = { reg, val };
7454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct i2c_msg msg = {
7554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
7654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	};
7754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
7854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		printk(KERN_WARNING "MT2266 I2C write failed\n");
7954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		return -EREMOTEIO;
8054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	}
8154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return 0;
8254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
8354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
8454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET// Writes a set of consecutive registers
8554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
8654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
8754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct i2c_msg msg = {
8854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
8954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	};
9054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
9154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
9254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		return -EREMOTEIO;
9354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	}
9454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return 0;
9554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
9654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
9754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET// Initialisation sequences
98542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANETstatic u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
99542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET				 0x00, 0x52, 0x99, 0x3f };
10054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
10154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic u8 mt2266_init2[] = {
102542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET    0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
103542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET    0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
104542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
105542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET    0xff, 0x00, 0x77, 0x0f, 0x2d
106542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET};
107542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
108542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANETstatic u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
109542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET						0x22, 0x22, 0x22, 0x22 };
11054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
111542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANETstatic u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
112542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET						0x32, 0x32, 0x32, 0x32 };
11354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
114542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANETstatic u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
115542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET						0xa7, 0xa7, 0xa7, 0xa7 };
11654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
117542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANETstatic u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
118542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET			   0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
119542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
120542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANETstatic u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
121542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET			   0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
12254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
12354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET#define FREF 30000       // Quartz oscillator 30 MHz
12454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
12514d24d148c7521b2b88b396652e36f55d061e195Mauro Carvalho Chehabstatic int mt2266_set_params(struct dvb_frontend *fe)
12654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
12782c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
12854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct mt2266_priv *priv;
12954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	int ret=0;
13054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	u32 freq;
13154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	u32 tune;
13254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	u8  lnaband;
13354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	u8  b[10];
13454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	int i;
135542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	u8 band;
13654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
13754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	priv = fe->tuner_priv;
13854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
13982c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab	freq = priv->frequency / 1000; /* Hz -> kHz */
140542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (freq < 470000 && freq > 230000)
141542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		return -EINVAL; /* Gap between VHF and UHF bands */
142542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
14382c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab	priv->frequency = c->frequency;
144542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	tune = 2 * freq * (8192/16) / (FREF/16);
145542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
146542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (band == MT2266_VHF)
147542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		tune *= 2;
148542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
14982c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab	switch (c->bandwidth_hz) {
15082c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab	case 6000000:
151542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writeregs(priv, mt2266_init_6mhz,
152542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET				 sizeof(mt2266_init_6mhz));
153542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		break;
15482c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab	case 8000000:
155542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writeregs(priv, mt2266_init_8mhz,
156542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET				 sizeof(mt2266_init_8mhz));
15782c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab		break;
15882c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab	case 7000000:
15982c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab	default:
16082c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab		mt2266_writeregs(priv, mt2266_init_7mhz,
16182c0126ff2e3278ecf1d6c7d0bf71838e189dbdcMauro Carvalho Chehab				 sizeof(mt2266_init_7mhz));
162542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		break;
163542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	}
164c6f56e7d794cba022353d464dfa3383d1b3e0125Mauro Carvalho Chehab	priv->bandwidth = c->bandwidth_hz;
165542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
166542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (band == MT2266_VHF && priv->band == MT2266_UHF) {
167542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		dprintk("Switch from UHF to VHF");
168542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writereg(priv, 0x05, 0x04);
169542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writereg(priv, 0x19, 0x61);
170542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
171542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	} else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
172542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		dprintk("Switch from VHF to UHF");
173542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writereg(priv, 0x05, 0x52);
174542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writereg(priv, 0x19, 0x61);
175542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
176542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	}
177542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	msleep(10);
178542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
179542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (freq <= 495000)
180542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0xEE;
181542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 525000)
182542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0xDD;
183542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 550000)
184542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0xCC;
185542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 580000)
186542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0xBB;
187542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 605000)
188542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0xAA;
189542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 630000)
190542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x99;
191542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 655000)
192542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x88;
193542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 685000)
194542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x77;
195542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 710000)
196542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x66;
197542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 735000)
198542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x55;
199542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 765000)
200542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x44;
201542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 802000)
202542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x33;
203542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else if (freq <= 840000)
204542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x22;
205542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	else
206542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		lnaband = 0x11;
20754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
20854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	b[0] = REG_TUNE;
20954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	b[1] = (tune >> 8) & 0x1F;
21054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	b[2] = tune & 0xFF;
21154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	b[3] = tune >> 13;
21254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	mt2266_writeregs(priv,b,4);
21354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
214542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	dprintk("set_parms: tune=%d band=%d %s",
215542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		(int) tune, (int) lnaband,
216542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		(band == MT2266_UHF) ? "UHF" : "VHF");
217542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	dprintk("set_parms: [1..3]: %2x %2x %2x",
218542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		(int) b[1], (int) b[2], (int)b[3]);
219542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
220542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (band == MT2266_UHF) {
221542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		b[0] = 0x05;
222542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
223542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		b[2] = lnaband;
224542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writeregs(priv, b, 3);
225542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	}
22654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
227542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	/* Wait for pll lock or timeout */
22854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	i = 0;
22954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	do {
23054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		mt2266_readreg(priv,REG_LOCK,b);
231542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		if (b[0] & 0x40)
23254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET			break;
23354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		msleep(10);
23454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		i++;
23554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	} while (i<10);
236b6884a17fc70e979ef34e4b5560988b522bb50a0Patrick Boettcher	dprintk("Lock when i=%i",(int)i);
237542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
238542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (band == MT2266_UHF && priv->band == MT2266_VHF)
239542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		mt2266_writereg(priv, 0x05, 0x62);
240542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
241542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	priv->band = band;
242542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET
24354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return ret;
24454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
24554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
24654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic void mt2266_calibrate(struct mt2266_priv *priv)
24754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
248542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x11, 0x03);
249542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x11, 0x01);
250542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
251542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
252542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x33, 0x5e);
253542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x10, 0x10);
254542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x10, 0x00);
255542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
25654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	msleep(25);
257542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x17, 0x6d);
258542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x1c, 0x00);
25954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	msleep(75);
260542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x17, 0x6d);
261542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x1c, 0xff);
26254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
26354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
26454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
26554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
26654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct mt2266_priv *priv = fe->tuner_priv;
26754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	*frequency = priv->frequency;
26854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return 0;
26954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
27054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
27154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
27254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
27354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct mt2266_priv *priv = fe->tuner_priv;
27454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	*bandwidth = priv->bandwidth;
27554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return 0;
27654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
27754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
27854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int mt2266_init(struct dvb_frontend *fe)
27954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
280542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	int ret;
28154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct mt2266_priv *priv = fe->tuner_priv;
282542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	ret = mt2266_writereg(priv, 0x17, 0x6d);
283542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (ret < 0)
284542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		return ret;
285542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	ret = mt2266_writereg(priv, 0x1c, 0xff);
286542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (ret < 0)
287542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		return ret;
28854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return 0;
28954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
29054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
29154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int mt2266_sleep(struct dvb_frontend *fe)
29254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
29354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct mt2266_priv *priv = fe->tuner_priv;
294542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x17, 0x6d);
295542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	mt2266_writereg(priv, 0x1c, 0x00);
29654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return 0;
29754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
29854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
29954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic int mt2266_release(struct dvb_frontend *fe)
30054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
30154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	kfree(fe->tuner_priv);
30254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	fe->tuner_priv = NULL;
30354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return 0;
30454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
30554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
30654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstatic const struct dvb_tuner_ops mt2266_tuner_ops = {
30754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	.info = {
30854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		.name           = "Microtune MT2266",
309542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		.frequency_min  = 174000000,
310542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET		.frequency_max  = 862000000,
31154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		.frequency_step =     50000,
31254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	},
31354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	.release       = mt2266_release,
31454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	.init          = mt2266_init,
31554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	.sleep         = mt2266_sleep,
31654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	.set_params    = mt2266_set_params,
31754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	.get_frequency = mt2266_get_frequency,
31854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	.get_bandwidth = mt2266_get_bandwidth
31954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET};
32054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
32154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETstruct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
32254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET{
32354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	struct mt2266_priv *priv = NULL;
32454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	u8 id = 0;
32554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
32654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
32754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	if (priv == NULL)
32854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		return NULL;
32954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
33054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	priv->cfg      = cfg;
33154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	priv->i2c      = i2c;
332542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	priv->band     = MT2266_UHF;
33354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
334542794be2caf46b5fe95cbb7cd878d884597647eOlivier DANET	if (mt2266_readreg(priv, 0, &id)) {
33554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		kfree(priv);
33654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		return NULL;
33754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	}
33854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	if (id != PART_REV) {
33954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		kfree(priv);
34054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET		return NULL;
34154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	}
34254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	printk(KERN_INFO "MT2266: successfully identified\n");
34354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
34454d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
34554d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	fe->tuner_priv = priv;
34654d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	mt2266_calibrate(priv);
34754d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET	return fe;
34854d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET}
34954d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETEXPORT_SYMBOL(mt2266_attach);
35054d75ebaa02809f24a16624e32706af3bf97588eOlivier DANET
35154d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETMODULE_AUTHOR("Olivier DANET");
35254d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETMODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
35354d75ebaa02809f24a16624e32706af3bf97588eOlivier DANETMODULE_LICENSE("GPL");
354