1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Driver for the ST STV6111 tuner |
4 | * |
5 | * Copyright (C) 2014 Digital Devices GmbH |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/moduleparam.h> |
11 | #include <linux/init.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/firmware.h> |
14 | #include <linux/i2c.h> |
15 | #include <asm/div64.h> |
16 | |
17 | #include "stv6111.h" |
18 | |
19 | #include <media/dvb_frontend.h> |
20 | |
21 | struct stv { |
22 | struct i2c_adapter *i2c; |
23 | u8 adr; |
24 | |
25 | u8 reg[11]; |
26 | u32 ref_freq; |
27 | u32 frequency; |
28 | }; |
29 | |
30 | struct slookup { |
31 | s16 value; |
32 | u16 reg_value; |
33 | }; |
34 | |
35 | static const struct slookup lnagain_nf_lookup[] = { |
36 | /* Gain *100dB // Reg */ |
37 | { 2572, 0 }, |
38 | { 2575, 1 }, |
39 | { 2580, 2 }, |
40 | { 2588, 3 }, |
41 | { 2596, 4 }, |
42 | { 2611, 5 }, |
43 | { 2633, 6 }, |
44 | { 2664, 7 }, |
45 | { 2701, 8 }, |
46 | { 2753, 9 }, |
47 | { 2816, 10 }, |
48 | { 2902, 11 }, |
49 | { 2995, 12 }, |
50 | { 3104, 13 }, |
51 | { 3215, 14 }, |
52 | { 3337, 15 }, |
53 | { 3492, 16 }, |
54 | { 3614, 17 }, |
55 | { 3731, 18 }, |
56 | { 3861, 19 }, |
57 | { 3988, 20 }, |
58 | { 4124, 21 }, |
59 | { 4253, 22 }, |
60 | { 4386, 23 }, |
61 | { 4505, 24 }, |
62 | { 4623, 25 }, |
63 | { 4726, 26 }, |
64 | { 4821, 27 }, |
65 | { 4903, 28 }, |
66 | { 4979, 29 }, |
67 | { 5045, 30 }, |
68 | { 5102, 31 } |
69 | }; |
70 | |
71 | static const struct slookup lnagain_iip3_lookup[] = { |
72 | /* Gain *100dB // reg */ |
73 | { 1548, 0 }, |
74 | { 1552, 1 }, |
75 | { 1569, 2 }, |
76 | { 1565, 3 }, |
77 | { 1577, 4 }, |
78 | { 1594, 5 }, |
79 | { 1627, 6 }, |
80 | { 1656, 7 }, |
81 | { 1700, 8 }, |
82 | { 1748, 9 }, |
83 | { 1805, 10 }, |
84 | { 1896, 11 }, |
85 | { 1995, 12 }, |
86 | { 2113, 13 }, |
87 | { 2233, 14 }, |
88 | { 2366, 15 }, |
89 | { 2543, 16 }, |
90 | { 2687, 17 }, |
91 | { 2842, 18 }, |
92 | { 2999, 19 }, |
93 | { 3167, 20 }, |
94 | { 3342, 21 }, |
95 | { 3507, 22 }, |
96 | { 3679, 23 }, |
97 | { 3827, 24 }, |
98 | { 3970, 25 }, |
99 | { 4094, 26 }, |
100 | { 4210, 27 }, |
101 | { 4308, 28 }, |
102 | { 4396, 29 }, |
103 | { 4468, 30 }, |
104 | { 4535, 31 } |
105 | }; |
106 | |
107 | static const struct slookup gain_rfagc_lookup[] = { |
108 | /* Gain *100dB // reg */ |
109 | { 4870, 0x3000 }, |
110 | { 4850, 0x3C00 }, |
111 | { 4800, 0x4500 }, |
112 | { 4750, 0x4800 }, |
113 | { 4700, 0x4B00 }, |
114 | { 4650, 0x4D00 }, |
115 | { 4600, 0x4F00 }, |
116 | { 4550, 0x5100 }, |
117 | { 4500, 0x5200 }, |
118 | { 4420, 0x5500 }, |
119 | { 4316, 0x5800 }, |
120 | { 4200, 0x5B00 }, |
121 | { 4119, 0x5D00 }, |
122 | { 3999, 0x6000 }, |
123 | { 3950, 0x6100 }, |
124 | { 3876, 0x6300 }, |
125 | { 3755, 0x6600 }, |
126 | { 3641, 0x6900 }, |
127 | { 3567, 0x6B00 }, |
128 | { 3425, 0x6F00 }, |
129 | { 3350, 0x7100 }, |
130 | { 3236, 0x7400 }, |
131 | { 3118, 0x7700 }, |
132 | { 3004, 0x7A00 }, |
133 | { 2917, 0x7C00 }, |
134 | { 2776, 0x7F00 }, |
135 | { 2635, 0x8200 }, |
136 | { 2516, 0x8500 }, |
137 | { 2406, 0x8800 }, |
138 | { 2290, 0x8B00 }, |
139 | { 2170, 0x8E00 }, |
140 | { 2073, 0x9100 }, |
141 | { 1949, 0x9400 }, |
142 | { 1836, 0x9700 }, |
143 | { 1712, 0x9A00 }, |
144 | { 1631, 0x9C00 }, |
145 | { 1515, 0x9F00 }, |
146 | { 1400, 0xA200 }, |
147 | { 1323, 0xA400 }, |
148 | { 1203, 0xA700 }, |
149 | { 1091, 0xAA00 }, |
150 | { 1011, 0xAC00 }, |
151 | { 904, 0xAF00 }, |
152 | { 787, 0xB200 }, |
153 | { 685, 0xB500 }, |
154 | { 571, 0xB800 }, |
155 | { 464, 0xBB00 }, |
156 | { 374, 0xBE00 }, |
157 | { 275, 0xC200 }, |
158 | { 181, 0xC600 }, |
159 | { 102, 0xCC00 }, |
160 | { 49, 0xD900 } |
161 | }; |
162 | |
163 | /* |
164 | * This table is 6 dB too low comapred to the others (probably created with |
165 | * a different BB_MAG setting) |
166 | */ |
167 | static const struct slookup gain_channel_agc_nf_lookup[] = { |
168 | /* Gain *100dB // reg */ |
169 | { 7082, 0x3000 }, |
170 | { 7052, 0x4000 }, |
171 | { 7007, 0x4600 }, |
172 | { 6954, 0x4A00 }, |
173 | { 6909, 0x4D00 }, |
174 | { 6833, 0x5100 }, |
175 | { 6753, 0x5400 }, |
176 | { 6659, 0x5700 }, |
177 | { 6561, 0x5A00 }, |
178 | { 6472, 0x5C00 }, |
179 | { 6366, 0x5F00 }, |
180 | { 6259, 0x6100 }, |
181 | { 6151, 0x6400 }, |
182 | { 6026, 0x6700 }, |
183 | { 5920, 0x6900 }, |
184 | { 5835, 0x6B00 }, |
185 | { 5770, 0x6C00 }, |
186 | { 5681, 0x6E00 }, |
187 | { 5596, 0x7000 }, |
188 | { 5503, 0x7200 }, |
189 | { 5429, 0x7300 }, |
190 | { 5319, 0x7500 }, |
191 | { 5220, 0x7700 }, |
192 | { 5111, 0x7900 }, |
193 | { 4983, 0x7B00 }, |
194 | { 4876, 0x7D00 }, |
195 | { 4755, 0x7F00 }, |
196 | { 4635, 0x8100 }, |
197 | { 4499, 0x8300 }, |
198 | { 4405, 0x8500 }, |
199 | { 4323, 0x8600 }, |
200 | { 4233, 0x8800 }, |
201 | { 4156, 0x8A00 }, |
202 | { 4038, 0x8C00 }, |
203 | { 3935, 0x8E00 }, |
204 | { 3823, 0x9000 }, |
205 | { 3712, 0x9200 }, |
206 | { 3601, 0x9500 }, |
207 | { 3511, 0x9700 }, |
208 | { 3413, 0x9900 }, |
209 | { 3309, 0x9B00 }, |
210 | { 3213, 0x9D00 }, |
211 | { 3088, 0x9F00 }, |
212 | { 2992, 0xA100 }, |
213 | { 2878, 0xA400 }, |
214 | { 2769, 0xA700 }, |
215 | { 2645, 0xAA00 }, |
216 | { 2538, 0xAD00 }, |
217 | { 2441, 0xB000 }, |
218 | { 2350, 0xB600 }, |
219 | { 2237, 0xBA00 }, |
220 | { 2137, 0xBF00 }, |
221 | { 2039, 0xC500 }, |
222 | { 1938, 0xDF00 }, |
223 | { 1927, 0xFF00 } |
224 | }; |
225 | |
226 | static const struct slookup gain_channel_agc_iip3_lookup[] = { |
227 | /* Gain *100dB // reg */ |
228 | { 7070, 0x3000 }, |
229 | { 7028, 0x4000 }, |
230 | { 7019, 0x4600 }, |
231 | { 6900, 0x4A00 }, |
232 | { 6811, 0x4D00 }, |
233 | { 6763, 0x5100 }, |
234 | { 6690, 0x5400 }, |
235 | { 6644, 0x5700 }, |
236 | { 6617, 0x5A00 }, |
237 | { 6598, 0x5C00 }, |
238 | { 6462, 0x5F00 }, |
239 | { 6348, 0x6100 }, |
240 | { 6197, 0x6400 }, |
241 | { 6154, 0x6700 }, |
242 | { 6098, 0x6900 }, |
243 | { 5893, 0x6B00 }, |
244 | { 5812, 0x6C00 }, |
245 | { 5773, 0x6E00 }, |
246 | { 5723, 0x7000 }, |
247 | { 5661, 0x7200 }, |
248 | { 5579, 0x7300 }, |
249 | { 5460, 0x7500 }, |
250 | { 5308, 0x7700 }, |
251 | { 5099, 0x7900 }, |
252 | { 4910, 0x7B00 }, |
253 | { 4800, 0x7D00 }, |
254 | { 4785, 0x7F00 }, |
255 | { 4635, 0x8100 }, |
256 | { 4466, 0x8300 }, |
257 | { 4314, 0x8500 }, |
258 | { 4295, 0x8600 }, |
259 | { 4144, 0x8800 }, |
260 | { 3920, 0x8A00 }, |
261 | { 3889, 0x8C00 }, |
262 | { 3771, 0x8E00 }, |
263 | { 3655, 0x9000 }, |
264 | { 3446, 0x9200 }, |
265 | { 3298, 0x9500 }, |
266 | { 3083, 0x9700 }, |
267 | { 3015, 0x9900 }, |
268 | { 2833, 0x9B00 }, |
269 | { 2746, 0x9D00 }, |
270 | { 2632, 0x9F00 }, |
271 | { 2598, 0xA100 }, |
272 | { 2480, 0xA400 }, |
273 | { 2236, 0xA700 }, |
274 | { 2171, 0xAA00 }, |
275 | { 2060, 0xAD00 }, |
276 | { 1999, 0xB000 }, |
277 | { 1974, 0xB600 }, |
278 | { 1820, 0xBA00 }, |
279 | { 1741, 0xBF00 }, |
280 | { 1655, 0xC500 }, |
281 | { 1444, 0xDF00 }, |
282 | { 1325, 0xFF00 }, |
283 | }; |
284 | |
285 | static inline u32 muldiv32(u32 a, u32 b, u32 c) |
286 | { |
287 | u64 tmp64; |
288 | |
289 | tmp64 = (u64)a * (u64)b; |
290 | do_div(tmp64, c); |
291 | |
292 | return (u32)tmp64; |
293 | } |
294 | |
295 | static int i2c_read(struct i2c_adapter *adap, |
296 | u8 adr, u8 *msg, int len, u8 *answ, int alen) |
297 | { |
298 | struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, |
299 | .buf = msg, .len = len}, |
300 | { .addr = adr, .flags = I2C_M_RD, |
301 | .buf = answ, .len = alen } }; |
302 | if (i2c_transfer(adap, msgs, num: 2) != 2) { |
303 | dev_err(&adap->dev, "i2c read error\n" ); |
304 | return -EIO; |
305 | } |
306 | return 0; |
307 | } |
308 | |
309 | static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) |
310 | { |
311 | struct i2c_msg msg = {.addr = adr, .flags = 0, |
312 | .buf = data, .len = len}; |
313 | |
314 | if (i2c_transfer(adap, msgs: &msg, num: 1) != 1) { |
315 | dev_err(&adap->dev, "i2c write error\n" ); |
316 | return -EIO; |
317 | } |
318 | return 0; |
319 | } |
320 | |
321 | static int write_regs(struct stv *state, int reg, int len) |
322 | { |
323 | u8 d[12]; |
324 | |
325 | memcpy(&d[1], &state->reg[reg], len); |
326 | d[0] = reg; |
327 | return i2c_write(adap: state->i2c, adr: state->adr, data: d, len: len + 1); |
328 | } |
329 | |
330 | static int write_reg(struct stv *state, u8 reg, u8 val) |
331 | { |
332 | u8 d[2] = {reg, val}; |
333 | |
334 | return i2c_write(adap: state->i2c, adr: state->adr, data: d, len: 2); |
335 | } |
336 | |
337 | static int read_reg(struct stv *state, u8 reg, u8 *val) |
338 | { |
339 | return i2c_read(adap: state->i2c, adr: state->adr, msg: ®, len: 1, answ: val, alen: 1); |
340 | } |
341 | |
342 | static int wait_for_call_done(struct stv *state, u8 mask) |
343 | { |
344 | int status = 0; |
345 | u32 lock_retry_count = 10; |
346 | |
347 | while (lock_retry_count > 0) { |
348 | u8 regval; |
349 | |
350 | status = read_reg(state, reg: 9, val: ®val); |
351 | if (status < 0) |
352 | return status; |
353 | |
354 | if ((regval & mask) == 0) |
355 | break; |
356 | usleep_range(min: 4000, max: 6000); |
357 | lock_retry_count -= 1; |
358 | |
359 | status = -EIO; |
360 | } |
361 | return status; |
362 | } |
363 | |
364 | static void init_state(struct stv *state) |
365 | { |
366 | u32 clkdiv = 0; |
367 | u32 agcmode = 0; |
368 | u32 agcref = 2; |
369 | u32 agcset = 0xffffffff; |
370 | u32 bbmode = 0xffffffff; |
371 | |
372 | state->reg[0] = 0x08; |
373 | state->reg[1] = 0x41; |
374 | state->reg[2] = 0x8f; |
375 | state->reg[3] = 0x00; |
376 | state->reg[4] = 0xce; |
377 | state->reg[5] = 0x54; |
378 | state->reg[6] = 0x55; |
379 | state->reg[7] = 0x45; |
380 | state->reg[8] = 0x46; |
381 | state->reg[9] = 0xbd; |
382 | state->reg[10] = 0x11; |
383 | |
384 | state->ref_freq = 16000; |
385 | |
386 | if (clkdiv <= 3) |
387 | state->reg[0x00] |= (clkdiv & 0x03); |
388 | if (agcmode <= 3) { |
389 | state->reg[0x03] |= (agcmode << 5); |
390 | if (agcmode == 0x01) |
391 | state->reg[0x01] |= 0x30; |
392 | } |
393 | if (bbmode <= 3) |
394 | state->reg[0x01] = (state->reg[0x01] & ~0x30) | (bbmode << 4); |
395 | if (agcref <= 7) |
396 | state->reg[0x03] |= agcref; |
397 | if (agcset <= 31) |
398 | state->reg[0x02] = (state->reg[0x02] & ~0x1F) | agcset | 0x40; |
399 | } |
400 | |
401 | static int attach_init(struct stv *state) |
402 | { |
403 | if (write_regs(state, reg: 0, len: 11)) |
404 | return -ENODEV; |
405 | return 0; |
406 | } |
407 | |
408 | static void release(struct dvb_frontend *fe) |
409 | { |
410 | kfree(objp: fe->tuner_priv); |
411 | fe->tuner_priv = NULL; |
412 | } |
413 | |
414 | static int set_bandwidth(struct dvb_frontend *fe, u32 cutoff_frequency) |
415 | { |
416 | struct stv *state = fe->tuner_priv; |
417 | u32 index = (cutoff_frequency + 999999) / 1000000; |
418 | int stat = 0; |
419 | |
420 | if (index < 6) |
421 | index = 6; |
422 | if (index > 50) |
423 | index = 50; |
424 | if ((state->reg[0x08] & ~0xFC) == ((index - 6) << 2)) |
425 | return 0; |
426 | |
427 | state->reg[0x08] = (state->reg[0x08] & ~0xFC) | ((index - 6) << 2); |
428 | state->reg[0x09] = (state->reg[0x09] & ~0x0C) | 0x08; |
429 | if (fe->ops.i2c_gate_ctrl) |
430 | stat = fe->ops.i2c_gate_ctrl(fe, 1); |
431 | if (!stat) { |
432 | write_regs(state, reg: 0x08, len: 2); |
433 | wait_for_call_done(state, mask: 0x08); |
434 | } |
435 | if (fe->ops.i2c_gate_ctrl && !stat) |
436 | fe->ops.i2c_gate_ctrl(fe, 0); |
437 | return stat; |
438 | } |
439 | |
440 | static int set_lof(struct stv *state, u32 local_frequency, u32 cutoff_frequency) |
441 | { |
442 | u32 index = (cutoff_frequency + 999999) / 1000000; |
443 | u32 frequency = (local_frequency + 500) / 1000; |
444 | u32 p = 1, psel = 0, fvco, div, frac; |
445 | u8 icp, tmp; |
446 | |
447 | if (index < 6) |
448 | index = 6; |
449 | if (index > 50) |
450 | index = 50; |
451 | |
452 | if (frequency <= 1300000) { |
453 | p = 4; |
454 | psel = 1; |
455 | } else { |
456 | p = 2; |
457 | psel = 0; |
458 | } |
459 | fvco = frequency * p; |
460 | div = fvco / state->ref_freq; |
461 | frac = fvco % state->ref_freq; |
462 | frac = muldiv32(a: frac, b: 0x40000, c: state->ref_freq); |
463 | |
464 | icp = 0; |
465 | if (fvco < 2700000) |
466 | icp = 0; |
467 | else if (fvco < 2950000) |
468 | icp = 1; |
469 | else if (fvco < 3300000) |
470 | icp = 2; |
471 | else if (fvco < 3700000) |
472 | icp = 3; |
473 | else if (fvco < 4200000) |
474 | icp = 5; |
475 | else if (fvco < 4800000) |
476 | icp = 6; |
477 | else |
478 | icp = 7; |
479 | |
480 | state->reg[0x02] |= 0x80; /* LNA IIP3 Mode */ |
481 | |
482 | state->reg[0x03] = (state->reg[0x03] & ~0x80) | (psel << 7); |
483 | state->reg[0x04] = (div & 0xFF); |
484 | state->reg[0x05] = (((div >> 8) & 0x01) | ((frac & 0x7F) << 1)) & 0xff; |
485 | state->reg[0x06] = ((frac >> 7) & 0xFF); |
486 | state->reg[0x07] = (state->reg[0x07] & ~0x07) | ((frac >> 15) & 0x07); |
487 | state->reg[0x07] = (state->reg[0x07] & ~0xE0) | (icp << 5); |
488 | |
489 | state->reg[0x08] = (state->reg[0x08] & ~0xFC) | ((index - 6) << 2); |
490 | /* Start cal vco,CF */ |
491 | state->reg[0x09] = (state->reg[0x09] & ~0x0C) | 0x0C; |
492 | write_regs(state, reg: 2, len: 8); |
493 | |
494 | wait_for_call_done(state, mask: 0x0C); |
495 | |
496 | usleep_range(min: 10000, max: 12000); |
497 | |
498 | read_reg(state, reg: 0x03, val: &tmp); |
499 | if (tmp & 0x10) { |
500 | state->reg[0x02] &= ~0x80; /* LNA NF Mode */ |
501 | write_regs(state, reg: 2, len: 1); |
502 | } |
503 | read_reg(state, reg: 0x08, val: &tmp); |
504 | |
505 | state->frequency = frequency; |
506 | |
507 | return 0; |
508 | } |
509 | |
510 | static int set_params(struct dvb_frontend *fe) |
511 | { |
512 | struct stv *state = fe->tuner_priv; |
513 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
514 | u32 freq, cutoff; |
515 | int stat = 0; |
516 | |
517 | if (p->delivery_system != SYS_DVBS && p->delivery_system != SYS_DVBS2) |
518 | return -EINVAL; |
519 | |
520 | freq = p->frequency * 1000; |
521 | cutoff = 5000000 + muldiv32(a: p->symbol_rate, b: 135, c: 200); |
522 | |
523 | if (fe->ops.i2c_gate_ctrl) |
524 | stat = fe->ops.i2c_gate_ctrl(fe, 1); |
525 | if (!stat) |
526 | set_lof(state, local_frequency: freq, cutoff_frequency: cutoff); |
527 | if (fe->ops.i2c_gate_ctrl && !stat) |
528 | fe->ops.i2c_gate_ctrl(fe, 0); |
529 | return 0; |
530 | } |
531 | |
532 | static s32 table_lookup(const struct slookup *table, |
533 | int table_size, u16 reg_value) |
534 | { |
535 | s32 gain; |
536 | s32 reg_diff; |
537 | int imin = 0; |
538 | int imax = table_size - 1; |
539 | int i; |
540 | |
541 | /* Assumes Table[0].RegValue < Table[imax].RegValue */ |
542 | if (reg_value <= table[0].reg_value) { |
543 | gain = table[0].value; |
544 | } else if (reg_value >= table[imax].reg_value) { |
545 | gain = table[imax].value; |
546 | } else { |
547 | while ((imax - imin) > 1) { |
548 | i = (imax + imin) / 2; |
549 | if ((table[imin].reg_value <= reg_value) && |
550 | (reg_value <= table[i].reg_value)) |
551 | imax = i; |
552 | else |
553 | imin = i; |
554 | } |
555 | reg_diff = table[imax].reg_value - table[imin].reg_value; |
556 | gain = table[imin].value; |
557 | if (reg_diff != 0) |
558 | gain += ((s32)(reg_value - table[imin].reg_value) * |
559 | (s32)(table[imax].value |
560 | - table[imin].value)) / reg_diff; |
561 | } |
562 | return gain; |
563 | } |
564 | |
565 | static int get_rf_strength(struct dvb_frontend *fe, u16 *st) |
566 | { |
567 | struct stv *state = fe->tuner_priv; |
568 | u16 rfagc = *st; |
569 | s32 gain; |
570 | |
571 | if ((state->reg[0x03] & 0x60) == 0) { |
572 | /* RF Mode, Read AGC ADC */ |
573 | u8 reg = 0; |
574 | int stat = 0; |
575 | |
576 | if (fe->ops.i2c_gate_ctrl) |
577 | stat = fe->ops.i2c_gate_ctrl(fe, 1); |
578 | if (!stat) { |
579 | write_reg(state, reg: 0x02, val: state->reg[0x02] | 0x20); |
580 | read_reg(state, reg: 2, val: ®); |
581 | if (reg & 0x20) |
582 | read_reg(state, reg: 2, val: ®); |
583 | } |
584 | if (fe->ops.i2c_gate_ctrl && !stat) |
585 | fe->ops.i2c_gate_ctrl(fe, 0); |
586 | |
587 | if ((state->reg[0x02] & 0x80) == 0) |
588 | /* NF */ |
589 | gain = table_lookup(table: lnagain_nf_lookup, |
590 | ARRAY_SIZE(lnagain_nf_lookup), |
591 | reg_value: reg & 0x1F); |
592 | else |
593 | /* IIP3 */ |
594 | gain = table_lookup(table: lnagain_iip3_lookup, |
595 | ARRAY_SIZE(lnagain_iip3_lookup), |
596 | reg_value: reg & 0x1F); |
597 | |
598 | gain += table_lookup(table: gain_rfagc_lookup, |
599 | ARRAY_SIZE(gain_rfagc_lookup), reg_value: rfagc); |
600 | |
601 | gain -= 2400; |
602 | } else { |
603 | /* Channel Mode */ |
604 | if ((state->reg[0x02] & 0x80) == 0) { |
605 | /* NF */ |
606 | gain = table_lookup( |
607 | table: gain_channel_agc_nf_lookup, |
608 | ARRAY_SIZE(gain_channel_agc_nf_lookup), reg_value: rfagc); |
609 | |
610 | gain += 600; |
611 | } else { |
612 | /* IIP3 */ |
613 | gain = table_lookup( |
614 | table: gain_channel_agc_iip3_lookup, |
615 | ARRAY_SIZE(gain_channel_agc_iip3_lookup), |
616 | reg_value: rfagc); |
617 | } |
618 | } |
619 | |
620 | if (state->frequency > 0) |
621 | /* Tilt correction ( 0.00016 dB/MHz ) */ |
622 | gain -= ((((s32)(state->frequency / 1000) - 1550) * 2) / 12); |
623 | |
624 | /* + (BBGain * 10); */ |
625 | gain += (s32)((state->reg[0x01] & 0xC0) >> 6) * 600 - 1300; |
626 | |
627 | if (gain < 0) |
628 | gain = 0; |
629 | else if (gain > 10000) |
630 | gain = 10000; |
631 | |
632 | *st = 10000 - gain; |
633 | |
634 | return 0; |
635 | } |
636 | |
637 | static const struct dvb_tuner_ops tuner_ops = { |
638 | .info = { |
639 | .name = "ST STV6111" , |
640 | .frequency_min_hz = 950 * MHz, |
641 | .frequency_max_hz = 2150 * MHz, |
642 | }, |
643 | .set_params = set_params, |
644 | .release = release, |
645 | .get_rf_strength = get_rf_strength, |
646 | .set_bandwidth = set_bandwidth, |
647 | }; |
648 | |
649 | struct dvb_frontend *stv6111_attach(struct dvb_frontend *fe, |
650 | struct i2c_adapter *i2c, u8 adr) |
651 | { |
652 | struct stv *state; |
653 | int stat = -ENODEV; |
654 | int gatestat = 0; |
655 | |
656 | state = kzalloc(size: sizeof(*state), GFP_KERNEL); |
657 | if (!state) |
658 | return NULL; |
659 | state->adr = adr; |
660 | state->i2c = i2c; |
661 | memcpy(&fe->ops.tuner_ops, &tuner_ops, sizeof(struct dvb_tuner_ops)); |
662 | init_state(state); |
663 | |
664 | if (fe->ops.i2c_gate_ctrl) |
665 | gatestat = fe->ops.i2c_gate_ctrl(fe, 1); |
666 | if (!gatestat) |
667 | stat = attach_init(state); |
668 | if (fe->ops.i2c_gate_ctrl && !gatestat) |
669 | fe->ops.i2c_gate_ctrl(fe, 0); |
670 | if (stat < 0) { |
671 | kfree(objp: state); |
672 | return NULL; |
673 | } |
674 | fe->tuner_priv = state; |
675 | return fe; |
676 | } |
677 | EXPORT_SYMBOL_GPL(stv6111_attach); |
678 | |
679 | MODULE_DESCRIPTION("ST STV6111 satellite tuner driver" ); |
680 | MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel" ); |
681 | MODULE_LICENSE("GPL v2" ); |
682 | |