aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/common
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2008-04-29 20:38:45 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-29 17:41:38 -0400
commitb094516f9589245617eb5d0452769826063f72ac (patch)
tree45593c7f1ae4c180d97ed7b9cbc27a85c03f55d1 /drivers/media/common
parentdf7aaaf3a74016cbc72382b6388c7c62f3df49b2 (diff)
V4L/DVB (7769): Move other terrestrial tuners to common/tuners
Those tuners are currently used only under media/dvb. However, they can support also analog TV. Better to move them to the same place as the other hybrid tuners. This would make easier to use those tuners also by analog drivers. Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/common')
-rw-r--r--drivers/media/common/tuners/Kconfig28
-rw-r--r--drivers/media/common/tuners/Makefile4
-rw-r--r--drivers/media/common/tuners/mt2060.c369
-rw-r--r--drivers/media/common/tuners/mt2060.h43
-rw-r--r--drivers/media/common/tuners/mt2060_priv.h105
-rw-r--r--drivers/media/common/tuners/mt2131.c314
-rw-r--r--drivers/media/common/tuners/mt2131.h54
-rw-r--r--drivers/media/common/tuners/mt2131_priv.h49
-rw-r--r--drivers/media/common/tuners/mt2266.c351
-rw-r--r--drivers/media/common/tuners/mt2266.h37
-rw-r--r--drivers/media/common/tuners/qt1010.c485
-rw-r--r--drivers/media/common/tuners/qt1010.h53
-rw-r--r--drivers/media/common/tuners/qt1010_priv.h105
13 files changed, 1997 insertions, 0 deletions
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 9a6a9022e970..e6926e9fa332 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -99,6 +99,34 @@ config TUNER_MT20XX
99 help 99 help
100 Say Y here to include support for the MT2032 / MT2050 tuner. 100 Say Y here to include support for the MT2032 / MT2050 tuner.
101 101
102config DVB_TUNER_MT2060
103 tristate "Microtune MT2060 silicon IF tuner"
104 depends on I2C
105 default m if DVB_FE_CUSTOMISE
106 help
107 A driver for the silicon IF tuner MT2060 from Microtune.
108
109config DVB_TUNER_MT2266
110 tristate "Microtune MT2266 silicon tuner"
111 depends on I2C
112 default m if DVB_FE_CUSTOMISE
113 help
114 A driver for the silicon baseband tuner MT2266 from Microtune.
115
116config DVB_TUNER_MT2131
117 tristate "Microtune MT2131 silicon tuner"
118 depends on I2C
119 default m if DVB_FE_CUSTOMISE
120 help
121 A driver for the silicon baseband tuner MT2131 from Microtune.
122
123config DVB_TUNER_QT1010
124 tristate "Quantek QT1010 silicon tuner"
125 depends on DVB_CORE && I2C
126 default m if DVB_FE_CUSTOMISE
127 help
128 A driver for the silicon tuner QT1010 from Quantek.
129
102config TUNER_XC2028 130config TUNER_XC2028
103 tristate "XCeive xc2028/xc3028 tuners" 131 tristate "XCeive xc2028/xc3028 tuners"
104 depends on I2C && FW_LOADER 132 depends on I2C && FW_LOADER
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index 685ae64fa3b8..812864312628 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -16,6 +16,10 @@ obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
16obj-$(CONFIG_DVB_TDA827X) += tda827x.o 16obj-$(CONFIG_DVB_TDA827X) += tda827x.o
17obj-$(CONFIG_DVB_TDA18271) += tda18271.o 17obj-$(CONFIG_DVB_TDA18271) += tda18271.o
18obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o 18obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
19obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
20obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
21obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
22obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
19 23
20EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core 24EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
21EXTRA_CFLAGS += -Idrivers/media/dvb/frontends 25EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c
new file mode 100644
index 000000000000..1305b0e63ce5
--- /dev/null
+++ b/drivers/media/common/tuners/mt2060.c
@@ -0,0 +1,369 @@
1/*
2 * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
3 *
4 * Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
20 */
21
22/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
23
24#include <linux/module.h>
25#include <linux/delay.h>
26#include <linux/dvb/frontend.h>
27#include <linux/i2c.h>
28
29#include "dvb_frontend.h"
30
31#include "mt2060.h"
32#include "mt2060_priv.h"
33
34static int debug;
35module_param(debug, int, 0644);
36MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
37
38#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0)
39
40// Reads a single register
41static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val)
42{
43 struct i2c_msg msg[2] = {
44 { .addr = priv->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
45 { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 },
46 };
47
48 if (i2c_transfer(priv->i2c, msg, 2) != 2) {
49 printk(KERN_WARNING "mt2060 I2C read failed\n");
50 return -EREMOTEIO;
51 }
52 return 0;
53}
54
55// Writes a single register
56static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
57{
58 u8 buf[2] = { reg, val };
59 struct i2c_msg msg = {
60 .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
61 };
62
63 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
64 printk(KERN_WARNING "mt2060 I2C write failed\n");
65 return -EREMOTEIO;
66 }
67 return 0;
68}
69
70// Writes a set of consecutive registers
71static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
72{
73 struct i2c_msg msg = {
74 .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
75 };
76 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
77 printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len);
78 return -EREMOTEIO;
79 }
80 return 0;
81}
82
83// Initialisation sequences
84// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49
85static u8 mt2060_config1[] = {
86 REG_LO1C1,
87 0x3F, 0x74, 0x00, 0x08, 0x93
88};
89
90// FMCG=2, GP2=0, GP1=0
91static u8 mt2060_config2[] = {
92 REG_MISC_CTRL,
93 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42
94};
95
96// VGAG=3, V1CSE=1
97
98#ifdef MT2060_SPURCHECK
99/* The function below calculates the frequency offset between the output frequency if2
100 and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */
101static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2)
102{
103 int I,J;
104 int dia,diamin,diff;
105 diamin=1000000;
106 for (I = 1; I < 10; I++) {
107 J = ((2*I*lo1)/lo2+1)/2;
108 diff = I*(int)lo1-J*(int)lo2;
109 if (diff < 0) diff=-diff;
110 dia = (diff-(int)if2);
111 if (dia < 0) dia=-dia;
112 if (diamin > dia) diamin=dia;
113 }
114 return diamin;
115}
116
117#define BANDWIDTH 4000 // kHz
118
119/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */
120static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2)
121{
122 u32 Spur,Sp1,Sp2;
123 int I,J;
124 I=0;
125 J=1000;
126
127 Spur=mt2060_spurcalc(lo1,lo2,if2);
128 if (Spur < BANDWIDTH) {
129 /* Potential spurs detected */
130 dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)",
131 (int)lo1,(int)lo2);
132 I=1000;
133 Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2);
134 Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2);
135
136 if (Sp1 < Sp2) {
137 J=-J; I=-I; Spur=Sp2;
138 } else
139 Spur=Sp1;
140
141 while (Spur < BANDWIDTH) {
142 I += J;
143 Spur = mt2060_spurcalc(lo1+I,lo2+I,if2);
144 }
145 dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)",
146 (int)(lo1+I),(int)(lo2+I));
147 }
148 return I;
149}
150#endif
151
152#define IF2 36150 // IF2 frequency = 36.150 MHz
153#define FREF 16000 // Quartz oscillator 16 MHz
154
155static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
156{
157 struct mt2060_priv *priv;
158 int ret=0;
159 int i=0;
160 u32 freq;
161 u8 lnaband;
162 u32 f_lo1,f_lo2;
163 u32 div1,num1,div2,num2;
164 u8 b[8];
165 u32 if1;
166
167 priv = fe->tuner_priv;
168
169 if1 = priv->if1_freq;
170 b[0] = REG_LO1B1;
171 b[1] = 0xFF;
172
173 mt2060_writeregs(priv,b,2);
174
175 freq = params->frequency / 1000; // Hz -> kHz
176 priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
177
178 f_lo1 = freq + if1 * 1000;
179 f_lo1 = (f_lo1 / 250) * 250;
180 f_lo2 = f_lo1 - freq - IF2;
181 // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise
182 f_lo2 = ((f_lo2 + 25) / 50) * 50;
183 priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000,
184
185#ifdef MT2060_SPURCHECK
186 // LO-related spurs detection and correction
187 num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2);
188 f_lo1 += num1;
189 f_lo2 += num1;
190#endif
191 //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 )
192 num1 = f_lo1 / (FREF / 64);
193 div1 = num1 / 64;
194 num1 &= 0x3f;
195
196 // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 )
197 num2 = f_lo2 * 64 / (FREF / 128);
198 div2 = num2 / 8192;
199 num2 &= 0x1fff;
200
201 if (freq <= 95000) lnaband = 0xB0; else
202 if (freq <= 180000) lnaband = 0xA0; else
203 if (freq <= 260000) lnaband = 0x90; else
204 if (freq <= 335000) lnaband = 0x80; else
205 if (freq <= 425000) lnaband = 0x70; else
206 if (freq <= 480000) lnaband = 0x60; else
207 if (freq <= 570000) lnaband = 0x50; else
208 if (freq <= 645000) lnaband = 0x40; else
209 if (freq <= 730000) lnaband = 0x30; else
210 if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10;
211
212 b[0] = REG_LO1C1;
213 b[1] = lnaband | ((num1 >>2) & 0x0F);
214 b[2] = div1;
215 b[3] = (num2 & 0x0F) | ((num1 & 3) << 4);
216 b[4] = num2 >> 4;
217 b[5] = ((num2 >>12) & 1) | (div2 << 1);
218
219 dprintk("IF1: %dMHz",(int)if1);
220 dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2);
221 dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2);
222 dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]);
223
224 mt2060_writeregs(priv,b,6);
225
226 //Waits for pll lock or timeout
227 i = 0;
228 do {
229 mt2060_readreg(priv,REG_LO_STATUS,b);
230 if ((b[0] & 0x88)==0x88)
231 break;
232 msleep(4);
233 i++;
234 } while (i<10);
235
236 return ret;
237}
238
239static void mt2060_calibrate(struct mt2060_priv *priv)
240{
241 u8 b = 0;
242 int i = 0;
243
244 if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1)))
245 return;
246 if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2)))
247 return;
248
249 /* initialize the clock output */
250 mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
251
252 do {
253 b |= (1 << 6); // FM1SS;
254 mt2060_writereg(priv, REG_LO2C1,b);
255 msleep(20);
256
257 if (i == 0) {
258 b |= (1 << 7); // FM1CA;
259 mt2060_writereg(priv, REG_LO2C1,b);
260 b &= ~(1 << 7); // FM1CA;
261 msleep(20);
262 }
263
264 b &= ~(1 << 6); // FM1SS
265 mt2060_writereg(priv, REG_LO2C1,b);
266
267 msleep(20);
268 i++;
269 } while (i < 9);
270
271 i = 0;
272 while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0)
273 msleep(20);
274
275 if (i < 10) {
276 mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :)
277 dprintk("calibration was successful: %d", (int)priv->fmfreq);
278 } else
279 dprintk("FMCAL timed out");
280}
281
282static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency)
283{
284 struct mt2060_priv *priv = fe->tuner_priv;
285 *frequency = priv->frequency;
286 return 0;
287}
288
289static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
290{
291 struct mt2060_priv *priv = fe->tuner_priv;
292 *bandwidth = priv->bandwidth;
293 return 0;
294}
295
296static int mt2060_init(struct dvb_frontend *fe)
297{
298 struct mt2060_priv *priv = fe->tuner_priv;
299 return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
300}
301
302static int mt2060_sleep(struct dvb_frontend *fe)
303{
304 struct mt2060_priv *priv = fe->tuner_priv;
305 return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
306}
307
308static int mt2060_release(struct dvb_frontend *fe)
309{
310 kfree(fe->tuner_priv);
311 fe->tuner_priv = NULL;
312 return 0;
313}
314
315static const struct dvb_tuner_ops mt2060_tuner_ops = {
316 .info = {
317 .name = "Microtune MT2060",
318 .frequency_min = 48000000,
319 .frequency_max = 860000000,
320 .frequency_step = 50000,
321 },
322
323 .release = mt2060_release,
324
325 .init = mt2060_init,
326 .sleep = mt2060_sleep,
327
328 .set_params = mt2060_set_params,
329 .get_frequency = mt2060_get_frequency,
330 .get_bandwidth = mt2060_get_bandwidth
331};
332
333/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */
334struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
335{
336 struct mt2060_priv *priv = NULL;
337 u8 id = 0;
338
339 priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL);
340 if (priv == NULL)
341 return NULL;
342
343 priv->cfg = cfg;
344 priv->i2c = i2c;
345 priv->if1_freq = if1;
346
347 if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
348 kfree(priv);
349 return NULL;
350 }
351
352 if (id != PART_REV) {
353 kfree(priv);
354 return NULL;
355 }
356 printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1);
357 memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops));
358
359 fe->tuner_priv = priv;
360
361 mt2060_calibrate(priv);
362
363 return fe;
364}
365EXPORT_SYMBOL(mt2060_attach);
366
367MODULE_AUTHOR("Olivier DANET");
368MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver");
369MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mt2060.h b/drivers/media/common/tuners/mt2060.h
new file mode 100644
index 000000000000..acba0058f519
--- /dev/null
+++ b/drivers/media/common/tuners/mt2060.h
@@ -0,0 +1,43 @@
1/*
2 * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
3 *
4 * Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
20 */
21
22#ifndef MT2060_H
23#define MT2060_H
24
25struct dvb_frontend;
26struct i2c_adapter;
27
28struct mt2060_config {
29 u8 i2c_address;
30 u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
31};
32
33#if defined(CONFIG_DVB_TUNER_MT2060) || (defined(CONFIG_DVB_TUNER_MT2060_MODULE) && defined(MODULE))
34extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
35#else
36static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
37{
38 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
39 return NULL;
40}
41#endif // CONFIG_DVB_TUNER_MT2060
42
43#endif
diff --git a/drivers/media/common/tuners/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h
new file mode 100644
index 000000000000..5eaccdefd0b0
--- /dev/null
+++ b/drivers/media/common/tuners/mt2060_priv.h
@@ -0,0 +1,105 @@
1/*
2 * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
3 *
4 * Copyright (c) 2006 Olivier DANET <odanet@caramail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
20 */
21
22#ifndef MT2060_PRIV_H
23#define MT2060_PRIV_H
24
25// Uncomment the #define below to enable spurs checking. The results where quite unconvincing.
26// #define MT2060_SPURCHECK
27
28/* This driver is based on the information available in the datasheet of the
29 "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map :
30
31 I2C Address : 0x60
32
33 Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults )
34 --------------------------------------------------------------------------------
35 00 | [ PART ] | [ REV ] | R = 0x63
36 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F
37 02 | [ DIV1 ] | RW = 0x74
38 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00
39 04 | NUM2(11:4) ] | RW = 0x08
40 05 | [ DIV2 ] |NUM2(12)| RW = 0x93
41 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R
42 07 | [ FMF ] | R
43 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R
44 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20
45 0A | ??
46 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30
47 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF
48 0D | 1 | 0 | [ V1CS ] | RW = 0xB0
49 0E | ??
50 0F | ??
51 10 | ??
52 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42
53
54 PART : Part code : 6 for MT2060
55 REV : Revision code : 3 for current revision
56 LNABAND : Input frequency range : ( See code for details )
57 NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details )
58 FM1CA : Calibration Start Bit
59 FM1SS : Calibration Single Step bit
60 L1LK : LO1 Lock Detect
61 TAD1 : Tune Line ADC ( ? )
62 L2LK : LO2 Lock Detect
63 TAD2 : Tune Line ADC ( ? )
64 FMF : Estimated first IF Center frequency Offset ( ? )
65 FM1CAL : Calibration done bit
66 TEMP : On chip temperature sensor
67 FMCG : Mixer 1 Cap Gain ( ? )
68 GP01 / GP02 : Programmable digital outputs. Unconnected pins ?
69 V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? )
70 V1CS : LO1 Capacitor Selection Value ( ? )
71 LOTO : LO Timeout ( ? )
72 VGAG : Tuner Output gain
73*/
74
75#define I2C_ADDRESS 0x60
76
77#define REG_PART_REV 0
78#define REG_LO1C1 1
79#define REG_LO1C2 2
80#define REG_LO2C1 3
81#define REG_LO2C2 4
82#define REG_LO2C3 5
83#define REG_LO_STATUS 6
84#define REG_FM_FREQ 7
85#define REG_MISC_STAT 8
86#define REG_MISC_CTRL 9
87#define REG_RESERVED_A 0x0A
88#define REG_VGAG 0x0B
89#define REG_LO1B1 0x0C
90#define REG_LO1B2 0x0D
91#define REG_LOTO 0x11
92
93#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips
94
95struct mt2060_priv {
96 struct mt2060_config *cfg;
97 struct i2c_adapter *i2c;
98
99 u32 frequency;
100 u32 bandwidth;
101 u16 if1_freq;
102 u8 fmfreq;
103};
104
105#endif
diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c
new file mode 100644
index 000000000000..e254bcfc2efb
--- /dev/null
+++ b/drivers/media/common/tuners/mt2131.c
@@ -0,0 +1,314 @@
1/*
2 * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
3 *
4 * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/module.h>
23#include <linux/delay.h>
24#include <linux/dvb/frontend.h>
25#include <linux/i2c.h>
26
27#include "dvb_frontend.h"
28
29#include "mt2131.h"
30#include "mt2131_priv.h"
31
32static int debug;
33module_param(debug, int, 0644);
34MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
35
36#define dprintk(level,fmt, arg...) if (debug >= level) \
37 printk(KERN_INFO "%s: " fmt, "mt2131", ## arg)
38
39static u8 mt2131_config1[] = {
40 0x01,
41 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,
42 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,
43 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,
44 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00
45};
46
47static u8 mt2131_config2[] = {
48 0x10,
49 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04
50};
51
52static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)
53{
54 struct i2c_msg msg[2] = {
55 { .addr = priv->cfg->i2c_address, .flags = 0,
56 .buf = &reg, .len = 1 },
57 { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
58 .buf = val, .len = 1 },
59 };
60
61 if (i2c_transfer(priv->i2c, msg, 2) != 2) {
62 printk(KERN_WARNING "mt2131 I2C read failed\n");
63 return -EREMOTEIO;
64 }
65 return 0;
66}
67
68static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)
69{
70 u8 buf[2] = { reg, val };
71 struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,
72 .buf = buf, .len = 2 };
73
74 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
75 printk(KERN_WARNING "mt2131 I2C write failed\n");
76 return -EREMOTEIO;
77 }
78 return 0;
79}
80
81static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
82{
83 struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
84 .flags = 0, .buf = buf, .len = len };
85
86 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
87 printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",
88 (int)len);
89 return -EREMOTEIO;
90 }
91 return 0;
92}
93
94static int mt2131_set_params(struct dvb_frontend *fe,
95 struct dvb_frontend_parameters *params)
96{
97 struct mt2131_priv *priv;
98 int ret=0, i;
99 u32 freq;
100 u8 if_band_center;
101 u32 f_lo1, f_lo2;
102 u32 div1, num1, div2, num2;
103 u8 b[8];
104 u8 lockval = 0;
105
106 priv = fe->tuner_priv;
107 if (fe->ops.info.type == FE_OFDM)
108 priv->bandwidth = params->u.ofdm.bandwidth;
109 else
110 priv->bandwidth = 0;
111
112 freq = params->frequency / 1000; // Hz -> kHz
113 dprintk(1, "%s() freq=%d\n", __func__, freq);
114
115 f_lo1 = freq + MT2131_IF1 * 1000;
116 f_lo1 = (f_lo1 / 250) * 250;
117 f_lo2 = f_lo1 - freq - MT2131_IF2;
118
119 priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000;
120
121 /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */
122 num1 = f_lo1 * 64 / (MT2131_FREF / 128);
123 div1 = num1 / 8192;
124 num1 &= 0x1fff;
125
126 /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */
127 num2 = f_lo2 * 64 / (MT2131_FREF / 128);
128 div2 = num2 / 8192;
129 num2 &= 0x1fff;
130
131 if (freq <= 82500) if_band_center = 0x00; else
132 if (freq <= 137500) if_band_center = 0x01; else
133 if (freq <= 192500) if_band_center = 0x02; else
134 if (freq <= 247500) if_band_center = 0x03; else
135 if (freq <= 302500) if_band_center = 0x04; else
136 if (freq <= 357500) if_band_center = 0x05; else
137 if (freq <= 412500) if_band_center = 0x06; else
138 if (freq <= 467500) if_band_center = 0x07; else
139 if (freq <= 522500) if_band_center = 0x08; else
140 if (freq <= 577500) if_band_center = 0x09; else
141 if (freq <= 632500) if_band_center = 0x0A; else
142 if (freq <= 687500) if_band_center = 0x0B; else
143 if (freq <= 742500) if_band_center = 0x0C; else
144 if (freq <= 797500) if_band_center = 0x0D; else
145 if (freq <= 852500) if_band_center = 0x0E; else
146 if (freq <= 907500) if_band_center = 0x0F; else
147 if (freq <= 962500) if_band_center = 0x10; else
148 if (freq <= 1017500) if_band_center = 0x11; else
149 if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;
150
151 b[0] = 1;
152 b[1] = (num1 >> 5) & 0xFF;
153 b[2] = (num1 & 0x1F);
154 b[3] = div1;
155 b[4] = (num2 >> 5) & 0xFF;
156 b[5] = num2 & 0x1F;
157 b[6] = div2;
158
159 dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);
160 dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center);
161 dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);
162 dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n",
163 (int)div1, (int)num1, (int)div2, (int)num2);
164 dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",
165 (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],
166 (int)b[6]);
167
168 ret = mt2131_writeregs(priv,b,7);
169 if (ret < 0)
170 return ret;
171
172 mt2131_writereg(priv, 0x0b, if_band_center);
173
174 /* Wait for lock */
175 i = 0;
176 do {
177 mt2131_readreg(priv, 0x08, &lockval);
178 if ((lockval & 0x88) == 0x88)
179 break;
180 msleep(4);
181 i++;
182 } while (i < 10);
183
184 return ret;
185}
186
187static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
188{
189 struct mt2131_priv *priv = fe->tuner_priv;
190 dprintk(1, "%s()\n", __func__);
191 *frequency = priv->frequency;
192 return 0;
193}
194
195static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
196{
197 struct mt2131_priv *priv = fe->tuner_priv;
198 dprintk(1, "%s()\n", __func__);
199 *bandwidth = priv->bandwidth;
200 return 0;
201}
202
203static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
204{
205 struct mt2131_priv *priv = fe->tuner_priv;
206 u8 lock_status = 0;
207 u8 afc_status = 0;
208
209 *status = 0;
210
211 mt2131_readreg(priv, 0x08, &lock_status);
212 if ((lock_status & 0x88) == 0x88)
213 *status = TUNER_STATUS_LOCKED;
214
215 mt2131_readreg(priv, 0x09, &afc_status);
216 dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
217 __func__, lock_status, afc_status);
218
219 return 0;
220}
221
222static int mt2131_init(struct dvb_frontend *fe)
223{
224 struct mt2131_priv *priv = fe->tuner_priv;
225 int ret;
226 dprintk(1, "%s()\n", __func__);
227
228 if ((ret = mt2131_writeregs(priv, mt2131_config1,
229 sizeof(mt2131_config1))) < 0)
230 return ret;
231
232 mt2131_writereg(priv, 0x0b, 0x09);
233 mt2131_writereg(priv, 0x15, 0x47);
234 mt2131_writereg(priv, 0x07, 0xf2);
235 mt2131_writereg(priv, 0x0b, 0x01);
236
237 if ((ret = mt2131_writeregs(priv, mt2131_config2,
238 sizeof(mt2131_config2))) < 0)
239 return ret;
240
241 return ret;
242}
243
244static int mt2131_release(struct dvb_frontend *fe)
245{
246 dprintk(1, "%s()\n", __func__);
247 kfree(fe->tuner_priv);
248 fe->tuner_priv = NULL;
249 return 0;
250}
251
252static const struct dvb_tuner_ops mt2131_tuner_ops = {
253 .info = {
254 .name = "Microtune MT2131",
255 .frequency_min = 48000000,
256 .frequency_max = 860000000,
257 .frequency_step = 50000,
258 },
259
260 .release = mt2131_release,
261 .init = mt2131_init,
262
263 .set_params = mt2131_set_params,
264 .get_frequency = mt2131_get_frequency,
265 .get_bandwidth = mt2131_get_bandwidth,
266 .get_status = mt2131_get_status
267};
268
269struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
270 struct i2c_adapter *i2c,
271 struct mt2131_config *cfg, u16 if1)
272{
273 struct mt2131_priv *priv = NULL;
274 u8 id = 0;
275
276 dprintk(1, "%s()\n", __func__);
277
278 priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
279 if (priv == NULL)
280 return NULL;
281
282 priv->cfg = cfg;
283 priv->bandwidth = 6000000; /* 6MHz */
284 priv->i2c = i2c;
285
286 if (mt2131_readreg(priv, 0, &id) != 0) {
287 kfree(priv);
288 return NULL;
289 }
290 if ( (id != 0x3E) && (id != 0x3F) ) {
291 printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n",
292 cfg->i2c_address);
293 kfree(priv);
294 return NULL;
295 }
296
297 printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n",
298 cfg->i2c_address);
299 memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops,
300 sizeof(struct dvb_tuner_ops));
301
302 fe->tuner_priv = priv;
303 return fe;
304}
305EXPORT_SYMBOL(mt2131_attach);
306
307MODULE_AUTHOR("Steven Toth");
308MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
309MODULE_LICENSE("GPL");
310
311/*
312 * Local variables:
313 * c-basic-offset: 8
314 */
diff --git a/drivers/media/common/tuners/mt2131.h b/drivers/media/common/tuners/mt2131.h
new file mode 100644
index 000000000000..606d8576bc98
--- /dev/null
+++ b/drivers/media/common/tuners/mt2131.h
@@ -0,0 +1,54 @@
1/*
2 * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
3 *
4 * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef __MT2131_H__
23#define __MT2131_H__
24
25struct dvb_frontend;
26struct i2c_adapter;
27
28struct mt2131_config {
29 u8 i2c_address;
30 u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
31};
32
33#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE))
34extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
35 struct i2c_adapter *i2c,
36 struct mt2131_config *cfg,
37 u16 if1);
38#else
39static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
40 struct i2c_adapter *i2c,
41 struct mt2131_config *cfg,
42 u16 if1)
43{
44 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
45 return NULL;
46}
47#endif /* CONFIG_DVB_TUNER_MT2131 */
48
49#endif /* __MT2131_H__ */
50
51/*
52 * Local variables:
53 * c-basic-offset: 8
54 */
diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h
new file mode 100644
index 000000000000..e930759c2c00
--- /dev/null
+++ b/drivers/media/common/tuners/mt2131_priv.h
@@ -0,0 +1,49 @@
1/*
2 * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
3 *
4 * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef __MT2131_PRIV_H__
23#define __MT2131_PRIV_H__
24
25/* Regs */
26#define MT2131_PWR 0x07
27#define MT2131_UPC_1 0x0b
28#define MT2131_AGC_RL 0x10
29#define MT2131_MISC_2 0x15
30
31/* frequency values in KHz */
32#define MT2131_IF1 1220
33#define MT2131_IF2 44000
34#define MT2131_FREF 16000
35
36struct mt2131_priv {
37 struct mt2131_config *cfg;
38 struct i2c_adapter *i2c;
39
40 u32 frequency;
41 u32 bandwidth;
42};
43
44#endif /* __MT2131_PRIV_H__ */
45
46/*
47 * Local variables:
48 * c-basic-offset: 8
49 */
diff --git a/drivers/media/common/tuners/mt2266.c b/drivers/media/common/tuners/mt2266.c
new file mode 100644
index 000000000000..54b18f94b14b
--- /dev/null
+++ b/drivers/media/common/tuners/mt2266.c
@@ -0,0 +1,351 @@
1/*
2 * Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
3 *
4 * Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/module.h>
18#include <linux/delay.h>
19#include <linux/dvb/frontend.h>
20#include <linux/i2c.h>
21
22#include "dvb_frontend.h"
23#include "mt2266.h"
24
25#define I2C_ADDRESS 0x60
26
27#define REG_PART_REV 0
28#define REG_TUNE 1
29#define REG_BAND 6
30#define REG_BANDWIDTH 8
31#define REG_LOCK 0x12
32
33#define PART_REV 0x85
34
35struct mt2266_priv {
36 struct mt2266_config *cfg;
37 struct i2c_adapter *i2c;
38
39 u32 frequency;
40 u32 bandwidth;
41 u8 band;
42};
43
44#define MT2266_VHF 1
45#define MT2266_UHF 0
46
47/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
48
49static int debug;
50module_param(debug, int, 0644);
51MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
52
53#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
54
55// Reads a single register
56static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
57{
58 struct i2c_msg msg[2] = {
59 { .addr = priv->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
60 { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 },
61 };
62 if (i2c_transfer(priv->i2c, msg, 2) != 2) {
63 printk(KERN_WARNING "MT2266 I2C read failed\n");
64 return -EREMOTEIO;
65 }
66 return 0;
67}
68
69// Writes a single register
70static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
71{
72 u8 buf[2] = { reg, val };
73 struct i2c_msg msg = {
74 .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
75 };
76 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
77 printk(KERN_WARNING "MT2266 I2C write failed\n");
78 return -EREMOTEIO;
79 }
80 return 0;
81}
82
83// Writes a set of consecutive registers
84static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
85{
86 struct i2c_msg msg = {
87 .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
88 };
89 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
90 printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
91 return -EREMOTEIO;
92 }
93 return 0;
94}
95
96// Initialisation sequences
97static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
98 0x00, 0x52, 0x99, 0x3f };
99
100static u8 mt2266_init2[] = {
101 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
102 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
103 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
104 0xff, 0x00, 0x77, 0x0f, 0x2d
105};
106
107static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
108 0x22, 0x22, 0x22, 0x22 };
109
110static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
111 0x32, 0x32, 0x32, 0x32 };
112
113static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
114 0xa7, 0xa7, 0xa7, 0xa7 };
115
116static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
117 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
118
119static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
120 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
121
122#define FREF 30000 // Quartz oscillator 30 MHz
123
124static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
125{
126 struct mt2266_priv *priv;
127 int ret=0;
128 u32 freq;
129 u32 tune;
130 u8 lnaband;
131 u8 b[10];
132 int i;
133 u8 band;
134
135 priv = fe->tuner_priv;
136
137 freq = params->frequency / 1000; // Hz -> kHz
138 if (freq < 470000 && freq > 230000)
139 return -EINVAL; /* Gap between VHF and UHF bands */
140 priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
141 priv->frequency = freq * 1000;
142
143 tune = 2 * freq * (8192/16) / (FREF/16);
144 band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
145 if (band == MT2266_VHF)
146 tune *= 2;
147
148 switch (params->u.ofdm.bandwidth) {
149 case BANDWIDTH_6_MHZ:
150 mt2266_writeregs(priv, mt2266_init_6mhz,
151 sizeof(mt2266_init_6mhz));
152 break;
153 case BANDWIDTH_7_MHZ:
154 mt2266_writeregs(priv, mt2266_init_7mhz,
155 sizeof(mt2266_init_7mhz));
156 break;
157 case BANDWIDTH_8_MHZ:
158 default:
159 mt2266_writeregs(priv, mt2266_init_8mhz,
160 sizeof(mt2266_init_8mhz));
161 break;
162 }
163
164 if (band == MT2266_VHF && priv->band == MT2266_UHF) {
165 dprintk("Switch from UHF to VHF");
166 mt2266_writereg(priv, 0x05, 0x04);
167 mt2266_writereg(priv, 0x19, 0x61);
168 mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
169 } else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
170 dprintk("Switch from VHF to UHF");
171 mt2266_writereg(priv, 0x05, 0x52);
172 mt2266_writereg(priv, 0x19, 0x61);
173 mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
174 }
175 msleep(10);
176
177 if (freq <= 495000)
178 lnaband = 0xEE;
179 else if (freq <= 525000)
180 lnaband = 0xDD;
181 else if (freq <= 550000)
182 lnaband = 0xCC;
183 else if (freq <= 580000)
184 lnaband = 0xBB;
185 else if (freq <= 605000)
186 lnaband = 0xAA;
187 else if (freq <= 630000)
188 lnaband = 0x99;
189 else if (freq <= 655000)
190 lnaband = 0x88;
191 else if (freq <= 685000)
192 lnaband = 0x77;
193 else if (freq <= 710000)
194 lnaband = 0x66;
195 else if (freq <= 735000)
196 lnaband = 0x55;
197 else if (freq <= 765000)
198 lnaband = 0x44;
199 else if (freq <= 802000)
200 lnaband = 0x33;
201 else if (freq <= 840000)
202 lnaband = 0x22;
203 else
204 lnaband = 0x11;
205
206 b[0] = REG_TUNE;
207 b[1] = (tune >> 8) & 0x1F;
208 b[2] = tune & 0xFF;
209 b[3] = tune >> 13;
210 mt2266_writeregs(priv,b,4);
211
212 dprintk("set_parms: tune=%d band=%d %s",
213 (int) tune, (int) lnaband,
214 (band == MT2266_UHF) ? "UHF" : "VHF");
215 dprintk("set_parms: [1..3]: %2x %2x %2x",
216 (int) b[1], (int) b[2], (int)b[3]);
217
218 if (band == MT2266_UHF) {
219 b[0] = 0x05;
220 b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
221 b[2] = lnaband;
222 mt2266_writeregs(priv, b, 3);
223 }
224
225 /* Wait for pll lock or timeout */
226 i = 0;
227 do {
228 mt2266_readreg(priv,REG_LOCK,b);
229 if (b[0] & 0x40)
230 break;
231 msleep(10);
232 i++;
233 } while (i<10);
234 dprintk("Lock when i=%i",(int)i);
235
236 if (band == MT2266_UHF && priv->band == MT2266_VHF)
237 mt2266_writereg(priv, 0x05, 0x62);
238
239 priv->band = band;
240
241 return ret;
242}
243
244static void mt2266_calibrate(struct mt2266_priv *priv)
245{
246 mt2266_writereg(priv, 0x11, 0x03);
247 mt2266_writereg(priv, 0x11, 0x01);
248 mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
249 mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
250 mt2266_writereg(priv, 0x33, 0x5e);
251 mt2266_writereg(priv, 0x10, 0x10);
252 mt2266_writereg(priv, 0x10, 0x00);
253 mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
254 msleep(25);
255 mt2266_writereg(priv, 0x17, 0x6d);
256 mt2266_writereg(priv, 0x1c, 0x00);
257 msleep(75);
258 mt2266_writereg(priv, 0x17, 0x6d);
259 mt2266_writereg(priv, 0x1c, 0xff);
260}
261
262static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
263{
264 struct mt2266_priv *priv = fe->tuner_priv;
265 *frequency = priv->frequency;
266 return 0;
267}
268
269static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
270{
271 struct mt2266_priv *priv = fe->tuner_priv;
272 *bandwidth = priv->bandwidth;
273 return 0;
274}
275
276static int mt2266_init(struct dvb_frontend *fe)
277{
278 int ret;
279 struct mt2266_priv *priv = fe->tuner_priv;
280 ret = mt2266_writereg(priv, 0x17, 0x6d);
281 if (ret < 0)
282 return ret;
283 ret = mt2266_writereg(priv, 0x1c, 0xff);
284 if (ret < 0)
285 return ret;
286 return 0;
287}
288
289static int mt2266_sleep(struct dvb_frontend *fe)
290{
291 struct mt2266_priv *priv = fe->tuner_priv;
292 mt2266_writereg(priv, 0x17, 0x6d);
293 mt2266_writereg(priv, 0x1c, 0x00);
294 return 0;
295}
296
297static int mt2266_release(struct dvb_frontend *fe)
298{
299 kfree(fe->tuner_priv);
300 fe->tuner_priv = NULL;
301 return 0;
302}
303
304static const struct dvb_tuner_ops mt2266_tuner_ops = {
305 .info = {
306 .name = "Microtune MT2266",
307 .frequency_min = 174000000,
308 .frequency_max = 862000000,
309 .frequency_step = 50000,
310 },
311 .release = mt2266_release,
312 .init = mt2266_init,
313 .sleep = mt2266_sleep,
314 .set_params = mt2266_set_params,
315 .get_frequency = mt2266_get_frequency,
316 .get_bandwidth = mt2266_get_bandwidth
317};
318
319struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
320{
321 struct mt2266_priv *priv = NULL;
322 u8 id = 0;
323
324 priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
325 if (priv == NULL)
326 return NULL;
327
328 priv->cfg = cfg;
329 priv->i2c = i2c;
330 priv->band = MT2266_UHF;
331
332 if (mt2266_readreg(priv, 0, &id)) {
333 kfree(priv);
334 return NULL;
335 }
336 if (id != PART_REV) {
337 kfree(priv);
338 return NULL;
339 }
340 printk(KERN_INFO "MT2266: successfully identified\n");
341 memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
342
343 fe->tuner_priv = priv;
344 mt2266_calibrate(priv);
345 return fe;
346}
347EXPORT_SYMBOL(mt2266_attach);
348
349MODULE_AUTHOR("Olivier DANET");
350MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
351MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mt2266.h b/drivers/media/common/tuners/mt2266.h
new file mode 100644
index 000000000000..c5113efe333c
--- /dev/null
+++ b/drivers/media/common/tuners/mt2266.h
@@ -0,0 +1,37 @@
1/*
2 * Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
3 *
4 * Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#ifndef MT2266_H
18#define MT2266_H
19
20struct dvb_frontend;
21struct i2c_adapter;
22
23struct mt2266_config {
24 u8 i2c_address;
25};
26
27#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE))
28extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
29#else
30static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
31{
32 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
33 return NULL;
34}
35#endif // CONFIG_DVB_TUNER_MT2266
36
37#endif
diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c
new file mode 100644
index 000000000000..825aa1412e6f
--- /dev/null
+++ b/drivers/media/common/tuners/qt1010.c
@@ -0,0 +1,485 @@
1/*
2 * Driver for Quantek QT1010 silicon tuner
3 *
4 * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
5 * Aapo Tahkola <aet@rasterburn.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21#include "qt1010.h"
22#include "qt1010_priv.h"
23
24static int debug;
25module_param(debug, int, 0644);
26MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
27
28#define dprintk(args...) \
29 do { \
30 if (debug) printk(KERN_DEBUG "QT1010: " args); \
31 } while (0)
32
33/* read single register */
34static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
35{
36 struct i2c_msg msg[2] = {
37 { .addr = priv->cfg->i2c_address,
38 .flags = 0, .buf = &reg, .len = 1 },
39 { .addr = priv->cfg->i2c_address,
40 .flags = I2C_M_RD, .buf = val, .len = 1 },
41 };
42
43 if (i2c_transfer(priv->i2c, msg, 2) != 2) {
44 printk(KERN_WARNING "qt1010 I2C read failed\n");
45 return -EREMOTEIO;
46 }
47 return 0;
48}
49
50/* write single register */
51static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
52{
53 u8 buf[2] = { reg, val };
54 struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
55 .flags = 0, .buf = buf, .len = 2 };
56
57 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
58 printk(KERN_WARNING "qt1010 I2C write failed\n");
59 return -EREMOTEIO;
60 }
61 return 0;
62}
63
64/* dump all registers */
65static void qt1010_dump_regs(struct qt1010_priv *priv)
66{
67 char buf[52], buf2[4];
68 u8 reg, val;
69
70 for (reg = 0; ; reg++) {
71 if (reg % 16 == 0) {
72 if (reg)
73 printk("%s\n", buf);
74 sprintf(buf, "%02x: ", reg);
75 }
76 if (qt1010_readreg(priv, reg, &val) == 0)
77 sprintf(buf2, "%02x ", val);
78 else
79 strcpy(buf2, "-- ");
80 strcat(buf, buf2);
81 if (reg == 0x2f)
82 break;
83 }
84 printk("%s\n", buf);
85}
86
87static int qt1010_set_params(struct dvb_frontend *fe,
88 struct dvb_frontend_parameters *params)
89{
90 struct qt1010_priv *priv;
91 int err;
92 u32 freq, div, mod1, mod2;
93 u8 i, tmpval, reg05;
94 qt1010_i2c_oper_t rd[48] = {
95 { QT1010_WR, 0x01, 0x80 },
96 { QT1010_WR, 0x02, 0x3f },
97 { QT1010_WR, 0x05, 0xff }, /* 02 c write */
98 { QT1010_WR, 0x06, 0x44 },
99 { QT1010_WR, 0x07, 0xff }, /* 04 c write */
100 { QT1010_WR, 0x08, 0x08 },
101 { QT1010_WR, 0x09, 0xff }, /* 06 c write */
102 { QT1010_WR, 0x0a, 0xff }, /* 07 c write */
103 { QT1010_WR, 0x0b, 0xff }, /* 08 c write */
104 { QT1010_WR, 0x0c, 0xe1 },
105 { QT1010_WR, 0x1a, 0xff }, /* 10 c write */
106 { QT1010_WR, 0x1b, 0x00 },
107 { QT1010_WR, 0x1c, 0x89 },
108 { QT1010_WR, 0x11, 0xff }, /* 13 c write */
109 { QT1010_WR, 0x12, 0xff }, /* 14 c write */
110 { QT1010_WR, 0x22, 0xff }, /* 15 c write */
111 { QT1010_WR, 0x1e, 0x00 },
112 { QT1010_WR, 0x1e, 0xd0 },
113 { QT1010_RD, 0x22, 0xff }, /* 16 c read */
114 { QT1010_WR, 0x1e, 0x00 },
115 { QT1010_RD, 0x05, 0xff }, /* 20 c read */
116 { QT1010_RD, 0x22, 0xff }, /* 21 c read */
117 { QT1010_WR, 0x23, 0xd0 },
118 { QT1010_WR, 0x1e, 0x00 },
119 { QT1010_WR, 0x1e, 0xe0 },
120 { QT1010_RD, 0x23, 0xff }, /* 25 c read */
121 { QT1010_RD, 0x23, 0xff }, /* 26 c read */
122 { QT1010_WR, 0x1e, 0x00 },
123 { QT1010_WR, 0x24, 0xd0 },
124 { QT1010_WR, 0x1e, 0x00 },
125 { QT1010_WR, 0x1e, 0xf0 },
126 { QT1010_RD, 0x24, 0xff }, /* 31 c read */
127 { QT1010_WR, 0x1e, 0x00 },
128 { QT1010_WR, 0x14, 0x7f },
129 { QT1010_WR, 0x15, 0x7f },
130 { QT1010_WR, 0x05, 0xff }, /* 35 c write */
131 { QT1010_WR, 0x06, 0x00 },
132 { QT1010_WR, 0x15, 0x1f },
133 { QT1010_WR, 0x16, 0xff },
134 { QT1010_WR, 0x18, 0xff },
135 { QT1010_WR, 0x1f, 0xff }, /* 40 c write */
136 { QT1010_WR, 0x20, 0xff }, /* 41 c write */
137 { QT1010_WR, 0x21, 0x53 },
138 { QT1010_WR, 0x25, 0xff }, /* 43 c write */
139 { QT1010_WR, 0x26, 0x15 },
140 { QT1010_WR, 0x00, 0xff }, /* 45 c write */
141 { QT1010_WR, 0x02, 0x00 },
142 { QT1010_WR, 0x01, 0x00 }
143 };
144
145#define FREQ1 32000000 /* 32 MHz */
146#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */
147
148 priv = fe->tuner_priv;
149 freq = params->frequency;
150 div = (freq + QT1010_OFFSET) / QT1010_STEP;
151 freq = (div * QT1010_STEP) - QT1010_OFFSET;
152 mod1 = (freq + QT1010_OFFSET) % FREQ1;
153 mod2 = (freq + QT1010_OFFSET) % FREQ2;
154 priv->bandwidth =
155 (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
156 priv->frequency = freq;
157
158 if (fe->ops.i2c_gate_ctrl)
159 fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
160
161 /* reg 05 base value */
162 if (freq < 290000000) reg05 = 0x14; /* 290 MHz */
163 else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
164 else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
165 else reg05 = 0x74;
166
167 /* 0x5 */
168 rd[2].val = reg05;
169
170 /* 07 - set frequency: 32 MHz scale */
171 rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
172
173 /* 09 - changes every 8/24 MHz */
174 if (mod1 < 8000000) rd[6].val = 0x1d;
175 else rd[6].val = 0x1c;
176
177 /* 0a - set frequency: 4 MHz scale (max 28 MHz) */
178 if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */
179 else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */
180 else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */
181 else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
182 else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
183 else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
184 else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
185 else rd[7].val = 0x0a; /* +28 MHz */
186
187 /* 0b - changes every 2/2 MHz */
188 if (mod2 < 2000000) rd[8].val = 0x45;
189 else rd[8].val = 0x44;
190
191 /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
192 tmpval = 0x78; /* byte, overflows intentionally */
193 rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
194
195 /* 11 */
196 rd[13].val = 0xfd; /* TODO: correct value calculation */
197
198 /* 12 */
199 rd[14].val = 0x91; /* TODO: correct value calculation */
200
201 /* 22 */
202 if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
203 else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
204 else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
205 else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
206 else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
207 else rd[15].val = 0xd0;
208
209 /* 05 */
210 rd[35].val = (reg05 & 0xf0);
211
212 /* 1f */
213 if (mod1 < 8000000) tmpval = 0x00;
214 else if (mod1 < 12000000) tmpval = 0x01;
215 else if (mod1 < 16000000) tmpval = 0x02;
216 else if (mod1 < 24000000) tmpval = 0x03;
217 else if (mod1 < 28000000) tmpval = 0x04;
218 else tmpval = 0x05;
219 rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
220
221 /* 20 */
222 if (mod1 < 8000000) tmpval = 0x00;
223 else if (mod1 < 12000000) tmpval = 0x01;
224 else if (mod1 < 20000000) tmpval = 0x02;
225 else if (mod1 < 24000000) tmpval = 0x03;
226 else if (mod1 < 28000000) tmpval = 0x04;
227 else tmpval = 0x05;
228 rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
229
230 /* 25 */
231 rd[43].val = priv->reg25_init_val;
232
233 /* 00 */
234 rd[45].val = 0x92; /* TODO: correct value calculation */
235
236 dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
237 "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
238 "20:%02x 25:%02x 00:%02x", \
239 freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
240 rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
241 rd[40].val, rd[41].val, rd[43].val, rd[45].val);
242
243 for (i = 0; i < ARRAY_SIZE(rd); i++) {
244 if (rd[i].oper == QT1010_WR) {
245 err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
246 } else { /* read is required to proper locking */
247 err = qt1010_readreg(priv, rd[i].reg, &tmpval);
248 }
249 if (err) return err;
250 }
251
252 if (debug)
253 qt1010_dump_regs(priv);
254
255 if (fe->ops.i2c_gate_ctrl)
256 fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
257
258 return 0;
259}
260
261static int qt1010_init_meas1(struct qt1010_priv *priv,
262 u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
263{
264 u8 i, val1, val2;
265 int err;
266
267 qt1010_i2c_oper_t i2c_data[] = {
268 { QT1010_WR, reg, reg_init_val },
269 { QT1010_WR, 0x1e, 0x00 },
270 { QT1010_WR, 0x1e, oper },
271 { QT1010_RD, reg, 0xff }
272 };
273
274 for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
275 if (i2c_data[i].oper == QT1010_WR) {
276 err = qt1010_writereg(priv, i2c_data[i].reg,
277 i2c_data[i].val);
278 } else {
279 err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
280 }
281 if (err) return err;
282 }
283
284 do {
285 val1 = val2;
286 err = qt1010_readreg(priv, reg, &val2);
287 if (err) return err;
288 dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
289 } while (val1 != val2);
290 *retval = val1;
291
292 return qt1010_writereg(priv, 0x1e, 0x00);
293}
294
295static u8 qt1010_init_meas2(struct qt1010_priv *priv,
296 u8 reg_init_val, u8 *retval)
297{
298 u8 i, val;
299 int err;
300 qt1010_i2c_oper_t i2c_data[] = {
301 { QT1010_WR, 0x07, reg_init_val },
302 { QT1010_WR, 0x22, 0xd0 },
303 { QT1010_WR, 0x1e, 0x00 },
304 { QT1010_WR, 0x1e, 0xd0 },
305 { QT1010_RD, 0x22, 0xff },
306 { QT1010_WR, 0x1e, 0x00 },
307 { QT1010_WR, 0x22, 0xff }
308 };
309 for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
310 if (i2c_data[i].oper == QT1010_WR) {
311 err = qt1010_writereg(priv, i2c_data[i].reg,
312 i2c_data[i].val);
313 } else {
314 err = qt1010_readreg(priv, i2c_data[i].reg, &val);
315 }
316 if (err) return err;
317 }
318 *retval = val;
319 return 0;
320}
321
322static int qt1010_init(struct dvb_frontend *fe)
323{
324 struct qt1010_priv *priv = fe->tuner_priv;
325 struct dvb_frontend_parameters params;
326 int err = 0;
327 u8 i, tmpval, *valptr = NULL;
328
329 qt1010_i2c_oper_t i2c_data[] = {
330 { QT1010_WR, 0x01, 0x80 },
331 { QT1010_WR, 0x0d, 0x84 },
332 { QT1010_WR, 0x0e, 0xb7 },
333 { QT1010_WR, 0x2a, 0x23 },
334 { QT1010_WR, 0x2c, 0xdc },
335 { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
336 { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
337 { QT1010_WR, 0x2b, 0x70 },
338 { QT1010_WR, 0x2a, 0x23 },
339 { QT1010_M1, 0x26, 0x08 },
340 { QT1010_M1, 0x82, 0xff },
341 { QT1010_WR, 0x05, 0x14 },
342 { QT1010_WR, 0x06, 0x44 },
343 { QT1010_WR, 0x07, 0x28 },
344 { QT1010_WR, 0x08, 0x0b },
345 { QT1010_WR, 0x11, 0xfd },
346 { QT1010_M1, 0x22, 0x0d },
347 { QT1010_M1, 0xd0, 0xff },
348 { QT1010_WR, 0x06, 0x40 },
349 { QT1010_WR, 0x16, 0xf0 },
350 { QT1010_WR, 0x02, 0x38 },
351 { QT1010_WR, 0x03, 0x18 },
352 { QT1010_WR, 0x20, 0xe0 },
353 { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
354 { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
355 { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
356 { QT1010_WR, 0x03, 0x19 },
357 { QT1010_WR, 0x02, 0x3f },
358 { QT1010_WR, 0x21, 0x53 },
359 { QT1010_RD, 0x21, 0xff },
360 { QT1010_WR, 0x11, 0xfd },
361 { QT1010_WR, 0x05, 0x34 },
362 { QT1010_WR, 0x06, 0x44 },
363 { QT1010_WR, 0x08, 0x08 }
364 };
365
366 if (fe->ops.i2c_gate_ctrl)
367 fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
368
369 for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
370 switch (i2c_data[i].oper) {
371 case QT1010_WR:
372 err = qt1010_writereg(priv, i2c_data[i].reg,
373 i2c_data[i].val);
374 break;
375 case QT1010_RD:
376 if (i2c_data[i].val == 0x20)
377 valptr = &priv->reg20_init_val;
378 else
379 valptr = &tmpval;
380 err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
381 break;
382 case QT1010_M1:
383 if (i2c_data[i].val == 0x25)
384 valptr = &priv->reg25_init_val;
385 else if (i2c_data[i].val == 0x1f)
386 valptr = &priv->reg1f_init_val;
387 else
388 valptr = &tmpval;
389 err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
390 i2c_data[i].reg,
391 i2c_data[i].val, valptr);
392 i++;
393 break;
394 }
395 if (err) return err;
396 }
397
398 for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
399 if ((err = qt1010_init_meas2(priv, i, &tmpval)))
400 return err;
401
402 params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
403 /* MSI Megasky 580 GL861 533000000 */
404 return qt1010_set_params(fe, &params);
405}
406
407static int qt1010_release(struct dvb_frontend *fe)
408{
409 kfree(fe->tuner_priv);
410 fe->tuner_priv = NULL;
411 return 0;
412}
413
414static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
415{
416 struct qt1010_priv *priv = fe->tuner_priv;
417 *frequency = priv->frequency;
418 return 0;
419}
420
421static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
422{
423 struct qt1010_priv *priv = fe->tuner_priv;
424 *bandwidth = priv->bandwidth;
425 return 0;
426}
427
428static const struct dvb_tuner_ops qt1010_tuner_ops = {
429 .info = {
430 .name = "Quantek QT1010",
431 .frequency_min = QT1010_MIN_FREQ,
432 .frequency_max = QT1010_MAX_FREQ,
433 .frequency_step = QT1010_STEP,
434 },
435
436 .release = qt1010_release,
437 .init = qt1010_init,
438 /* TODO: implement sleep */
439
440 .set_params = qt1010_set_params,
441 .get_frequency = qt1010_get_frequency,
442 .get_bandwidth = qt1010_get_bandwidth
443};
444
445struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
446 struct i2c_adapter *i2c,
447 struct qt1010_config *cfg)
448{
449 struct qt1010_priv *priv = NULL;
450 u8 id;
451
452 priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
453 if (priv == NULL)
454 return NULL;
455
456 priv->cfg = cfg;
457 priv->i2c = i2c;
458
459 if (fe->ops.i2c_gate_ctrl)
460 fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
461
462
463 /* Try to detect tuner chip. Probably this is not correct register. */
464 if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
465 kfree(priv);
466 return NULL;
467 }
468
469 if (fe->ops.i2c_gate_ctrl)
470 fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
471
472 printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
473 memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
474 sizeof(struct dvb_tuner_ops));
475
476 fe->tuner_priv = priv;
477 return fe;
478}
479EXPORT_SYMBOL(qt1010_attach);
480
481MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
482MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
483MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
484MODULE_VERSION("0.1");
485MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/qt1010.h b/drivers/media/common/tuners/qt1010.h
new file mode 100644
index 000000000000..cff6a7ca5380
--- /dev/null
+++ b/drivers/media/common/tuners/qt1010.h
@@ -0,0 +1,53 @@
1/*
2 * Driver for Quantek QT1010 silicon tuner
3 *
4 * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
5 * Aapo Tahkola <aet@rasterburn.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef QT1010_H
23#define QT1010_H
24
25#include "dvb_frontend.h"
26
27struct qt1010_config {
28 u8 i2c_address;
29};
30
31/**
32 * Attach a qt1010 tuner to the supplied frontend structure.
33 *
34 * @param fe frontend to attach to
35 * @param i2c i2c adapter to use
36 * @param cfg tuner hw based configuration
37 * @return fe pointer on success, NULL on failure
38 */
39#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE))
40extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
41 struct i2c_adapter *i2c,
42 struct qt1010_config *cfg);
43#else
44static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
45 struct i2c_adapter *i2c,
46 struct qt1010_config *cfg)
47{
48 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
49 return NULL;
50}
51#endif // CONFIG_DVB_TUNER_QT1010
52
53#endif
diff --git a/drivers/media/common/tuners/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h
new file mode 100644
index 000000000000..090cf475f099
--- /dev/null
+++ b/drivers/media/common/tuners/qt1010_priv.h
@@ -0,0 +1,105 @@
1/*
2 * Driver for Quantek QT1010 silicon tuner
3 *
4 * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
5 * Aapo Tahkola <aet@rasterburn.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef QT1010_PRIV_H
23#define QT1010_PRIV_H
24
25/*
26reg def meaning
27=== === =======
2800 00 ?
2901 a0 ? operation start/stop; start=80, stop=00
3002 00 ?
3103 19 ?
3204 00 ?
3305 00 ? maybe band selection
3406 00 ?
3507 2b set frequency: 32 MHz scale, n*32 MHz
3608 0b ?
3709 10 ? changes every 8/24 MHz; values 1d/1c
380a 08 set frequency: 4 MHz scale, n*4 MHz
390b 41 ? changes every 2/2 MHz; values 45/45
400c e1 ?
410d 94 ?
420e b6 ?
430f 2c ?
4410 10 ?
4511 f1 ? maybe device specified adjustment
4612 11 ? maybe device specified adjustment
4713 3f ?
4814 1f ?
4915 3f ?
5016 ff ?
5117 ff ?
5218 f7 ?
5319 80 ?
541a d0 set frequency: 125 kHz scale, n*125 kHz
551b 00 ?
561c 89 ?
571d 00 ?
581e 00 ? looks like operation register; write cmd here, read result from 1f-26
591f 20 ? chip initialization
6020 e0 ? chip initialization
6121 20 ?
6222 d0 ?
6323 d0 ?
6424 d0 ?
6525 40 ? chip initialization
6626 08 ?
6727 29 ?
6828 55 ?
6929 39 ?
702a 13 ?
712b 01 ?
722c ea ?
732d 00 ?
742e 00 ? not used?
752f 00 ? not used?
76*/
77
78#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers,
79 hw could be more precise but we don't
80 know how to use */
81#define QT1010_MIN_FREQ 48000000 /* 48 MHz */
82#define QT1010_MAX_FREQ 860000000 /* 860 MHz */
83#define QT1010_OFFSET 1246000000 /* 1246 MHz */
84
85#define QT1010_WR 0
86#define QT1010_RD 1
87#define QT1010_M1 3
88
89typedef struct {
90 u8 oper, reg, val;
91} qt1010_i2c_oper_t;
92
93struct qt1010_priv {
94 struct qt1010_config *cfg;
95 struct i2c_adapter *i2c;
96
97 u8 reg1f_init_val;
98 u8 reg20_init_val;
99 u8 reg25_init_val;
100
101 u32 frequency;
102 u32 bandwidth;
103};
104
105#endif