Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/common/tuners/qt1010.c
15112 views
1
/*
2
* Driver for Quantek QT1010 silicon tuner
3
*
4
* Copyright (C) 2006 Antti Palosaari <[email protected]>
5
* Aapo Tahkola <[email protected]>
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
24
static int debug;
25
module_param(debug, int, 0644);
26
MODULE_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 */
34
static 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 */
51
static 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 */
65
static void qt1010_dump_regs(struct qt1010_priv *priv)
66
{
67
u8 reg, val;
68
69
for (reg = 0; ; reg++) {
70
if (reg % 16 == 0) {
71
if (reg)
72
printk(KERN_CONT "\n");
73
printk(KERN_DEBUG "%02x:", reg);
74
}
75
if (qt1010_readreg(priv, reg, &val) == 0)
76
printk(KERN_CONT " %02x", val);
77
else
78
printk(KERN_CONT " --");
79
if (reg == 0x2f)
80
break;
81
}
82
printk(KERN_CONT "\n");
83
}
84
85
static int qt1010_set_params(struct dvb_frontend *fe,
86
struct dvb_frontend_parameters *params)
87
{
88
struct qt1010_priv *priv;
89
int err;
90
u32 freq, div, mod1, mod2;
91
u8 i, tmpval, reg05;
92
qt1010_i2c_oper_t rd[48] = {
93
{ QT1010_WR, 0x01, 0x80 },
94
{ QT1010_WR, 0x02, 0x3f },
95
{ QT1010_WR, 0x05, 0xff }, /* 02 c write */
96
{ QT1010_WR, 0x06, 0x44 },
97
{ QT1010_WR, 0x07, 0xff }, /* 04 c write */
98
{ QT1010_WR, 0x08, 0x08 },
99
{ QT1010_WR, 0x09, 0xff }, /* 06 c write */
100
{ QT1010_WR, 0x0a, 0xff }, /* 07 c write */
101
{ QT1010_WR, 0x0b, 0xff }, /* 08 c write */
102
{ QT1010_WR, 0x0c, 0xe1 },
103
{ QT1010_WR, 0x1a, 0xff }, /* 10 c write */
104
{ QT1010_WR, 0x1b, 0x00 },
105
{ QT1010_WR, 0x1c, 0x89 },
106
{ QT1010_WR, 0x11, 0xff }, /* 13 c write */
107
{ QT1010_WR, 0x12, 0xff }, /* 14 c write */
108
{ QT1010_WR, 0x22, 0xff }, /* 15 c write */
109
{ QT1010_WR, 0x1e, 0x00 },
110
{ QT1010_WR, 0x1e, 0xd0 },
111
{ QT1010_RD, 0x22, 0xff }, /* 16 c read */
112
{ QT1010_WR, 0x1e, 0x00 },
113
{ QT1010_RD, 0x05, 0xff }, /* 20 c read */
114
{ QT1010_RD, 0x22, 0xff }, /* 21 c read */
115
{ QT1010_WR, 0x23, 0xd0 },
116
{ QT1010_WR, 0x1e, 0x00 },
117
{ QT1010_WR, 0x1e, 0xe0 },
118
{ QT1010_RD, 0x23, 0xff }, /* 25 c read */
119
{ QT1010_RD, 0x23, 0xff }, /* 26 c read */
120
{ QT1010_WR, 0x1e, 0x00 },
121
{ QT1010_WR, 0x24, 0xd0 },
122
{ QT1010_WR, 0x1e, 0x00 },
123
{ QT1010_WR, 0x1e, 0xf0 },
124
{ QT1010_RD, 0x24, 0xff }, /* 31 c read */
125
{ QT1010_WR, 0x1e, 0x00 },
126
{ QT1010_WR, 0x14, 0x7f },
127
{ QT1010_WR, 0x15, 0x7f },
128
{ QT1010_WR, 0x05, 0xff }, /* 35 c write */
129
{ QT1010_WR, 0x06, 0x00 },
130
{ QT1010_WR, 0x15, 0x1f },
131
{ QT1010_WR, 0x16, 0xff },
132
{ QT1010_WR, 0x18, 0xff },
133
{ QT1010_WR, 0x1f, 0xff }, /* 40 c write */
134
{ QT1010_WR, 0x20, 0xff }, /* 41 c write */
135
{ QT1010_WR, 0x21, 0x53 },
136
{ QT1010_WR, 0x25, 0xff }, /* 43 c write */
137
{ QT1010_WR, 0x26, 0x15 },
138
{ QT1010_WR, 0x00, 0xff }, /* 45 c write */
139
{ QT1010_WR, 0x02, 0x00 },
140
{ QT1010_WR, 0x01, 0x00 }
141
};
142
143
#define FREQ1 32000000 /* 32 MHz */
144
#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */
145
146
priv = fe->tuner_priv;
147
freq = params->frequency;
148
div = (freq + QT1010_OFFSET) / QT1010_STEP;
149
freq = (div * QT1010_STEP) - QT1010_OFFSET;
150
mod1 = (freq + QT1010_OFFSET) % FREQ1;
151
mod2 = (freq + QT1010_OFFSET) % FREQ2;
152
priv->bandwidth =
153
(fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
154
priv->frequency = freq;
155
156
if (fe->ops.i2c_gate_ctrl)
157
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
158
159
/* reg 05 base value */
160
if (freq < 290000000) reg05 = 0x14; /* 290 MHz */
161
else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
162
else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
163
else reg05 = 0x74;
164
165
/* 0x5 */
166
rd[2].val = reg05;
167
168
/* 07 - set frequency: 32 MHz scale */
169
rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
170
171
/* 09 - changes every 8/24 MHz */
172
if (mod1 < 8000000) rd[6].val = 0x1d;
173
else rd[6].val = 0x1c;
174
175
/* 0a - set frequency: 4 MHz scale (max 28 MHz) */
176
if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */
177
else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */
178
else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */
179
else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
180
else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
181
else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
182
else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
183
else rd[7].val = 0x0a; /* +28 MHz */
184
185
/* 0b - changes every 2/2 MHz */
186
if (mod2 < 2000000) rd[8].val = 0x45;
187
else rd[8].val = 0x44;
188
189
/* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
190
tmpval = 0x78; /* byte, overflows intentionally */
191
rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
192
193
/* 11 */
194
rd[13].val = 0xfd; /* TODO: correct value calculation */
195
196
/* 12 */
197
rd[14].val = 0x91; /* TODO: correct value calculation */
198
199
/* 22 */
200
if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
201
else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
202
else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
203
else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
204
else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
205
else rd[15].val = 0xd0;
206
207
/* 05 */
208
rd[35].val = (reg05 & 0xf0);
209
210
/* 1f */
211
if (mod1 < 8000000) tmpval = 0x00;
212
else if (mod1 < 12000000) tmpval = 0x01;
213
else if (mod1 < 16000000) tmpval = 0x02;
214
else if (mod1 < 24000000) tmpval = 0x03;
215
else if (mod1 < 28000000) tmpval = 0x04;
216
else tmpval = 0x05;
217
rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
218
219
/* 20 */
220
if (mod1 < 8000000) tmpval = 0x00;
221
else if (mod1 < 12000000) tmpval = 0x01;
222
else if (mod1 < 20000000) tmpval = 0x02;
223
else if (mod1 < 24000000) tmpval = 0x03;
224
else if (mod1 < 28000000) tmpval = 0x04;
225
else tmpval = 0x05;
226
rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
227
228
/* 25 */
229
rd[43].val = priv->reg25_init_val;
230
231
/* 00 */
232
rd[45].val = 0x92; /* TODO: correct value calculation */
233
234
dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
235
"1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
236
"20:%02x 25:%02x 00:%02x", \
237
freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
238
rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
239
rd[40].val, rd[41].val, rd[43].val, rd[45].val);
240
241
for (i = 0; i < ARRAY_SIZE(rd); i++) {
242
if (rd[i].oper == QT1010_WR) {
243
err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
244
} else { /* read is required to proper locking */
245
err = qt1010_readreg(priv, rd[i].reg, &tmpval);
246
}
247
if (err) return err;
248
}
249
250
if (debug)
251
qt1010_dump_regs(priv);
252
253
if (fe->ops.i2c_gate_ctrl)
254
fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
255
256
return 0;
257
}
258
259
static int qt1010_init_meas1(struct qt1010_priv *priv,
260
u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
261
{
262
u8 i, val1, val2;
263
int err;
264
265
qt1010_i2c_oper_t i2c_data[] = {
266
{ QT1010_WR, reg, reg_init_val },
267
{ QT1010_WR, 0x1e, 0x00 },
268
{ QT1010_WR, 0x1e, oper },
269
{ QT1010_RD, reg, 0xff }
270
};
271
272
for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
273
if (i2c_data[i].oper == QT1010_WR) {
274
err = qt1010_writereg(priv, i2c_data[i].reg,
275
i2c_data[i].val);
276
} else {
277
err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
278
}
279
if (err) return err;
280
}
281
282
do {
283
val1 = val2;
284
err = qt1010_readreg(priv, reg, &val2);
285
if (err) return err;
286
dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
287
} while (val1 != val2);
288
*retval = val1;
289
290
return qt1010_writereg(priv, 0x1e, 0x00);
291
}
292
293
static u8 qt1010_init_meas2(struct qt1010_priv *priv,
294
u8 reg_init_val, u8 *retval)
295
{
296
u8 i, val;
297
int err;
298
qt1010_i2c_oper_t i2c_data[] = {
299
{ QT1010_WR, 0x07, reg_init_val },
300
{ QT1010_WR, 0x22, 0xd0 },
301
{ QT1010_WR, 0x1e, 0x00 },
302
{ QT1010_WR, 0x1e, 0xd0 },
303
{ QT1010_RD, 0x22, 0xff },
304
{ QT1010_WR, 0x1e, 0x00 },
305
{ QT1010_WR, 0x22, 0xff }
306
};
307
for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
308
if (i2c_data[i].oper == QT1010_WR) {
309
err = qt1010_writereg(priv, i2c_data[i].reg,
310
i2c_data[i].val);
311
} else {
312
err = qt1010_readreg(priv, i2c_data[i].reg, &val);
313
}
314
if (err) return err;
315
}
316
*retval = val;
317
return 0;
318
}
319
320
static int qt1010_init(struct dvb_frontend *fe)
321
{
322
struct qt1010_priv *priv = fe->tuner_priv;
323
struct dvb_frontend_parameters params;
324
int err = 0;
325
u8 i, tmpval, *valptr = NULL;
326
327
qt1010_i2c_oper_t i2c_data[] = {
328
{ QT1010_WR, 0x01, 0x80 },
329
{ QT1010_WR, 0x0d, 0x84 },
330
{ QT1010_WR, 0x0e, 0xb7 },
331
{ QT1010_WR, 0x2a, 0x23 },
332
{ QT1010_WR, 0x2c, 0xdc },
333
{ QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
334
{ QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
335
{ QT1010_WR, 0x2b, 0x70 },
336
{ QT1010_WR, 0x2a, 0x23 },
337
{ QT1010_M1, 0x26, 0x08 },
338
{ QT1010_M1, 0x82, 0xff },
339
{ QT1010_WR, 0x05, 0x14 },
340
{ QT1010_WR, 0x06, 0x44 },
341
{ QT1010_WR, 0x07, 0x28 },
342
{ QT1010_WR, 0x08, 0x0b },
343
{ QT1010_WR, 0x11, 0xfd },
344
{ QT1010_M1, 0x22, 0x0d },
345
{ QT1010_M1, 0xd0, 0xff },
346
{ QT1010_WR, 0x06, 0x40 },
347
{ QT1010_WR, 0x16, 0xf0 },
348
{ QT1010_WR, 0x02, 0x38 },
349
{ QT1010_WR, 0x03, 0x18 },
350
{ QT1010_WR, 0x20, 0xe0 },
351
{ QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
352
{ QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
353
{ QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
354
{ QT1010_WR, 0x03, 0x19 },
355
{ QT1010_WR, 0x02, 0x3f },
356
{ QT1010_WR, 0x21, 0x53 },
357
{ QT1010_RD, 0x21, 0xff },
358
{ QT1010_WR, 0x11, 0xfd },
359
{ QT1010_WR, 0x05, 0x34 },
360
{ QT1010_WR, 0x06, 0x44 },
361
{ QT1010_WR, 0x08, 0x08 }
362
};
363
364
if (fe->ops.i2c_gate_ctrl)
365
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
366
367
for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
368
switch (i2c_data[i].oper) {
369
case QT1010_WR:
370
err = qt1010_writereg(priv, i2c_data[i].reg,
371
i2c_data[i].val);
372
break;
373
case QT1010_RD:
374
if (i2c_data[i].val == 0x20)
375
valptr = &priv->reg20_init_val;
376
else
377
valptr = &tmpval;
378
err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
379
break;
380
case QT1010_M1:
381
if (i2c_data[i].val == 0x25)
382
valptr = &priv->reg25_init_val;
383
else if (i2c_data[i].val == 0x1f)
384
valptr = &priv->reg1f_init_val;
385
else
386
valptr = &tmpval;
387
err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
388
i2c_data[i].reg,
389
i2c_data[i].val, valptr);
390
i++;
391
break;
392
}
393
if (err) return err;
394
}
395
396
for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
397
if ((err = qt1010_init_meas2(priv, i, &tmpval)))
398
return err;
399
400
params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
401
/* MSI Megasky 580 GL861 533000000 */
402
return qt1010_set_params(fe, &params);
403
}
404
405
static int qt1010_release(struct dvb_frontend *fe)
406
{
407
kfree(fe->tuner_priv);
408
fe->tuner_priv = NULL;
409
return 0;
410
}
411
412
static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
413
{
414
struct qt1010_priv *priv = fe->tuner_priv;
415
*frequency = priv->frequency;
416
return 0;
417
}
418
419
static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
420
{
421
struct qt1010_priv *priv = fe->tuner_priv;
422
*bandwidth = priv->bandwidth;
423
return 0;
424
}
425
426
static const struct dvb_tuner_ops qt1010_tuner_ops = {
427
.info = {
428
.name = "Quantek QT1010",
429
.frequency_min = QT1010_MIN_FREQ,
430
.frequency_max = QT1010_MAX_FREQ,
431
.frequency_step = QT1010_STEP,
432
},
433
434
.release = qt1010_release,
435
.init = qt1010_init,
436
/* TODO: implement sleep */
437
438
.set_params = qt1010_set_params,
439
.get_frequency = qt1010_get_frequency,
440
.get_bandwidth = qt1010_get_bandwidth
441
};
442
443
struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
444
struct i2c_adapter *i2c,
445
struct qt1010_config *cfg)
446
{
447
struct qt1010_priv *priv = NULL;
448
u8 id;
449
450
priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
451
if (priv == NULL)
452
return NULL;
453
454
priv->cfg = cfg;
455
priv->i2c = i2c;
456
457
if (fe->ops.i2c_gate_ctrl)
458
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
459
460
461
/* Try to detect tuner chip. Probably this is not correct register. */
462
if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
463
kfree(priv);
464
return NULL;
465
}
466
467
if (fe->ops.i2c_gate_ctrl)
468
fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
469
470
printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
471
memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
472
sizeof(struct dvb_tuner_ops));
473
474
fe->tuner_priv = priv;
475
return fe;
476
}
477
EXPORT_SYMBOL(qt1010_attach);
478
479
MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
480
MODULE_AUTHOR("Antti Palosaari <[email protected]>");
481
MODULE_AUTHOR("Aapo Tahkola <[email protected]>");
482
MODULE_VERSION("0.1");
483
MODULE_LICENSE("GPL");
484
485