xref: /openbmc/linux/drivers/media/tuners/mt2266.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ccae7af2SMauro Carvalho Chehab /*
3ccae7af2SMauro Carvalho Chehab  *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
4ccae7af2SMauro Carvalho Chehab  *
5ccae7af2SMauro Carvalho Chehab  *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
6ccae7af2SMauro Carvalho Chehab  */
7ccae7af2SMauro Carvalho Chehab 
8ccae7af2SMauro Carvalho Chehab #include <linux/module.h>
9ccae7af2SMauro Carvalho Chehab #include <linux/delay.h>
10ccae7af2SMauro Carvalho Chehab #include <linux/dvb/frontend.h>
11ccae7af2SMauro Carvalho Chehab #include <linux/i2c.h>
12ccae7af2SMauro Carvalho Chehab #include <linux/slab.h>
13ccae7af2SMauro Carvalho Chehab 
14fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
15ccae7af2SMauro Carvalho Chehab #include "mt2266.h"
16ccae7af2SMauro Carvalho Chehab 
17ccae7af2SMauro Carvalho Chehab #define I2C_ADDRESS 0x60
18ccae7af2SMauro Carvalho Chehab 
19ccae7af2SMauro Carvalho Chehab #define REG_PART_REV   0
20ccae7af2SMauro Carvalho Chehab #define REG_TUNE       1
21ccae7af2SMauro Carvalho Chehab #define REG_BAND       6
22ccae7af2SMauro Carvalho Chehab #define REG_BANDWIDTH  8
23ccae7af2SMauro Carvalho Chehab #define REG_LOCK       0x12
24ccae7af2SMauro Carvalho Chehab 
25ccae7af2SMauro Carvalho Chehab #define PART_REV 0x85
26ccae7af2SMauro Carvalho Chehab 
27ccae7af2SMauro Carvalho Chehab struct mt2266_priv {
28ccae7af2SMauro Carvalho Chehab 	struct mt2266_config *cfg;
29ccae7af2SMauro Carvalho Chehab 	struct i2c_adapter   *i2c;
30ccae7af2SMauro Carvalho Chehab 
31ccae7af2SMauro Carvalho Chehab 	u32 frequency;
32ccae7af2SMauro Carvalho Chehab 	u32 bandwidth;
33ccae7af2SMauro Carvalho Chehab 	u8 band;
34ccae7af2SMauro Carvalho Chehab };
35ccae7af2SMauro Carvalho Chehab 
36ccae7af2SMauro Carvalho Chehab #define MT2266_VHF 1
37ccae7af2SMauro Carvalho Chehab #define MT2266_UHF 0
38ccae7af2SMauro Carvalho Chehab 
39ccae7af2SMauro Carvalho Chehab /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
40ccae7af2SMauro Carvalho Chehab 
41ccae7af2SMauro Carvalho Chehab static int debug;
42ccae7af2SMauro Carvalho Chehab module_param(debug, int, 0644);
43ccae7af2SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
44ccae7af2SMauro Carvalho Chehab 
45ccae7af2SMauro Carvalho Chehab #define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
46ccae7af2SMauro Carvalho Chehab 
47ccae7af2SMauro Carvalho Chehab // Reads a single register
mt2266_readreg(struct mt2266_priv * priv,u8 reg,u8 * val)48ccae7af2SMauro Carvalho Chehab static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
49ccae7af2SMauro Carvalho Chehab {
50ccae7af2SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
51ccae7af2SMauro Carvalho Chehab 		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
52ccae7af2SMauro Carvalho Chehab 		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
53ccae7af2SMauro Carvalho Chehab 	};
54ccae7af2SMauro Carvalho Chehab 	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
55ccae7af2SMauro Carvalho Chehab 		printk(KERN_WARNING "MT2266 I2C read failed\n");
56ccae7af2SMauro Carvalho Chehab 		return -EREMOTEIO;
57ccae7af2SMauro Carvalho Chehab 	}
58ccae7af2SMauro Carvalho Chehab 	return 0;
59ccae7af2SMauro Carvalho Chehab }
60ccae7af2SMauro Carvalho Chehab 
61ccae7af2SMauro Carvalho Chehab // Writes a single register
mt2266_writereg(struct mt2266_priv * priv,u8 reg,u8 val)62ccae7af2SMauro Carvalho Chehab static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
63ccae7af2SMauro Carvalho Chehab {
64ccae7af2SMauro Carvalho Chehab 	u8 buf[2] = { reg, val };
65ccae7af2SMauro Carvalho Chehab 	struct i2c_msg msg = {
66ccae7af2SMauro Carvalho Chehab 		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
67ccae7af2SMauro Carvalho Chehab 	};
68ccae7af2SMauro Carvalho Chehab 	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
69ccae7af2SMauro Carvalho Chehab 		printk(KERN_WARNING "MT2266 I2C write failed\n");
70ccae7af2SMauro Carvalho Chehab 		return -EREMOTEIO;
71ccae7af2SMauro Carvalho Chehab 	}
72ccae7af2SMauro Carvalho Chehab 	return 0;
73ccae7af2SMauro Carvalho Chehab }
74ccae7af2SMauro Carvalho Chehab 
75ccae7af2SMauro Carvalho Chehab // Writes a set of consecutive registers
mt2266_writeregs(struct mt2266_priv * priv,u8 * buf,u8 len)76ccae7af2SMauro Carvalho Chehab static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
77ccae7af2SMauro Carvalho Chehab {
78ccae7af2SMauro Carvalho Chehab 	struct i2c_msg msg = {
79ccae7af2SMauro Carvalho Chehab 		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
80ccae7af2SMauro Carvalho Chehab 	};
81ccae7af2SMauro Carvalho Chehab 	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
82ccae7af2SMauro Carvalho Chehab 		printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
83ccae7af2SMauro Carvalho Chehab 		return -EREMOTEIO;
84ccae7af2SMauro Carvalho Chehab 	}
85ccae7af2SMauro Carvalho Chehab 	return 0;
86ccae7af2SMauro Carvalho Chehab }
87ccae7af2SMauro Carvalho Chehab 
88ccae7af2SMauro Carvalho Chehab // Initialisation sequences
89ccae7af2SMauro Carvalho Chehab static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
90ccae7af2SMauro Carvalho Chehab 				 0x00, 0x52, 0x99, 0x3f };
91ccae7af2SMauro Carvalho Chehab 
92ccae7af2SMauro Carvalho Chehab static u8 mt2266_init2[] = {
93ccae7af2SMauro Carvalho Chehab     0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
94ccae7af2SMauro Carvalho Chehab     0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
95ccae7af2SMauro Carvalho Chehab     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
96ccae7af2SMauro Carvalho Chehab     0xff, 0x00, 0x77, 0x0f, 0x2d
97ccae7af2SMauro Carvalho Chehab };
98ccae7af2SMauro Carvalho Chehab 
99ccae7af2SMauro Carvalho Chehab static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
100ccae7af2SMauro Carvalho Chehab 						0x22, 0x22, 0x22, 0x22 };
101ccae7af2SMauro Carvalho Chehab 
102ccae7af2SMauro Carvalho Chehab static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
103ccae7af2SMauro Carvalho Chehab 						0x32, 0x32, 0x32, 0x32 };
104ccae7af2SMauro Carvalho Chehab 
105ccae7af2SMauro Carvalho Chehab static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
106ccae7af2SMauro Carvalho Chehab 						0xa7, 0xa7, 0xa7, 0xa7 };
107ccae7af2SMauro Carvalho Chehab 
108ccae7af2SMauro Carvalho Chehab static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
109ccae7af2SMauro Carvalho Chehab 			   0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
110ccae7af2SMauro Carvalho Chehab 
111ccae7af2SMauro Carvalho Chehab static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
112ccae7af2SMauro Carvalho Chehab 			   0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
113ccae7af2SMauro Carvalho Chehab 
114ccae7af2SMauro Carvalho Chehab #define FREF 30000       // Quartz oscillator 30 MHz
115ccae7af2SMauro Carvalho Chehab 
mt2266_set_params(struct dvb_frontend * fe)116ccae7af2SMauro Carvalho Chehab static int mt2266_set_params(struct dvb_frontend *fe)
117ccae7af2SMauro Carvalho Chehab {
118ccae7af2SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
119ccae7af2SMauro Carvalho Chehab 	struct mt2266_priv *priv;
120ccae7af2SMauro Carvalho Chehab 	int ret=0;
121ccae7af2SMauro Carvalho Chehab 	u32 freq;
122ccae7af2SMauro Carvalho Chehab 	u32 tune;
123ccae7af2SMauro Carvalho Chehab 	u8  lnaband;
124ccae7af2SMauro Carvalho Chehab 	u8  b[10];
125ccae7af2SMauro Carvalho Chehab 	int i;
126ccae7af2SMauro Carvalho Chehab 	u8 band;
127ccae7af2SMauro Carvalho Chehab 
128ccae7af2SMauro Carvalho Chehab 	priv = fe->tuner_priv;
129ccae7af2SMauro Carvalho Chehab 
130ccae7af2SMauro Carvalho Chehab 	freq = priv->frequency / 1000; /* Hz -> kHz */
131ccae7af2SMauro Carvalho Chehab 	if (freq < 470000 && freq > 230000)
132ccae7af2SMauro Carvalho Chehab 		return -EINVAL; /* Gap between VHF and UHF bands */
133ccae7af2SMauro Carvalho Chehab 
134ccae7af2SMauro Carvalho Chehab 	priv->frequency = c->frequency;
135ccae7af2SMauro Carvalho Chehab 	tune = 2 * freq * (8192/16) / (FREF/16);
136ccae7af2SMauro Carvalho Chehab 	band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
137ccae7af2SMauro Carvalho Chehab 	if (band == MT2266_VHF)
138ccae7af2SMauro Carvalho Chehab 		tune *= 2;
139ccae7af2SMauro Carvalho Chehab 
140ccae7af2SMauro Carvalho Chehab 	switch (c->bandwidth_hz) {
141ccae7af2SMauro Carvalho Chehab 	case 6000000:
142ccae7af2SMauro Carvalho Chehab 		mt2266_writeregs(priv, mt2266_init_6mhz,
143ccae7af2SMauro Carvalho Chehab 				 sizeof(mt2266_init_6mhz));
144ccae7af2SMauro Carvalho Chehab 		break;
145ccae7af2SMauro Carvalho Chehab 	case 8000000:
146ccae7af2SMauro Carvalho Chehab 		mt2266_writeregs(priv, mt2266_init_8mhz,
147ccae7af2SMauro Carvalho Chehab 				 sizeof(mt2266_init_8mhz));
148ccae7af2SMauro Carvalho Chehab 		break;
149ccae7af2SMauro Carvalho Chehab 	case 7000000:
150ccae7af2SMauro Carvalho Chehab 	default:
151ccae7af2SMauro Carvalho Chehab 		mt2266_writeregs(priv, mt2266_init_7mhz,
152ccae7af2SMauro Carvalho Chehab 				 sizeof(mt2266_init_7mhz));
153ccae7af2SMauro Carvalho Chehab 		break;
154ccae7af2SMauro Carvalho Chehab 	}
155ccae7af2SMauro Carvalho Chehab 	priv->bandwidth = c->bandwidth_hz;
156ccae7af2SMauro Carvalho Chehab 
157ccae7af2SMauro Carvalho Chehab 	if (band == MT2266_VHF && priv->band == MT2266_UHF) {
158ccae7af2SMauro Carvalho Chehab 		dprintk("Switch from UHF to VHF");
159ccae7af2SMauro Carvalho Chehab 		mt2266_writereg(priv, 0x05, 0x04);
160ccae7af2SMauro Carvalho Chehab 		mt2266_writereg(priv, 0x19, 0x61);
161ccae7af2SMauro Carvalho Chehab 		mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
162ccae7af2SMauro Carvalho Chehab 	} else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
163ccae7af2SMauro Carvalho Chehab 		dprintk("Switch from VHF to UHF");
164ccae7af2SMauro Carvalho Chehab 		mt2266_writereg(priv, 0x05, 0x52);
165ccae7af2SMauro Carvalho Chehab 		mt2266_writereg(priv, 0x19, 0x61);
166ccae7af2SMauro Carvalho Chehab 		mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
167ccae7af2SMauro Carvalho Chehab 	}
168ccae7af2SMauro Carvalho Chehab 	msleep(10);
169ccae7af2SMauro Carvalho Chehab 
170ccae7af2SMauro Carvalho Chehab 	if (freq <= 495000)
171ccae7af2SMauro Carvalho Chehab 		lnaband = 0xEE;
172ccae7af2SMauro Carvalho Chehab 	else if (freq <= 525000)
173ccae7af2SMauro Carvalho Chehab 		lnaband = 0xDD;
174ccae7af2SMauro Carvalho Chehab 	else if (freq <= 550000)
175ccae7af2SMauro Carvalho Chehab 		lnaband = 0xCC;
176ccae7af2SMauro Carvalho Chehab 	else if (freq <= 580000)
177ccae7af2SMauro Carvalho Chehab 		lnaband = 0xBB;
178ccae7af2SMauro Carvalho Chehab 	else if (freq <= 605000)
179ccae7af2SMauro Carvalho Chehab 		lnaband = 0xAA;
180ccae7af2SMauro Carvalho Chehab 	else if (freq <= 630000)
181ccae7af2SMauro Carvalho Chehab 		lnaband = 0x99;
182ccae7af2SMauro Carvalho Chehab 	else if (freq <= 655000)
183ccae7af2SMauro Carvalho Chehab 		lnaband = 0x88;
184ccae7af2SMauro Carvalho Chehab 	else if (freq <= 685000)
185ccae7af2SMauro Carvalho Chehab 		lnaband = 0x77;
186ccae7af2SMauro Carvalho Chehab 	else if (freq <= 710000)
187ccae7af2SMauro Carvalho Chehab 		lnaband = 0x66;
188ccae7af2SMauro Carvalho Chehab 	else if (freq <= 735000)
189ccae7af2SMauro Carvalho Chehab 		lnaband = 0x55;
190ccae7af2SMauro Carvalho Chehab 	else if (freq <= 765000)
191ccae7af2SMauro Carvalho Chehab 		lnaband = 0x44;
192ccae7af2SMauro Carvalho Chehab 	else if (freq <= 802000)
193ccae7af2SMauro Carvalho Chehab 		lnaband = 0x33;
194ccae7af2SMauro Carvalho Chehab 	else if (freq <= 840000)
195ccae7af2SMauro Carvalho Chehab 		lnaband = 0x22;
196ccae7af2SMauro Carvalho Chehab 	else
197ccae7af2SMauro Carvalho Chehab 		lnaband = 0x11;
198ccae7af2SMauro Carvalho Chehab 
199ccae7af2SMauro Carvalho Chehab 	b[0] = REG_TUNE;
200ccae7af2SMauro Carvalho Chehab 	b[1] = (tune >> 8) & 0x1F;
201ccae7af2SMauro Carvalho Chehab 	b[2] = tune & 0xFF;
202ccae7af2SMauro Carvalho Chehab 	b[3] = tune >> 13;
203ccae7af2SMauro Carvalho Chehab 	mt2266_writeregs(priv,b,4);
204ccae7af2SMauro Carvalho Chehab 
205ccae7af2SMauro Carvalho Chehab 	dprintk("set_parms: tune=%d band=%d %s",
206ccae7af2SMauro Carvalho Chehab 		(int) tune, (int) lnaband,
207ccae7af2SMauro Carvalho Chehab 		(band == MT2266_UHF) ? "UHF" : "VHF");
208ccae7af2SMauro Carvalho Chehab 	dprintk("set_parms: [1..3]: %2x %2x %2x",
209ccae7af2SMauro Carvalho Chehab 		(int) b[1], (int) b[2], (int)b[3]);
210ccae7af2SMauro Carvalho Chehab 
211ccae7af2SMauro Carvalho Chehab 	if (band == MT2266_UHF) {
212ccae7af2SMauro Carvalho Chehab 		b[0] = 0x05;
213ccae7af2SMauro Carvalho Chehab 		b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
214ccae7af2SMauro Carvalho Chehab 		b[2] = lnaband;
215ccae7af2SMauro Carvalho Chehab 		mt2266_writeregs(priv, b, 3);
216ccae7af2SMauro Carvalho Chehab 	}
217ccae7af2SMauro Carvalho Chehab 
218ccae7af2SMauro Carvalho Chehab 	/* Wait for pll lock or timeout */
219ccae7af2SMauro Carvalho Chehab 	i = 0;
220ccae7af2SMauro Carvalho Chehab 	do {
221ccae7af2SMauro Carvalho Chehab 		mt2266_readreg(priv,REG_LOCK,b);
222ccae7af2SMauro Carvalho Chehab 		if (b[0] & 0x40)
223ccae7af2SMauro Carvalho Chehab 			break;
224ccae7af2SMauro Carvalho Chehab 		msleep(10);
225ccae7af2SMauro Carvalho Chehab 		i++;
226ccae7af2SMauro Carvalho Chehab 	} while (i<10);
227ccae7af2SMauro Carvalho Chehab 	dprintk("Lock when i=%i",(int)i);
228ccae7af2SMauro Carvalho Chehab 
229ccae7af2SMauro Carvalho Chehab 	if (band == MT2266_UHF && priv->band == MT2266_VHF)
230ccae7af2SMauro Carvalho Chehab 		mt2266_writereg(priv, 0x05, 0x62);
231ccae7af2SMauro Carvalho Chehab 
232ccae7af2SMauro Carvalho Chehab 	priv->band = band;
233ccae7af2SMauro Carvalho Chehab 
234ccae7af2SMauro Carvalho Chehab 	return ret;
235ccae7af2SMauro Carvalho Chehab }
236ccae7af2SMauro Carvalho Chehab 
mt2266_calibrate(struct mt2266_priv * priv)237ccae7af2SMauro Carvalho Chehab static void mt2266_calibrate(struct mt2266_priv *priv)
238ccae7af2SMauro Carvalho Chehab {
239ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x11, 0x03);
240ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x11, 0x01);
241ccae7af2SMauro Carvalho Chehab 	mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
242ccae7af2SMauro Carvalho Chehab 	mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
243ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x33, 0x5e);
244ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x10, 0x10);
245ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x10, 0x00);
246ccae7af2SMauro Carvalho Chehab 	mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
247ccae7af2SMauro Carvalho Chehab 	msleep(25);
248ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x17, 0x6d);
249ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x1c, 0x00);
250ccae7af2SMauro Carvalho Chehab 	msleep(75);
251ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x17, 0x6d);
252ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x1c, 0xff);
253ccae7af2SMauro Carvalho Chehab }
254ccae7af2SMauro Carvalho Chehab 
mt2266_get_frequency(struct dvb_frontend * fe,u32 * frequency)255ccae7af2SMauro Carvalho Chehab static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
256ccae7af2SMauro Carvalho Chehab {
257ccae7af2SMauro Carvalho Chehab 	struct mt2266_priv *priv = fe->tuner_priv;
258ccae7af2SMauro Carvalho Chehab 	*frequency = priv->frequency;
259ccae7af2SMauro Carvalho Chehab 	return 0;
260ccae7af2SMauro Carvalho Chehab }
261ccae7af2SMauro Carvalho Chehab 
mt2266_get_bandwidth(struct dvb_frontend * fe,u32 * bandwidth)262ccae7af2SMauro Carvalho Chehab static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
263ccae7af2SMauro Carvalho Chehab {
264ccae7af2SMauro Carvalho Chehab 	struct mt2266_priv *priv = fe->tuner_priv;
265ccae7af2SMauro Carvalho Chehab 	*bandwidth = priv->bandwidth;
266ccae7af2SMauro Carvalho Chehab 	return 0;
267ccae7af2SMauro Carvalho Chehab }
268ccae7af2SMauro Carvalho Chehab 
mt2266_init(struct dvb_frontend * fe)269ccae7af2SMauro Carvalho Chehab static int mt2266_init(struct dvb_frontend *fe)
270ccae7af2SMauro Carvalho Chehab {
271ccae7af2SMauro Carvalho Chehab 	int ret;
272ccae7af2SMauro Carvalho Chehab 	struct mt2266_priv *priv = fe->tuner_priv;
273ccae7af2SMauro Carvalho Chehab 	ret = mt2266_writereg(priv, 0x17, 0x6d);
274ccae7af2SMauro Carvalho Chehab 	if (ret < 0)
275ccae7af2SMauro Carvalho Chehab 		return ret;
276ccae7af2SMauro Carvalho Chehab 	ret = mt2266_writereg(priv, 0x1c, 0xff);
277ccae7af2SMauro Carvalho Chehab 	if (ret < 0)
278ccae7af2SMauro Carvalho Chehab 		return ret;
279ccae7af2SMauro Carvalho Chehab 	return 0;
280ccae7af2SMauro Carvalho Chehab }
281ccae7af2SMauro Carvalho Chehab 
mt2266_sleep(struct dvb_frontend * fe)282ccae7af2SMauro Carvalho Chehab static int mt2266_sleep(struct dvb_frontend *fe)
283ccae7af2SMauro Carvalho Chehab {
284ccae7af2SMauro Carvalho Chehab 	struct mt2266_priv *priv = fe->tuner_priv;
285ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x17, 0x6d);
286ccae7af2SMauro Carvalho Chehab 	mt2266_writereg(priv, 0x1c, 0x00);
287ccae7af2SMauro Carvalho Chehab 	return 0;
288ccae7af2SMauro Carvalho Chehab }
289ccae7af2SMauro Carvalho Chehab 
mt2266_release(struct dvb_frontend * fe)290f2709c20SMauro Carvalho Chehab static void mt2266_release(struct dvb_frontend *fe)
291f2709c20SMauro Carvalho Chehab {
292f2709c20SMauro Carvalho Chehab 	kfree(fe->tuner_priv);
293f2709c20SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
294f2709c20SMauro Carvalho Chehab }
295f2709c20SMauro Carvalho Chehab 
296ccae7af2SMauro Carvalho Chehab static const struct dvb_tuner_ops mt2266_tuner_ops = {
297ccae7af2SMauro Carvalho Chehab 	.info = {
298ccae7af2SMauro Carvalho Chehab 		.name              = "Microtune MT2266",
299a3f90c75SMauro Carvalho Chehab 		.frequency_min_hz  = 174 * MHz,
300a3f90c75SMauro Carvalho Chehab 		.frequency_max_hz  = 862 * MHz,
301a3f90c75SMauro Carvalho Chehab 		.frequency_step_hz =  50 * kHz,
302ccae7af2SMauro Carvalho Chehab 	},
303f2709c20SMauro Carvalho Chehab 	.release       = mt2266_release,
304ccae7af2SMauro Carvalho Chehab 	.init          = mt2266_init,
305ccae7af2SMauro Carvalho Chehab 	.sleep         = mt2266_sleep,
306ccae7af2SMauro Carvalho Chehab 	.set_params    = mt2266_set_params,
307ccae7af2SMauro Carvalho Chehab 	.get_frequency = mt2266_get_frequency,
308ccae7af2SMauro Carvalho Chehab 	.get_bandwidth = mt2266_get_bandwidth
309ccae7af2SMauro Carvalho Chehab };
310ccae7af2SMauro Carvalho Chehab 
mt2266_attach(struct dvb_frontend * fe,struct i2c_adapter * i2c,struct mt2266_config * cfg)311ccae7af2SMauro Carvalho Chehab struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
312ccae7af2SMauro Carvalho Chehab {
313ccae7af2SMauro Carvalho Chehab 	struct mt2266_priv *priv = NULL;
314ccae7af2SMauro Carvalho Chehab 	u8 id = 0;
315ccae7af2SMauro Carvalho Chehab 
316ccae7af2SMauro Carvalho Chehab 	priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
317ccae7af2SMauro Carvalho Chehab 	if (priv == NULL)
318ccae7af2SMauro Carvalho Chehab 		return NULL;
319ccae7af2SMauro Carvalho Chehab 
320ccae7af2SMauro Carvalho Chehab 	priv->cfg      = cfg;
321ccae7af2SMauro Carvalho Chehab 	priv->i2c      = i2c;
322ccae7af2SMauro Carvalho Chehab 	priv->band     = MT2266_UHF;
323ccae7af2SMauro Carvalho Chehab 
324ccae7af2SMauro Carvalho Chehab 	if (mt2266_readreg(priv, 0, &id)) {
325ccae7af2SMauro Carvalho Chehab 		kfree(priv);
326ccae7af2SMauro Carvalho Chehab 		return NULL;
327ccae7af2SMauro Carvalho Chehab 	}
328ccae7af2SMauro Carvalho Chehab 	if (id != PART_REV) {
329ccae7af2SMauro Carvalho Chehab 		kfree(priv);
330ccae7af2SMauro Carvalho Chehab 		return NULL;
331ccae7af2SMauro Carvalho Chehab 	}
332ccae7af2SMauro Carvalho Chehab 	printk(KERN_INFO "MT2266: successfully identified\n");
333ccae7af2SMauro Carvalho Chehab 	memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
334ccae7af2SMauro Carvalho Chehab 
335ccae7af2SMauro Carvalho Chehab 	fe->tuner_priv = priv;
336ccae7af2SMauro Carvalho Chehab 	mt2266_calibrate(priv);
337ccae7af2SMauro Carvalho Chehab 	return fe;
338ccae7af2SMauro Carvalho Chehab }
339*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(mt2266_attach);
340ccae7af2SMauro Carvalho Chehab 
341ccae7af2SMauro Carvalho Chehab MODULE_AUTHOR("Olivier DANET");
342ccae7af2SMauro Carvalho Chehab MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
343ccae7af2SMauro Carvalho Chehab MODULE_LICENSE("GPL");
344