aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/common/tuners/qt1010.c
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/tuners/qt1010.c
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/tuners/qt1010.c')
-rw-r--r--drivers/media/common/tuners/qt1010.c485
1 files changed, 485 insertions, 0 deletions
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");