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 = ®, .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