diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-25 09:26:21 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-04-25 09:26:21 -0400 |
commit | cfc3d6c44470c5509f1e8efb1577b49dbaeeb2da (patch) | |
tree | e63c49de395435ce6a8ae906b13e134636810d3d | |
parent | 542b329f8e0d92ca93d033d13a9db16b89830acd (diff) | |
parent | 396f3659aa9decdb0acf82a36e59c20d656e19ed (diff) |
Merge branch 'topic/r820t' into patchwork
* topic/r820t: (31 commits)
[media] r820t: Don't divide the IF by two
[media] r820t: disable auto gain/VGA setting
[media] rtl2832: Fix IF calculus
[media] r820t: put it into automatic gain mode
[media] r820t: Fix hp_cor filter mask
[media] r820t: fix PLL calculus
[media] r820t: Don't put it in standby if not initialized yet
[media] r820t: avoid rewrite all regs when not needed
[media] r820t: Allow disabling IMR callibration
[media] r820t: add a commented code for GPIO
[media] r820t: add IMR calibrate code
[media] r820t: proper initialize the PLL register
[media] r820t: use usleep_range()
[media] r820t: fix prefix of the r820t_read() function
[media] r820t: split the function that read cached regs
[media] r820t: better report signal strength
[media] r820t: add support for diplexer
[media] r820t: Show the read data in the bit-reversed order
[media] r820t: use the second table for 7MHz
[media] r820t: Invert bits for read ops
...
-rw-r--r-- | drivers/media/dvb-frontends/rtl2832.c | 85 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/rtl2832.h | 1 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/rtl2832_priv.h | 28 | ||||
-rw-r--r-- | drivers/media/tuners/Kconfig | 7 | ||||
-rw-r--r-- | drivers/media/tuners/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/tuners/r820t.c | 2352 | ||||
-rw-r--r-- | drivers/media/tuners/r820t.h | 58 | ||||
-rw-r--r-- | drivers/media/usb/dvb-usb-v2/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 34 | ||||
-rw-r--r-- | drivers/media/usb/dvb-usb-v2/rtl28xxu.h | 1 |
10 files changed, 2548 insertions, 20 deletions
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 73887690b046..facb84841518 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c | |||
@@ -380,13 +380,41 @@ err: | |||
380 | return ret; | 380 | return ret; |
381 | } | 381 | } |
382 | 382 | ||
383 | static int rtl2832_init(struct dvb_frontend *fe) | 383 | |
384 | static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) | ||
384 | { | 385 | { |
385 | struct rtl2832_priv *priv = fe->demodulator_priv; | 386 | struct rtl2832_priv *priv = fe->demodulator_priv; |
386 | int i, ret, len; | 387 | int ret; |
387 | u8 en_bbin; | ||
388 | u64 pset_iffreq; | 388 | u64 pset_iffreq; |
389 | u8 en_bbin = (if_freq == 0 ? 0x1 : 0x0); | ||
390 | |||
391 | /* | ||
392 | * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) | ||
393 | * / CrystalFreqHz) | ||
394 | */ | ||
395 | |||
396 | pset_iffreq = if_freq % priv->cfg.xtal; | ||
397 | pset_iffreq *= 0x400000; | ||
398 | pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); | ||
399 | pset_iffreq = -pset_iffreq; | ||
400 | pset_iffreq = pset_iffreq & 0x3fffff; | ||
401 | dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d pset_iffreq=%08x\n", | ||
402 | __func__, if_freq, (unsigned)pset_iffreq); | ||
403 | |||
404 | ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); | ||
405 | if (ret) | ||
406 | return ret; | ||
407 | |||
408 | ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); | ||
409 | |||
410 | return (ret); | ||
411 | } | ||
412 | |||
413 | static int rtl2832_init(struct dvb_frontend *fe) | ||
414 | { | ||
415 | struct rtl2832_priv *priv = fe->demodulator_priv; | ||
389 | const struct rtl2832_reg_value *init; | 416 | const struct rtl2832_reg_value *init; |
417 | int i, ret, len; | ||
390 | 418 | ||
391 | /* initialization values for the demodulator registers */ | 419 | /* initialization values for the demodulator registers */ |
392 | struct rtl2832_reg_value rtl2832_initial_regs[] = { | 420 | struct rtl2832_reg_value rtl2832_initial_regs[] = { |
@@ -432,22 +460,10 @@ static int rtl2832_init(struct dvb_frontend *fe) | |||
432 | {DVBT_TR_THD_SET2, 0x6}, | 460 | {DVBT_TR_THD_SET2, 0x6}, |
433 | {DVBT_TRK_KC_I2, 0x5}, | 461 | {DVBT_TRK_KC_I2, 0x5}, |
434 | {DVBT_CR_THD_SET2, 0x1}, | 462 | {DVBT_CR_THD_SET2, 0x1}, |
435 | {DVBT_SPEC_INV, 0x0}, | ||
436 | }; | 463 | }; |
437 | 464 | ||
438 | dev_dbg(&priv->i2c->dev, "%s:\n", __func__); | 465 | dev_dbg(&priv->i2c->dev, "%s:\n", __func__); |
439 | 466 | ||
440 | en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0); | ||
441 | |||
442 | /* | ||
443 | * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) | ||
444 | * / CrystalFreqHz) | ||
445 | */ | ||
446 | pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal; | ||
447 | pset_iffreq *= 0x400000; | ||
448 | pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); | ||
449 | pset_iffreq = pset_iffreq & 0x3fffff; | ||
450 | |||
451 | for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) { | 467 | for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) { |
452 | ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg, | 468 | ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg, |
453 | rtl2832_initial_regs[i].value); | 469 | rtl2832_initial_regs[i].value); |
@@ -472,6 +488,10 @@ static int rtl2832_init(struct dvb_frontend *fe) | |||
472 | len = ARRAY_SIZE(rtl2832_tuner_init_e4000); | 488 | len = ARRAY_SIZE(rtl2832_tuner_init_e4000); |
473 | init = rtl2832_tuner_init_e4000; | 489 | init = rtl2832_tuner_init_e4000; |
474 | break; | 490 | break; |
491 | case RTL2832_TUNER_R820T: | ||
492 | len = ARRAY_SIZE(rtl2832_tuner_init_r820t); | ||
493 | init = rtl2832_tuner_init_r820t; | ||
494 | break; | ||
475 | default: | 495 | default: |
476 | ret = -EINVAL; | 496 | ret = -EINVAL; |
477 | goto err; | 497 | goto err; |
@@ -483,14 +503,26 @@ static int rtl2832_init(struct dvb_frontend *fe) | |||
483 | goto err; | 503 | goto err; |
484 | } | 504 | } |
485 | 505 | ||
486 | /* if frequency settings */ | 506 | if (!fe->ops.tuner_ops.get_if_frequency) { |
487 | ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); | 507 | ret = rtl2832_set_if(fe, priv->cfg.if_dvbt); |
488 | if (ret) | 508 | if (ret) |
489 | goto err; | 509 | goto err; |
510 | } | ||
490 | 511 | ||
491 | ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); | 512 | /* |
492 | if (ret) | 513 | * r820t NIM code does a software reset here at the demod - |
493 | goto err; | 514 | * may not be needed, as there's already a software reset at set_params() |
515 | */ | ||
516 | #if 1 | ||
517 | /* soft reset */ | ||
518 | ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1); | ||
519 | if (ret) | ||
520 | goto err; | ||
521 | |||
522 | ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0); | ||
523 | if (ret) | ||
524 | goto err; | ||
525 | #endif | ||
494 | 526 | ||
495 | priv->sleeping = false; | 527 | priv->sleeping = false; |
496 | 528 | ||
@@ -564,6 +596,19 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) | |||
564 | if (fe->ops.tuner_ops.set_params) | 596 | if (fe->ops.tuner_ops.set_params) |
565 | fe->ops.tuner_ops.set_params(fe); | 597 | fe->ops.tuner_ops.set_params(fe); |
566 | 598 | ||
599 | /* If the frontend has get_if_frequency(), use it */ | ||
600 | if (fe->ops.tuner_ops.get_if_frequency) { | ||
601 | u32 if_freq; | ||
602 | |||
603 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); | ||
604 | if (ret) | ||
605 | goto err; | ||
606 | |||
607 | ret = rtl2832_set_if(fe, if_freq); | ||
608 | if (ret) | ||
609 | goto err; | ||
610 | } | ||
611 | |||
567 | switch (c->bandwidth_hz) { | 612 | switch (c->bandwidth_hz) { |
568 | case 6000000: | 613 | case 6000000: |
569 | i = 0; | 614 | i = 0; |
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index fefba0e9ba30..91b2dcf5a6ea 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h | |||
@@ -52,6 +52,7 @@ struct rtl2832_config { | |||
52 | #define RTL2832_TUNER_FC0012 0x26 | 52 | #define RTL2832_TUNER_FC0012 0x26 |
53 | #define RTL2832_TUNER_E4000 0x27 | 53 | #define RTL2832_TUNER_E4000 0x27 |
54 | #define RTL2832_TUNER_FC0013 0x29 | 54 | #define RTL2832_TUNER_FC0013 0x29 |
55 | #define RTL2832_TUNER_R820T 0x2a | ||
55 | u8 tuner; | 56 | u8 tuner; |
56 | }; | 57 | }; |
57 | 58 | ||
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index 7d97ce9d2193..b5f2b80092ee 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h | |||
@@ -267,6 +267,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_tua9001[] = { | |||
267 | {DVBT_OPT_ADC_IQ, 0x1}, | 267 | {DVBT_OPT_ADC_IQ, 0x1}, |
268 | {DVBT_AD_AVI, 0x0}, | 268 | {DVBT_AD_AVI, 0x0}, |
269 | {DVBT_AD_AVQ, 0x0}, | 269 | {DVBT_AD_AVQ, 0x0}, |
270 | {DVBT_SPEC_INV, 0x0}, | ||
270 | }; | 271 | }; |
271 | 272 | ||
272 | static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = { | 273 | static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = { |
@@ -300,6 +301,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = { | |||
300 | {DVBT_GI_PGA_STATE, 0x0}, | 301 | {DVBT_GI_PGA_STATE, 0x0}, |
301 | {DVBT_EN_AGC_PGA, 0x1}, | 302 | {DVBT_EN_AGC_PGA, 0x1}, |
302 | {DVBT_IF_AGC_MAN, 0x0}, | 303 | {DVBT_IF_AGC_MAN, 0x0}, |
304 | {DVBT_SPEC_INV, 0x0}, | ||
303 | }; | 305 | }; |
304 | 306 | ||
305 | static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = { | 307 | static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = { |
@@ -337,6 +339,32 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = { | |||
337 | {DVBT_REG_MONSEL, 0x1}, | 339 | {DVBT_REG_MONSEL, 0x1}, |
338 | {DVBT_REG_MON, 0x1}, | 340 | {DVBT_REG_MON, 0x1}, |
339 | {DVBT_REG_4MSEL, 0x0}, | 341 | {DVBT_REG_4MSEL, 0x0}, |
342 | {DVBT_SPEC_INV, 0x0}, | ||
343 | }; | ||
344 | |||
345 | static const struct rtl2832_reg_value rtl2832_tuner_init_r820t[] = { | ||
346 | {DVBT_DAGC_TRG_VAL, 0x39}, | ||
347 | {DVBT_AGC_TARG_VAL_0, 0x0}, | ||
348 | {DVBT_AGC_TARG_VAL_8_1, 0x40}, | ||
349 | {DVBT_AAGC_LOOP_GAIN, 0x16}, | ||
350 | {DVBT_LOOP_GAIN2_3_0, 0x8}, | ||
351 | {DVBT_LOOP_GAIN2_4, 0x1}, | ||
352 | {DVBT_LOOP_GAIN3, 0x18}, | ||
353 | {DVBT_VTOP1, 0x35}, | ||
354 | {DVBT_VTOP2, 0x21}, | ||
355 | {DVBT_VTOP3, 0x21}, | ||
356 | {DVBT_KRF1, 0x0}, | ||
357 | {DVBT_KRF2, 0x40}, | ||
358 | {DVBT_KRF3, 0x10}, | ||
359 | {DVBT_KRF4, 0x10}, | ||
360 | {DVBT_IF_AGC_MIN, 0x80}, | ||
361 | {DVBT_IF_AGC_MAX, 0x7f}, | ||
362 | {DVBT_RF_AGC_MIN, 0x80}, | ||
363 | {DVBT_RF_AGC_MAX, 0x7f}, | ||
364 | {DVBT_POLAR_RF_AGC, 0x0}, | ||
365 | {DVBT_POLAR_IF_AGC, 0x0}, | ||
366 | {DVBT_AD7_SETTING, 0xe9f4}, | ||
367 | {DVBT_SPEC_INV, 0x1}, | ||
340 | }; | 368 | }; |
341 | 369 | ||
342 | #endif /* RTL2832_PRIV_H */ | 370 | #endif /* RTL2832_PRIV_H */ |
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index ffabd66dd14d..f6768cad001a 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig | |||
@@ -248,4 +248,11 @@ config MEDIA_TUNER_IT913X | |||
248 | default m if !MEDIA_SUBDRV_AUTOSELECT | 248 | default m if !MEDIA_SUBDRV_AUTOSELECT |
249 | help | 249 | help |
250 | ITE Tech IT913x silicon tuner driver. | 250 | ITE Tech IT913x silicon tuner driver. |
251 | |||
252 | config MEDIA_TUNER_R820T | ||
253 | tristate "Rafael Micro R820T silicon tuner" | ||
254 | depends on MEDIA_SUPPORT && I2C | ||
255 | default m if !MEDIA_SUBDRV_AUTOSELECT | ||
256 | help | ||
257 | Rafael Micro R820T silicon tuner driver. | ||
251 | endmenu | 258 | endmenu |
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 2ebe4b725b51..308f108eadba 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile | |||
@@ -35,6 +35,7 @@ obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o | |||
35 | obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o | 35 | obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o |
36 | obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o | 36 | obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o |
37 | obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o | 37 | obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o |
38 | obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o | ||
38 | 39 | ||
39 | ccflags-y += -I$(srctree)/drivers/media/dvb-core | 40 | ccflags-y += -I$(srctree)/drivers/media/dvb-core |
40 | ccflags-y += -I$(srctree)/drivers/media/dvb-frontends | 41 | ccflags-y += -I$(srctree)/drivers/media/dvb-frontends |
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c new file mode 100644 index 000000000000..905a10615e52 --- /dev/null +++ b/drivers/media/tuners/r820t.c | |||
@@ -0,0 +1,2352 @@ | |||
1 | /* | ||
2 | * Rafael Micro R820T driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Mauro Carvalho Chehab <mchehab@redhat.com> | ||
5 | * | ||
6 | * This driver was written from scratch, based on an existing driver | ||
7 | * that it is part of rtl-sdr git tree, released under GPLv2: | ||
8 | * https://groups.google.com/forum/#!topic/ultra-cheap-sdr/Y3rBEOFtHug | ||
9 | * https://github.com/n1gp/gr-baz | ||
10 | * | ||
11 | * From what I understood from the threads, the original driver was converted | ||
12 | * to userspace from a Realtek tree. I couldn't find the original tree. | ||
13 | * However, the original driver look awkward on my eyes. So, I decided to | ||
14 | * write a new version from it from the scratch, while trying to reproduce | ||
15 | * everything found there. | ||
16 | * | ||
17 | * TODO: | ||
18 | * After locking, the original driver seems to have some routines to | ||
19 | * improve reception. This was not implemented here yet. | ||
20 | * | ||
21 | * RF Gain set/get is not implemented. | ||
22 | * | ||
23 | * This program is free software; you can redistribute it and/or modify | ||
24 | * it under the terms of the GNU General Public License as published by | ||
25 | * the Free Software Foundation; either version 2 of the License, or | ||
26 | * (at your option) any later version. | ||
27 | * | ||
28 | * This program is distributed in the hope that it will be useful, | ||
29 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
30 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
31 | * GNU General Public License for more details. | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | #include <linux/videodev2.h> | ||
36 | #include <linux/mutex.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/bitrev.h> | ||
39 | |||
40 | #include "tuner-i2c.h" | ||
41 | #include "r820t.h" | ||
42 | |||
43 | /* | ||
44 | * FIXME: I think that there are only 32 registers, but better safe than | ||
45 | * sorry. After finishing the driver, we may review it. | ||
46 | */ | ||
47 | #define REG_SHADOW_START 5 | ||
48 | #define NUM_REGS 27 | ||
49 | #define NUM_IMR 5 | ||
50 | #define IMR_TRIAL 9 | ||
51 | |||
52 | #define VER_NUM 49 | ||
53 | |||
54 | static int debug; | ||
55 | module_param(debug, int, 0644); | ||
56 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
57 | |||
58 | static int no_imr_cal; | ||
59 | module_param(no_imr_cal, int, 0444); | ||
60 | MODULE_PARM_DESC(no_imr_cal, "Disable IMR calibration at module init"); | ||
61 | |||
62 | |||
63 | /* | ||
64 | * enums and structures | ||
65 | */ | ||
66 | |||
67 | enum xtal_cap_value { | ||
68 | XTAL_LOW_CAP_30P = 0, | ||
69 | XTAL_LOW_CAP_20P, | ||
70 | XTAL_LOW_CAP_10P, | ||
71 | XTAL_LOW_CAP_0P, | ||
72 | XTAL_HIGH_CAP_0P | ||
73 | }; | ||
74 | |||
75 | struct r820t_sect_type { | ||
76 | u8 phase_y; | ||
77 | u8 gain_x; | ||
78 | u16 value; | ||
79 | }; | ||
80 | |||
81 | struct r820t_priv { | ||
82 | struct list_head hybrid_tuner_instance_list; | ||
83 | const struct r820t_config *cfg; | ||
84 | struct tuner_i2c_props i2c_props; | ||
85 | struct mutex lock; | ||
86 | |||
87 | u8 regs[NUM_REGS]; | ||
88 | u8 buf[NUM_REGS + 1]; | ||
89 | enum xtal_cap_value xtal_cap_sel; | ||
90 | u16 pll; /* kHz */ | ||
91 | u32 int_freq; | ||
92 | u8 fil_cal_code; | ||
93 | bool imr_done; | ||
94 | bool has_lock; | ||
95 | bool init_done; | ||
96 | struct r820t_sect_type imr_data[NUM_IMR]; | ||
97 | |||
98 | /* Store current mode */ | ||
99 | u32 delsys; | ||
100 | enum v4l2_tuner_type type; | ||
101 | v4l2_std_id std; | ||
102 | u32 bw; /* in MHz */ | ||
103 | }; | ||
104 | |||
105 | struct r820t_freq_range { | ||
106 | u32 freq; | ||
107 | u8 open_d; | ||
108 | u8 rf_mux_ploy; | ||
109 | u8 tf_c; | ||
110 | u8 xtal_cap20p; | ||
111 | u8 xtal_cap10p; | ||
112 | u8 xtal_cap0p; | ||
113 | u8 imr_mem; /* Not used, currently */ | ||
114 | }; | ||
115 | |||
116 | #define VCO_POWER_REF 0x02 | ||
117 | #define DIP_FREQ 32000000 | ||
118 | |||
119 | /* | ||
120 | * Static constants | ||
121 | */ | ||
122 | |||
123 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
124 | static DEFINE_MUTEX(r820t_list_mutex); | ||
125 | |||
126 | /* Those initial values start from REG_SHADOW_START */ | ||
127 | static const u8 r820t_init_array[NUM_REGS] = { | ||
128 | 0x83, 0x32, 0x75, /* 05 to 07 */ | ||
129 | 0xc0, 0x40, 0xd6, 0x6c, /* 08 to 0b */ | ||
130 | 0xf5, 0x63, 0x75, 0x68, /* 0c to 0f */ | ||
131 | 0x6c, 0x83, 0x80, 0x00, /* 10 to 13 */ | ||
132 | 0x0f, 0x00, 0xc0, 0x30, /* 14 to 17 */ | ||
133 | 0x48, 0xcc, 0x60, 0x00, /* 18 to 1b */ | ||
134 | 0x54, 0xae, 0x4a, 0xc0 /* 1c to 1f */ | ||
135 | }; | ||
136 | |||
137 | /* Tuner frequency ranges */ | ||
138 | static const struct r820t_freq_range freq_ranges[] = { | ||
139 | { | ||
140 | .freq = 0, | ||
141 | .open_d = 0x08, /* low */ | ||
142 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
143 | .tf_c = 0xdf, /* R27[7:0] band2,band0 */ | ||
144 | .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ | ||
145 | .xtal_cap10p = 0x01, | ||
146 | .xtal_cap0p = 0x00, | ||
147 | .imr_mem = 0, | ||
148 | }, { | ||
149 | .freq = 50, /* Start freq, in MHz */ | ||
150 | .open_d = 0x08, /* low */ | ||
151 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
152 | .tf_c = 0xbe, /* R27[7:0] band4,band1 */ | ||
153 | .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ | ||
154 | .xtal_cap10p = 0x01, | ||
155 | .xtal_cap0p = 0x00, | ||
156 | .imr_mem = 0, | ||
157 | }, { | ||
158 | .freq = 55, /* Start freq, in MHz */ | ||
159 | .open_d = 0x08, /* low */ | ||
160 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
161 | .tf_c = 0x8b, /* R27[7:0] band7,band4 */ | ||
162 | .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ | ||
163 | .xtal_cap10p = 0x01, | ||
164 | .xtal_cap0p = 0x00, | ||
165 | .imr_mem = 0, | ||
166 | }, { | ||
167 | .freq = 60, /* Start freq, in MHz */ | ||
168 | .open_d = 0x08, /* low */ | ||
169 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
170 | .tf_c = 0x7b, /* R27[7:0] band8,band4 */ | ||
171 | .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ | ||
172 | .xtal_cap10p = 0x01, | ||
173 | .xtal_cap0p = 0x00, | ||
174 | .imr_mem = 0, | ||
175 | }, { | ||
176 | .freq = 65, /* Start freq, in MHz */ | ||
177 | .open_d = 0x08, /* low */ | ||
178 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
179 | .tf_c = 0x69, /* R27[7:0] band9,band6 */ | ||
180 | .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ | ||
181 | .xtal_cap10p = 0x01, | ||
182 | .xtal_cap0p = 0x00, | ||
183 | .imr_mem = 0, | ||
184 | }, { | ||
185 | .freq = 70, /* Start freq, in MHz */ | ||
186 | .open_d = 0x08, /* low */ | ||
187 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
188 | .tf_c = 0x58, /* R27[7:0] band10,band7 */ | ||
189 | .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ | ||
190 | .xtal_cap10p = 0x01, | ||
191 | .xtal_cap0p = 0x00, | ||
192 | .imr_mem = 0, | ||
193 | }, { | ||
194 | .freq = 75, /* Start freq, in MHz */ | ||
195 | .open_d = 0x00, /* high */ | ||
196 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
197 | .tf_c = 0x44, /* R27[7:0] band11,band11 */ | ||
198 | .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ | ||
199 | .xtal_cap10p = 0x01, | ||
200 | .xtal_cap0p = 0x00, | ||
201 | .imr_mem = 0, | ||
202 | }, { | ||
203 | .freq = 80, /* Start freq, in MHz */ | ||
204 | .open_d = 0x00, /* high */ | ||
205 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
206 | .tf_c = 0x44, /* R27[7:0] band11,band11 */ | ||
207 | .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ | ||
208 | .xtal_cap10p = 0x01, | ||
209 | .xtal_cap0p = 0x00, | ||
210 | .imr_mem = 0, | ||
211 | }, { | ||
212 | .freq = 90, /* Start freq, in MHz */ | ||
213 | .open_d = 0x00, /* high */ | ||
214 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
215 | .tf_c = 0x34, /* R27[7:0] band12,band11 */ | ||
216 | .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ | ||
217 | .xtal_cap10p = 0x01, | ||
218 | .xtal_cap0p = 0x00, | ||
219 | .imr_mem = 0, | ||
220 | }, { | ||
221 | .freq = 100, /* Start freq, in MHz */ | ||
222 | .open_d = 0x00, /* high */ | ||
223 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
224 | .tf_c = 0x34, /* R27[7:0] band12,band11 */ | ||
225 | .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ | ||
226 | .xtal_cap10p = 0x01, | ||
227 | .xtal_cap0p = 0x00, | ||
228 | .imr_mem = 0, | ||
229 | }, { | ||
230 | .freq = 110, /* Start freq, in MHz */ | ||
231 | .open_d = 0x00, /* high */ | ||
232 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
233 | .tf_c = 0x24, /* R27[7:0] band13,band11 */ | ||
234 | .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ | ||
235 | .xtal_cap10p = 0x01, | ||
236 | .xtal_cap0p = 0x00, | ||
237 | .imr_mem = 1, | ||
238 | }, { | ||
239 | .freq = 120, /* Start freq, in MHz */ | ||
240 | .open_d = 0x00, /* high */ | ||
241 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
242 | .tf_c = 0x24, /* R27[7:0] band13,band11 */ | ||
243 | .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ | ||
244 | .xtal_cap10p = 0x01, | ||
245 | .xtal_cap0p = 0x00, | ||
246 | .imr_mem = 1, | ||
247 | }, { | ||
248 | .freq = 140, /* Start freq, in MHz */ | ||
249 | .open_d = 0x00, /* high */ | ||
250 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
251 | .tf_c = 0x14, /* R27[7:0] band14,band11 */ | ||
252 | .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ | ||
253 | .xtal_cap10p = 0x01, | ||
254 | .xtal_cap0p = 0x00, | ||
255 | .imr_mem = 1, | ||
256 | }, { | ||
257 | .freq = 180, /* Start freq, in MHz */ | ||
258 | .open_d = 0x00, /* high */ | ||
259 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
260 | .tf_c = 0x13, /* R27[7:0] band14,band12 */ | ||
261 | .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ | ||
262 | .xtal_cap10p = 0x00, | ||
263 | .xtal_cap0p = 0x00, | ||
264 | .imr_mem = 1, | ||
265 | }, { | ||
266 | .freq = 220, /* Start freq, in MHz */ | ||
267 | .open_d = 0x00, /* high */ | ||
268 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
269 | .tf_c = 0x13, /* R27[7:0] band14,band12 */ | ||
270 | .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ | ||
271 | .xtal_cap10p = 0x00, | ||
272 | .xtal_cap0p = 0x00, | ||
273 | .imr_mem = 2, | ||
274 | }, { | ||
275 | .freq = 250, /* Start freq, in MHz */ | ||
276 | .open_d = 0x00, /* high */ | ||
277 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
278 | .tf_c = 0x11, /* R27[7:0] highest,highest */ | ||
279 | .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ | ||
280 | .xtal_cap10p = 0x00, | ||
281 | .xtal_cap0p = 0x00, | ||
282 | .imr_mem = 2, | ||
283 | }, { | ||
284 | .freq = 280, /* Start freq, in MHz */ | ||
285 | .open_d = 0x00, /* high */ | ||
286 | .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ | ||
287 | .tf_c = 0x00, /* R27[7:0] highest,highest */ | ||
288 | .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ | ||
289 | .xtal_cap10p = 0x00, | ||
290 | .xtal_cap0p = 0x00, | ||
291 | .imr_mem = 2, | ||
292 | }, { | ||
293 | .freq = 310, /* Start freq, in MHz */ | ||
294 | .open_d = 0x00, /* high */ | ||
295 | .rf_mux_ploy = 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */ | ||
296 | .tf_c = 0x00, /* R27[7:0] highest,highest */ | ||
297 | .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ | ||
298 | .xtal_cap10p = 0x00, | ||
299 | .xtal_cap0p = 0x00, | ||
300 | .imr_mem = 2, | ||
301 | }, { | ||
302 | .freq = 450, /* Start freq, in MHz */ | ||
303 | .open_d = 0x00, /* high */ | ||
304 | .rf_mux_ploy = 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */ | ||
305 | .tf_c = 0x00, /* R27[7:0] highest,highest */ | ||
306 | .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ | ||
307 | .xtal_cap10p = 0x00, | ||
308 | .xtal_cap0p = 0x00, | ||
309 | .imr_mem = 3, | ||
310 | }, { | ||
311 | .freq = 588, /* Start freq, in MHz */ | ||
312 | .open_d = 0x00, /* high */ | ||
313 | .rf_mux_ploy = 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */ | ||
314 | .tf_c = 0x00, /* R27[7:0] highest,highest */ | ||
315 | .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ | ||
316 | .xtal_cap10p = 0x00, | ||
317 | .xtal_cap0p = 0x00, | ||
318 | .imr_mem = 3, | ||
319 | }, { | ||
320 | .freq = 650, /* Start freq, in MHz */ | ||
321 | .open_d = 0x00, /* high */ | ||
322 | .rf_mux_ploy = 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */ | ||
323 | .tf_c = 0x00, /* R27[7:0] highest,highest */ | ||
324 | .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ | ||
325 | .xtal_cap10p = 0x00, | ||
326 | .xtal_cap0p = 0x00, | ||
327 | .imr_mem = 4, | ||
328 | } | ||
329 | }; | ||
330 | |||
331 | static int r820t_xtal_capacitor[][2] = { | ||
332 | { 0x0b, XTAL_LOW_CAP_30P }, | ||
333 | { 0x02, XTAL_LOW_CAP_20P }, | ||
334 | { 0x01, XTAL_LOW_CAP_10P }, | ||
335 | { 0x00, XTAL_LOW_CAP_0P }, | ||
336 | { 0x10, XTAL_HIGH_CAP_0P }, | ||
337 | }; | ||
338 | |||
339 | /* | ||
340 | * measured with a Racal 6103E GSM test set at 928 MHz with -60 dBm | ||
341 | * input power, for raw results see: | ||
342 | * http://steve-m.de/projects/rtl-sdr/gain_measurement/r820t/ | ||
343 | */ | ||
344 | |||
345 | static const int r820t_lna_gain_steps[] = { | ||
346 | 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13 | ||
347 | }; | ||
348 | |||
349 | static const int r820t_mixer_gain_steps[] = { | ||
350 | 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8 | ||
351 | }; | ||
352 | |||
353 | /* | ||
354 | * I2C read/write code and shadow registers logic | ||
355 | */ | ||
356 | static void shadow_store(struct r820t_priv *priv, u8 reg, const u8 *val, | ||
357 | int len) | ||
358 | { | ||
359 | int r = reg - REG_SHADOW_START; | ||
360 | |||
361 | if (r < 0) { | ||
362 | len += r; | ||
363 | r = 0; | ||
364 | } | ||
365 | if (len <= 0) | ||
366 | return; | ||
367 | if (len > NUM_REGS) | ||
368 | len = NUM_REGS; | ||
369 | |||
370 | tuner_dbg("%s: prev reg=%02x len=%d: %*ph\n", | ||
371 | __func__, r + REG_SHADOW_START, len, len, val); | ||
372 | |||
373 | memcpy(&priv->regs[r], val, len); | ||
374 | } | ||
375 | |||
376 | static int r820t_write(struct r820t_priv *priv, u8 reg, const u8 *val, | ||
377 | int len) | ||
378 | { | ||
379 | int rc, size, pos = 0; | ||
380 | |||
381 | /* Store the shadow registers */ | ||
382 | shadow_store(priv, reg, val, len); | ||
383 | |||
384 | do { | ||
385 | if (len > priv->cfg->max_i2c_msg_len - 1) | ||
386 | size = priv->cfg->max_i2c_msg_len - 1; | ||
387 | else | ||
388 | size = len; | ||
389 | |||
390 | /* Fill I2C buffer */ | ||
391 | priv->buf[0] = reg; | ||
392 | memcpy(&priv->buf[1], &val[pos], size); | ||
393 | |||
394 | rc = tuner_i2c_xfer_send(&priv->i2c_props, priv->buf, size + 1); | ||
395 | if (rc != size + 1) { | ||
396 | tuner_info("%s: i2c wr failed=%d reg=%02x len=%d: %*ph\n", | ||
397 | __func__, rc, reg, size, size, &priv->buf[1]); | ||
398 | if (rc < 0) | ||
399 | return rc; | ||
400 | return -EREMOTEIO; | ||
401 | } | ||
402 | tuner_dbg("%s: i2c wr reg=%02x len=%d: %*ph\n", | ||
403 | __func__, reg, size, size, &priv->buf[1]); | ||
404 | |||
405 | reg += size; | ||
406 | len -= size; | ||
407 | pos += size; | ||
408 | } while (len > 0); | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val) | ||
414 | { | ||
415 | return r820t_write(priv, reg, &val, 1); | ||
416 | } | ||
417 | |||
418 | static int r820t_read_cache_reg(struct r820t_priv *priv, int reg) | ||
419 | { | ||
420 | reg -= REG_SHADOW_START; | ||
421 | |||
422 | if (reg >= 0 && reg < NUM_REGS) | ||
423 | return priv->regs[reg]; | ||
424 | else | ||
425 | return -EINVAL; | ||
426 | } | ||
427 | |||
428 | static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val, | ||
429 | u8 bit_mask) | ||
430 | { | ||
431 | int rc = r820t_read_cache_reg(priv, reg); | ||
432 | |||
433 | if (rc < 0) | ||
434 | return rc; | ||
435 | |||
436 | val = (rc & ~bit_mask) | (val & bit_mask); | ||
437 | |||
438 | return r820t_write(priv, reg, &val, 1); | ||
439 | } | ||
440 | |||
441 | static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len) | ||
442 | { | ||
443 | int rc, i; | ||
444 | u8 *p = &priv->buf[1]; | ||
445 | |||
446 | priv->buf[0] = reg; | ||
447 | |||
448 | rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, priv->buf, 1, p, len); | ||
449 | if (rc != len) { | ||
450 | tuner_info("%s: i2c rd failed=%d reg=%02x len=%d: %*ph\n", | ||
451 | __func__, rc, reg, len, len, p); | ||
452 | if (rc < 0) | ||
453 | return rc; | ||
454 | return -EREMOTEIO; | ||
455 | } | ||
456 | |||
457 | /* Copy data to the output buffer */ | ||
458 | for (i = 0; i < len; i++) | ||
459 | val[i] = bitrev8(p[i]); | ||
460 | |||
461 | tuner_dbg("%s: i2c rd reg=%02x len=%d: %*ph\n", | ||
462 | __func__, reg, len, len, val); | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * r820t tuning logic | ||
469 | */ | ||
470 | |||
471 | static int r820t_set_mux(struct r820t_priv *priv, u32 freq) | ||
472 | { | ||
473 | const struct r820t_freq_range *range; | ||
474 | int i, rc; | ||
475 | u8 val, reg08, reg09; | ||
476 | |||
477 | /* Get the proper frequency range */ | ||
478 | freq = freq / 1000000; | ||
479 | for (i = 0; i < ARRAY_SIZE(freq_ranges) - 1; i++) { | ||
480 | if (freq < freq_ranges[i + 1].freq) | ||
481 | break; | ||
482 | } | ||
483 | range = &freq_ranges[i]; | ||
484 | |||
485 | tuner_dbg("set r820t range#%d for frequency %d MHz\n", i, freq); | ||
486 | |||
487 | /* Open Drain */ | ||
488 | rc = r820t_write_reg_mask(priv, 0x17, range->open_d, 0x08); | ||
489 | if (rc < 0) | ||
490 | return rc; | ||
491 | |||
492 | /* RF_MUX,Polymux */ | ||
493 | rc = r820t_write_reg_mask(priv, 0x1a, range->rf_mux_ploy, 0xc3); | ||
494 | if (rc < 0) | ||
495 | return rc; | ||
496 | |||
497 | /* TF BAND */ | ||
498 | rc = r820t_write_reg(priv, 0x1b, range->tf_c); | ||
499 | if (rc < 0) | ||
500 | return rc; | ||
501 | |||
502 | /* XTAL CAP & Drive */ | ||
503 | switch (priv->xtal_cap_sel) { | ||
504 | case XTAL_LOW_CAP_30P: | ||
505 | case XTAL_LOW_CAP_20P: | ||
506 | val = range->xtal_cap20p | 0x08; | ||
507 | break; | ||
508 | case XTAL_LOW_CAP_10P: | ||
509 | val = range->xtal_cap10p | 0x08; | ||
510 | break; | ||
511 | case XTAL_HIGH_CAP_0P: | ||
512 | val = range->xtal_cap0p | 0x00; | ||
513 | break; | ||
514 | default: | ||
515 | case XTAL_LOW_CAP_0P: | ||
516 | val = range->xtal_cap0p | 0x08; | ||
517 | break; | ||
518 | } | ||
519 | rc = r820t_write_reg_mask(priv, 0x10, val, 0x0b); | ||
520 | if (rc < 0) | ||
521 | return rc; | ||
522 | |||
523 | if (priv->imr_done) { | ||
524 | reg08 = priv->imr_data[range->imr_mem].gain_x; | ||
525 | reg09 = priv->imr_data[range->imr_mem].phase_y; | ||
526 | } else { | ||
527 | reg08 = 0; | ||
528 | reg09 = 0; | ||
529 | } | ||
530 | rc = r820t_write_reg_mask(priv, 0x08, reg08, 0x3f); | ||
531 | if (rc < 0) | ||
532 | return rc; | ||
533 | |||
534 | rc = r820t_write_reg_mask(priv, 0x09, reg09, 0x3f); | ||
535 | |||
536 | return rc; | ||
537 | } | ||
538 | |||
539 | static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type, | ||
540 | u32 freq) | ||
541 | { | ||
542 | u32 vco_freq; | ||
543 | int rc, i; | ||
544 | unsigned sleep_time = 10000; | ||
545 | u32 vco_fra; /* VCO contribution by SDM (kHz) */ | ||
546 | u32 vco_min = 1770000; | ||
547 | u32 vco_max = vco_min * 2; | ||
548 | u32 pll_ref; | ||
549 | u16 n_sdm = 2; | ||
550 | u16 sdm = 0; | ||
551 | u8 mix_div = 2; | ||
552 | u8 div_buf = 0; | ||
553 | u8 div_num = 0; | ||
554 | u8 refdiv2 = 0; | ||
555 | u8 ni, si, nint, vco_fine_tune, val; | ||
556 | u8 data[5]; | ||
557 | |||
558 | /* Frequency in kHz */ | ||
559 | freq = freq / 1000; | ||
560 | pll_ref = priv->cfg->xtal / 1000; | ||
561 | |||
562 | #if 0 | ||
563 | /* Doesn't exist on rtl-sdk, and on field tests, caused troubles */ | ||
564 | if ((priv->cfg->rafael_chip == CHIP_R620D) || | ||
565 | (priv->cfg->rafael_chip == CHIP_R828D) || | ||
566 | (priv->cfg->rafael_chip == CHIP_R828)) { | ||
567 | /* ref set refdiv2, reffreq = Xtal/2 on ATV application */ | ||
568 | if (type != V4L2_TUNER_DIGITAL_TV) { | ||
569 | pll_ref /= 2; | ||
570 | refdiv2 = 0x10; | ||
571 | sleep_time = 20000; | ||
572 | } | ||
573 | } else { | ||
574 | if (priv->cfg->xtal > 24000000) { | ||
575 | pll_ref /= 2; | ||
576 | refdiv2 = 0x10; | ||
577 | } | ||
578 | } | ||
579 | #endif | ||
580 | |||
581 | rc = r820t_write_reg_mask(priv, 0x10, refdiv2, 0x10); | ||
582 | if (rc < 0) | ||
583 | return rc; | ||
584 | |||
585 | /* set pll autotune = 128kHz */ | ||
586 | rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x0c); | ||
587 | if (rc < 0) | ||
588 | return rc; | ||
589 | |||
590 | /* set VCO current = 100 */ | ||
591 | rc = r820t_write_reg_mask(priv, 0x12, 0x80, 0xe0); | ||
592 | if (rc < 0) | ||
593 | return rc; | ||
594 | |||
595 | /* Calculate divider */ | ||
596 | while (mix_div <= 64) { | ||
597 | if (((freq * mix_div) >= vco_min) && | ||
598 | ((freq * mix_div) < vco_max)) { | ||
599 | div_buf = mix_div; | ||
600 | while (div_buf > 2) { | ||
601 | div_buf = div_buf >> 1; | ||
602 | div_num++; | ||
603 | } | ||
604 | break; | ||
605 | } | ||
606 | mix_div = mix_div << 1; | ||
607 | } | ||
608 | |||
609 | rc = r820t_read(priv, 0x00, data, sizeof(data)); | ||
610 | if (rc < 0) | ||
611 | return rc; | ||
612 | |||
613 | vco_fine_tune = (data[4] & 0x30) >> 4; | ||
614 | |||
615 | if (vco_fine_tune > VCO_POWER_REF) | ||
616 | div_num = div_num - 1; | ||
617 | else if (vco_fine_tune < VCO_POWER_REF) | ||
618 | div_num = div_num + 1; | ||
619 | |||
620 | rc = r820t_write_reg_mask(priv, 0x10, div_num << 5, 0xe0); | ||
621 | if (rc < 0) | ||
622 | return rc; | ||
623 | |||
624 | vco_freq = freq * mix_div; | ||
625 | nint = vco_freq / (2 * pll_ref); | ||
626 | vco_fra = vco_freq - 2 * pll_ref * nint; | ||
627 | |||
628 | /* boundary spur prevention */ | ||
629 | if (vco_fra < pll_ref / 64) { | ||
630 | vco_fra = 0; | ||
631 | } else if (vco_fra > pll_ref * 127 / 64) { | ||
632 | vco_fra = 0; | ||
633 | nint++; | ||
634 | } else if ((vco_fra > pll_ref * 127 / 128) && (vco_fra < pll_ref)) { | ||
635 | vco_fra = pll_ref * 127 / 128; | ||
636 | } else if ((vco_fra > pll_ref) && (vco_fra < pll_ref * 129 / 128)) { | ||
637 | vco_fra = pll_ref * 129 / 128; | ||
638 | } | ||
639 | |||
640 | if (nint > 63) { | ||
641 | tuner_info("No valid PLL values for %u kHz!\n", freq); | ||
642 | return -EINVAL; | ||
643 | } | ||
644 | |||
645 | ni = (nint - 13) / 4; | ||
646 | si = nint - 4 * ni - 13; | ||
647 | |||
648 | rc = r820t_write_reg(priv, 0x14, ni + (si << 6)); | ||
649 | if (rc < 0) | ||
650 | return rc; | ||
651 | |||
652 | /* pw_sdm */ | ||
653 | if (!vco_fra) | ||
654 | val = 0x08; | ||
655 | else | ||
656 | val = 0x00; | ||
657 | |||
658 | rc = r820t_write_reg_mask(priv, 0x12, val, 0x08); | ||
659 | if (rc < 0) | ||
660 | return rc; | ||
661 | |||
662 | /* sdm calculator */ | ||
663 | while (vco_fra > 1) { | ||
664 | if (vco_fra > (2 * pll_ref / n_sdm)) { | ||
665 | sdm = sdm + 32768 / (n_sdm / 2); | ||
666 | vco_fra = vco_fra - 2 * pll_ref / n_sdm; | ||
667 | if (n_sdm >= 0x8000) | ||
668 | break; | ||
669 | } | ||
670 | n_sdm = n_sdm << 1; | ||
671 | } | ||
672 | |||
673 | tuner_dbg("freq %d kHz, pll ref %d%s, sdm=0x%04x\n", | ||
674 | freq, pll_ref, refdiv2 ? " / 2" : "", sdm); | ||
675 | |||
676 | rc = r820t_write_reg(priv, 0x16, sdm >> 8); | ||
677 | if (rc < 0) | ||
678 | return rc; | ||
679 | rc = r820t_write_reg(priv, 0x15, sdm & 0xff); | ||
680 | if (rc < 0) | ||
681 | return rc; | ||
682 | |||
683 | for (i = 0; i < 2; i++) { | ||
684 | usleep_range(sleep_time, sleep_time + 1000); | ||
685 | |||
686 | /* Check if PLL has locked */ | ||
687 | rc = r820t_read(priv, 0x00, data, 3); | ||
688 | if (rc < 0) | ||
689 | return rc; | ||
690 | if (data[2] & 0x40) | ||
691 | break; | ||
692 | |||
693 | if (!i) { | ||
694 | /* Didn't lock. Increase VCO current */ | ||
695 | rc = r820t_write_reg_mask(priv, 0x12, 0x60, 0xe0); | ||
696 | if (rc < 0) | ||
697 | return rc; | ||
698 | } | ||
699 | } | ||
700 | |||
701 | if (!(data[2] & 0x40)) { | ||
702 | priv->has_lock = false; | ||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | priv->has_lock = true; | ||
707 | tuner_dbg("tuner has lock at frequency %d kHz\n", freq); | ||
708 | |||
709 | /* set pll autotune = 8kHz */ | ||
710 | rc = r820t_write_reg_mask(priv, 0x1a, 0x08, 0x08); | ||
711 | |||
712 | return rc; | ||
713 | } | ||
714 | |||
715 | static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq, | ||
716 | enum v4l2_tuner_type type, | ||
717 | v4l2_std_id std, | ||
718 | u32 delsys) | ||
719 | { | ||
720 | int rc; | ||
721 | u8 mixer_top, lna_top, cp_cur, div_buf_cur, lna_vth_l, mixer_vth_l; | ||
722 | u8 air_cable1_in, cable2_in, pre_dect, lna_discharge, filter_cur; | ||
723 | |||
724 | tuner_dbg("adjusting tuner parameters for the standard\n"); | ||
725 | |||
726 | switch (delsys) { | ||
727 | case SYS_DVBT: | ||
728 | if ((freq == 506000000) || (freq == 666000000) || | ||
729 | (freq == 818000000)) { | ||
730 | mixer_top = 0x14; /* mixer top:14 , top-1, low-discharge */ | ||
731 | lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ | ||
732 | cp_cur = 0x28; /* 101, 0.2 */ | ||
733 | div_buf_cur = 0x20; /* 10, 200u */ | ||
734 | } else { | ||
735 | mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ | ||
736 | lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ | ||
737 | cp_cur = 0x38; /* 111, auto */ | ||
738 | div_buf_cur = 0x30; /* 11, 150u */ | ||
739 | } | ||
740 | lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ | ||
741 | mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ | ||
742 | air_cable1_in = 0x00; | ||
743 | cable2_in = 0x00; | ||
744 | pre_dect = 0x40; | ||
745 | lna_discharge = 14; | ||
746 | filter_cur = 0x40; /* 10, low */ | ||
747 | break; | ||
748 | case SYS_DVBT2: | ||
749 | mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ | ||
750 | lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ | ||
751 | lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ | ||
752 | mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ | ||
753 | air_cable1_in = 0x00; | ||
754 | cable2_in = 0x00; | ||
755 | pre_dect = 0x40; | ||
756 | lna_discharge = 14; | ||
757 | cp_cur = 0x38; /* 111, auto */ | ||
758 | div_buf_cur = 0x30; /* 11, 150u */ | ||
759 | filter_cur = 0x40; /* 10, low */ | ||
760 | break; | ||
761 | case SYS_ISDBT: | ||
762 | mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ | ||
763 | lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ | ||
764 | lna_vth_l = 0x75; /* lna vth 1.04 , vtl 0.84 */ | ||
765 | mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ | ||
766 | air_cable1_in = 0x00; | ||
767 | cable2_in = 0x00; | ||
768 | pre_dect = 0x40; | ||
769 | lna_discharge = 14; | ||
770 | cp_cur = 0x38; /* 111, auto */ | ||
771 | div_buf_cur = 0x30; /* 11, 150u */ | ||
772 | filter_cur = 0x40; /* 10, low */ | ||
773 | break; | ||
774 | default: /* DVB-T 8M */ | ||
775 | mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ | ||
776 | lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ | ||
777 | lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ | ||
778 | mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ | ||
779 | air_cable1_in = 0x00; | ||
780 | cable2_in = 0x00; | ||
781 | pre_dect = 0x40; | ||
782 | lna_discharge = 14; | ||
783 | cp_cur = 0x38; /* 111, auto */ | ||
784 | div_buf_cur = 0x30; /* 11, 150u */ | ||
785 | filter_cur = 0x40; /* 10, low */ | ||
786 | break; | ||
787 | } | ||
788 | |||
789 | if (priv->cfg->use_diplexer && | ||
790 | ((priv->cfg->rafael_chip == CHIP_R820T) || | ||
791 | (priv->cfg->rafael_chip == CHIP_R828S) || | ||
792 | (priv->cfg->rafael_chip == CHIP_R820C))) { | ||
793 | if (freq > DIP_FREQ) | ||
794 | air_cable1_in = 0x00; | ||
795 | else | ||
796 | air_cable1_in = 0x60; | ||
797 | cable2_in = 0x00; | ||
798 | } | ||
799 | |||
800 | rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0xc7); | ||
801 | if (rc < 0) | ||
802 | return rc; | ||
803 | rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0xf8); | ||
804 | if (rc < 0) | ||
805 | return rc; | ||
806 | rc = r820t_write_reg(priv, 0x0d, lna_vth_l); | ||
807 | if (rc < 0) | ||
808 | return rc; | ||
809 | rc = r820t_write_reg(priv, 0x0e, mixer_vth_l); | ||
810 | if (rc < 0) | ||
811 | return rc; | ||
812 | |||
813 | /* Air-IN only for Astrometa */ | ||
814 | rc = r820t_write_reg_mask(priv, 0x05, air_cable1_in, 0x60); | ||
815 | if (rc < 0) | ||
816 | return rc; | ||
817 | rc = r820t_write_reg_mask(priv, 0x06, cable2_in, 0x08); | ||
818 | if (rc < 0) | ||
819 | return rc; | ||
820 | |||
821 | rc = r820t_write_reg_mask(priv, 0x11, cp_cur, 0x38); | ||
822 | if (rc < 0) | ||
823 | return rc; | ||
824 | rc = r820t_write_reg_mask(priv, 0x17, div_buf_cur, 0x30); | ||
825 | if (rc < 0) | ||
826 | return rc; | ||
827 | rc = r820t_write_reg_mask(priv, 0x0a, filter_cur, 0x60); | ||
828 | if (rc < 0) | ||
829 | return rc; | ||
830 | /* | ||
831 | * Original driver initializes regs 0x05 and 0x06 with the | ||
832 | * same value again on this point. Probably, it is just an | ||
833 | * error there | ||
834 | */ | ||
835 | |||
836 | /* | ||
837 | * Set LNA | ||
838 | */ | ||
839 | |||
840 | tuner_dbg("adjusting LNA parameters\n"); | ||
841 | if (type != V4L2_TUNER_ANALOG_TV) { | ||
842 | /* LNA TOP: lowest */ | ||
843 | rc = r820t_write_reg_mask(priv, 0x1d, 0, 0x38); | ||
844 | if (rc < 0) | ||
845 | return rc; | ||
846 | |||
847 | /* 0: normal mode */ | ||
848 | rc = r820t_write_reg_mask(priv, 0x1c, 0, 0x04); | ||
849 | if (rc < 0) | ||
850 | return rc; | ||
851 | |||
852 | /* 0: PRE_DECT off */ | ||
853 | rc = r820t_write_reg_mask(priv, 0x06, 0, 0x40); | ||
854 | if (rc < 0) | ||
855 | return rc; | ||
856 | |||
857 | /* agc clk 250hz */ | ||
858 | rc = r820t_write_reg_mask(priv, 0x1a, 0x30, 0x30); | ||
859 | if (rc < 0) | ||
860 | return rc; | ||
861 | |||
862 | msleep(250); | ||
863 | |||
864 | /* write LNA TOP = 3 */ | ||
865 | rc = r820t_write_reg_mask(priv, 0x1d, 0x18, 0x38); | ||
866 | if (rc < 0) | ||
867 | return rc; | ||
868 | |||
869 | /* | ||
870 | * write discharge mode | ||
871 | * FIXME: IMHO, the mask here is wrong, but it matches | ||
872 | * what's there at the original driver | ||
873 | */ | ||
874 | rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0x04); | ||
875 | if (rc < 0) | ||
876 | return rc; | ||
877 | |||
878 | /* LNA discharge current */ | ||
879 | rc = r820t_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f); | ||
880 | if (rc < 0) | ||
881 | return rc; | ||
882 | |||
883 | /* agc clk 60hz */ | ||
884 | rc = r820t_write_reg_mask(priv, 0x1a, 0x20, 0x30); | ||
885 | if (rc < 0) | ||
886 | return rc; | ||
887 | } else { | ||
888 | /* PRE_DECT off */ | ||
889 | rc = r820t_write_reg_mask(priv, 0x06, 0, 0x40); | ||
890 | if (rc < 0) | ||
891 | return rc; | ||
892 | |||
893 | /* write LNA TOP */ | ||
894 | rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0x38); | ||
895 | if (rc < 0) | ||
896 | return rc; | ||
897 | |||
898 | /* | ||
899 | * write discharge mode | ||
900 | * FIXME: IMHO, the mask here is wrong, but it matches | ||
901 | * what's there at the original driver | ||
902 | */ | ||
903 | rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0x04); | ||
904 | if (rc < 0) | ||
905 | return rc; | ||
906 | |||
907 | /* LNA discharge current */ | ||
908 | rc = r820t_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f); | ||
909 | if (rc < 0) | ||
910 | return rc; | ||
911 | |||
912 | /* agc clk 1Khz, external det1 cap 1u */ | ||
913 | rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x30); | ||
914 | if (rc < 0) | ||
915 | return rc; | ||
916 | |||
917 | rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x04); | ||
918 | if (rc < 0) | ||
919 | return rc; | ||
920 | } | ||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static int r820t_set_tv_standard(struct r820t_priv *priv, | ||
925 | unsigned bw, | ||
926 | enum v4l2_tuner_type type, | ||
927 | v4l2_std_id std, u32 delsys) | ||
928 | |||
929 | { | ||
930 | int rc, i; | ||
931 | u32 if_khz, filt_cal_lo; | ||
932 | u8 data[5], val; | ||
933 | u8 filt_gain, img_r, filt_q, hp_cor, ext_enable, loop_through; | ||
934 | u8 lt_att, flt_ext_widest, polyfil_cur; | ||
935 | bool need_calibration; | ||
936 | |||
937 | tuner_dbg("selecting the delivery system\n"); | ||
938 | |||
939 | if (delsys == SYS_ISDBT) { | ||
940 | if_khz = 4063; | ||
941 | filt_cal_lo = 59000; | ||
942 | filt_gain = 0x10; /* +3db, 6mhz on */ | ||
943 | img_r = 0x00; /* image negative */ | ||
944 | filt_q = 0x10; /* r10[4]:low q(1'b1) */ | ||
945 | hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */ | ||
946 | ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */ | ||
947 | loop_through = 0x00; /* r5[7], lt on */ | ||
948 | lt_att = 0x00; /* r31[7], lt att enable */ | ||
949 | flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ | ||
950 | polyfil_cur = 0x60; /* r25[6:5]:min */ | ||
951 | } else { | ||
952 | if (bw <= 6) { | ||
953 | if_khz = 3570; | ||
954 | filt_cal_lo = 56000; /* 52000->56000 */ | ||
955 | filt_gain = 0x10; /* +3db, 6mhz on */ | ||
956 | img_r = 0x00; /* image negative */ | ||
957 | filt_q = 0x10; /* r10[4]:low q(1'b1) */ | ||
958 | hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */ | ||
959 | ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ | ||
960 | loop_through = 0x00; /* r5[7], lt on */ | ||
961 | lt_att = 0x00; /* r31[7], lt att enable */ | ||
962 | flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ | ||
963 | polyfil_cur = 0x60; /* r25[6:5]:min */ | ||
964 | } else if (bw == 7) { | ||
965 | #if 0 | ||
966 | /* | ||
967 | * There are two 7 MHz tables defined on the original | ||
968 | * driver, but just the second one seems to be visible | ||
969 | * by rtl2832. Keep this one here commented, as it | ||
970 | * might be needed in the future | ||
971 | */ | ||
972 | |||
973 | if_khz = 4070; | ||
974 | filt_cal_lo = 60000; | ||
975 | filt_gain = 0x10; /* +3db, 6mhz on */ | ||
976 | img_r = 0x00; /* image negative */ | ||
977 | filt_q = 0x10; /* r10[4]:low q(1'b1) */ | ||
978 | hp_cor = 0x2b; /* 1.7m disable, +1cap, 1.0mhz */ | ||
979 | ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ | ||
980 | loop_through = 0x00; /* r5[7], lt on */ | ||
981 | lt_att = 0x00; /* r31[7], lt att enable */ | ||
982 | flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ | ||
983 | polyfil_cur = 0x60; /* r25[6:5]:min */ | ||
984 | #endif | ||
985 | /* 7 MHz, second table */ | ||
986 | if_khz = 4570; | ||
987 | filt_cal_lo = 63000; | ||
988 | filt_gain = 0x10; /* +3db, 6mhz on */ | ||
989 | img_r = 0x00; /* image negative */ | ||
990 | filt_q = 0x10; /* r10[4]:low q(1'b1) */ | ||
991 | hp_cor = 0x2a; /* 1.7m disable, +1cap, 1.25mhz */ | ||
992 | ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ | ||
993 | loop_through = 0x00; /* r5[7], lt on */ | ||
994 | lt_att = 0x00; /* r31[7], lt att enable */ | ||
995 | flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ | ||
996 | polyfil_cur = 0x60; /* r25[6:5]:min */ | ||
997 | } else { | ||
998 | if_khz = 4570; | ||
999 | filt_cal_lo = 68500; | ||
1000 | filt_gain = 0x10; /* +3db, 6mhz on */ | ||
1001 | img_r = 0x00; /* image negative */ | ||
1002 | filt_q = 0x10; /* r10[4]:low q(1'b1) */ | ||
1003 | hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */ | ||
1004 | ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ | ||
1005 | loop_through = 0x00; /* r5[7], lt on */ | ||
1006 | lt_att = 0x00; /* r31[7], lt att enable */ | ||
1007 | flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ | ||
1008 | polyfil_cur = 0x60; /* r25[6:5]:min */ | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1012 | /* Initialize the shadow registers */ | ||
1013 | memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array)); | ||
1014 | |||
1015 | /* Init Flag & Xtal_check Result */ | ||
1016 | if (priv->imr_done) | ||
1017 | val = 1 | priv->xtal_cap_sel << 1; | ||
1018 | else | ||
1019 | val = 0; | ||
1020 | rc = r820t_write_reg_mask(priv, 0x0c, val, 0x0f); | ||
1021 | if (rc < 0) | ||
1022 | return rc; | ||
1023 | |||
1024 | /* version */ | ||
1025 | rc = r820t_write_reg_mask(priv, 0x13, VER_NUM, 0x3f); | ||
1026 | if (rc < 0) | ||
1027 | return rc; | ||
1028 | |||
1029 | /* for LT Gain test */ | ||
1030 | if (type != V4L2_TUNER_ANALOG_TV) { | ||
1031 | rc = r820t_write_reg_mask(priv, 0x1d, 0x00, 0x38); | ||
1032 | if (rc < 0) | ||
1033 | return rc; | ||
1034 | usleep_range(1000, 2000); | ||
1035 | } | ||
1036 | priv->int_freq = if_khz * 1000; | ||
1037 | |||
1038 | /* Check if standard changed. If so, filter calibration is needed */ | ||
1039 | if (type != priv->type) | ||
1040 | need_calibration = true; | ||
1041 | else if ((type == V4L2_TUNER_ANALOG_TV) && (std != priv->std)) | ||
1042 | need_calibration = true; | ||
1043 | else if ((type == V4L2_TUNER_DIGITAL_TV) && | ||
1044 | ((delsys != priv->delsys) || bw != priv->bw)) | ||
1045 | need_calibration = true; | ||
1046 | else | ||
1047 | need_calibration = false; | ||
1048 | |||
1049 | if (need_calibration) { | ||
1050 | tuner_dbg("calibrating the tuner\n"); | ||
1051 | for (i = 0; i < 2; i++) { | ||
1052 | /* Set filt_cap */ | ||
1053 | rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0x60); | ||
1054 | if (rc < 0) | ||
1055 | return rc; | ||
1056 | |||
1057 | /* set cali clk =on */ | ||
1058 | rc = r820t_write_reg_mask(priv, 0x0f, 0x04, 0x04); | ||
1059 | if (rc < 0) | ||
1060 | return rc; | ||
1061 | |||
1062 | /* X'tal cap 0pF for PLL */ | ||
1063 | rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x03); | ||
1064 | if (rc < 0) | ||
1065 | return rc; | ||
1066 | |||
1067 | rc = r820t_set_pll(priv, type, filt_cal_lo * 1000); | ||
1068 | if (rc < 0 || !priv->has_lock) | ||
1069 | return rc; | ||
1070 | |||
1071 | /* Start Trigger */ | ||
1072 | rc = r820t_write_reg_mask(priv, 0x0b, 0x10, 0x10); | ||
1073 | if (rc < 0) | ||
1074 | return rc; | ||
1075 | |||
1076 | usleep_range(1000, 2000); | ||
1077 | |||
1078 | /* Stop Trigger */ | ||
1079 | rc = r820t_write_reg_mask(priv, 0x0b, 0x00, 0x10); | ||
1080 | if (rc < 0) | ||
1081 | return rc; | ||
1082 | |||
1083 | /* set cali clk =off */ | ||
1084 | rc = r820t_write_reg_mask(priv, 0x0f, 0x00, 0x04); | ||
1085 | if (rc < 0) | ||
1086 | return rc; | ||
1087 | |||
1088 | /* Check if calibration worked */ | ||
1089 | rc = r820t_read(priv, 0x00, data, sizeof(data)); | ||
1090 | if (rc < 0) | ||
1091 | return rc; | ||
1092 | |||
1093 | priv->fil_cal_code = data[4] & 0x0f; | ||
1094 | if (priv->fil_cal_code && priv->fil_cal_code != 0x0f) | ||
1095 | break; | ||
1096 | } | ||
1097 | /* narrowest */ | ||
1098 | if (priv->fil_cal_code == 0x0f) | ||
1099 | priv->fil_cal_code = 0; | ||
1100 | } | ||
1101 | |||
1102 | rc = r820t_write_reg_mask(priv, 0x0a, | ||
1103 | filt_q | priv->fil_cal_code, 0x1f); | ||
1104 | if (rc < 0) | ||
1105 | return rc; | ||
1106 | |||
1107 | /* Set BW, Filter_gain, & HP corner */ | ||
1108 | rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0xef); | ||
1109 | if (rc < 0) | ||
1110 | return rc; | ||
1111 | |||
1112 | |||
1113 | /* Set Img_R */ | ||
1114 | rc = r820t_write_reg_mask(priv, 0x07, img_r, 0x80); | ||
1115 | if (rc < 0) | ||
1116 | return rc; | ||
1117 | |||
1118 | /* Set filt_3dB, V6MHz */ | ||
1119 | rc = r820t_write_reg_mask(priv, 0x06, filt_gain, 0x30); | ||
1120 | if (rc < 0) | ||
1121 | return rc; | ||
1122 | |||
1123 | /* channel filter extension */ | ||
1124 | rc = r820t_write_reg_mask(priv, 0x1e, ext_enable, 0x60); | ||
1125 | if (rc < 0) | ||
1126 | return rc; | ||
1127 | |||
1128 | /* Loop through */ | ||
1129 | rc = r820t_write_reg_mask(priv, 0x05, loop_through, 0x80); | ||
1130 | if (rc < 0) | ||
1131 | return rc; | ||
1132 | |||
1133 | /* Loop through attenuation */ | ||
1134 | rc = r820t_write_reg_mask(priv, 0x1f, lt_att, 0x80); | ||
1135 | if (rc < 0) | ||
1136 | return rc; | ||
1137 | |||
1138 | /* filter extension widest */ | ||
1139 | rc = r820t_write_reg_mask(priv, 0x0f, flt_ext_widest, 0x80); | ||
1140 | if (rc < 0) | ||
1141 | return rc; | ||
1142 | |||
1143 | /* RF poly filter current */ | ||
1144 | rc = r820t_write_reg_mask(priv, 0x19, polyfil_cur, 0x60); | ||
1145 | if (rc < 0) | ||
1146 | return rc; | ||
1147 | |||
1148 | /* Store current standard. If it changes, re-calibrate the tuner */ | ||
1149 | priv->delsys = delsys; | ||
1150 | priv->type = type; | ||
1151 | priv->std = std; | ||
1152 | priv->bw = bw; | ||
1153 | |||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | static int r820t_read_gain(struct r820t_priv *priv) | ||
1158 | { | ||
1159 | u8 data[4]; | ||
1160 | int rc; | ||
1161 | |||
1162 | rc = r820t_read(priv, 0x00, data, sizeof(data)); | ||
1163 | if (rc < 0) | ||
1164 | return rc; | ||
1165 | |||
1166 | return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4); | ||
1167 | } | ||
1168 | |||
1169 | #if 0 | ||
1170 | /* FIXME: This routine requires more testing */ | ||
1171 | static int r820t_set_gain_mode(struct r820t_priv *priv, | ||
1172 | bool set_manual_gain, | ||
1173 | int gain) | ||
1174 | { | ||
1175 | int rc; | ||
1176 | |||
1177 | if (set_manual_gain) { | ||
1178 | int i, total_gain = 0; | ||
1179 | uint8_t mix_index = 0, lna_index = 0; | ||
1180 | u8 data[4]; | ||
1181 | |||
1182 | /* LNA auto off */ | ||
1183 | rc = r820t_write_reg_mask(priv, 0x05, 0x10, 0x10); | ||
1184 | if (rc < 0) | ||
1185 | return rc; | ||
1186 | |||
1187 | /* Mixer auto off */ | ||
1188 | rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10); | ||
1189 | if (rc < 0) | ||
1190 | return rc; | ||
1191 | |||
1192 | rc = r820t_read(priv, 0x00, data, sizeof(data)); | ||
1193 | if (rc < 0) | ||
1194 | return rc; | ||
1195 | |||
1196 | /* set fixed VGA gain for now (16.3 dB) */ | ||
1197 | rc = r820t_write_reg_mask(priv, 0x0c, 0x08, 0x9f); | ||
1198 | if (rc < 0) | ||
1199 | return rc; | ||
1200 | |||
1201 | for (i = 0; i < 15; i++) { | ||
1202 | if (total_gain >= gain) | ||
1203 | break; | ||
1204 | |||
1205 | total_gain += r820t_lna_gain_steps[++lna_index]; | ||
1206 | |||
1207 | if (total_gain >= gain) | ||
1208 | break; | ||
1209 | |||
1210 | total_gain += r820t_mixer_gain_steps[++mix_index]; | ||
1211 | } | ||
1212 | |||
1213 | /* set LNA gain */ | ||
1214 | rc = r820t_write_reg_mask(priv, 0x05, lna_index, 0x0f); | ||
1215 | if (rc < 0) | ||
1216 | return rc; | ||
1217 | |||
1218 | /* set Mixer gain */ | ||
1219 | rc = r820t_write_reg_mask(priv, 0x07, mix_index, 0x0f); | ||
1220 | if (rc < 0) | ||
1221 | return rc; | ||
1222 | } else { | ||
1223 | /* LNA */ | ||
1224 | rc = r820t_write_reg_mask(priv, 0x05, 0, 0x10); | ||
1225 | if (rc < 0) | ||
1226 | return rc; | ||
1227 | |||
1228 | /* Mixer */ | ||
1229 | rc = r820t_write_reg_mask(priv, 0x07, 0x10, 0x10); | ||
1230 | if (rc < 0) | ||
1231 | return rc; | ||
1232 | |||
1233 | /* set fixed VGA gain for now (26.5 dB) */ | ||
1234 | rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f); | ||
1235 | if (rc < 0) | ||
1236 | return rc; | ||
1237 | } | ||
1238 | |||
1239 | return 0; | ||
1240 | } | ||
1241 | #endif | ||
1242 | |||
1243 | static int generic_set_freq(struct dvb_frontend *fe, | ||
1244 | u32 freq /* in HZ */, | ||
1245 | unsigned bw, | ||
1246 | enum v4l2_tuner_type type, | ||
1247 | v4l2_std_id std, u32 delsys) | ||
1248 | { | ||
1249 | struct r820t_priv *priv = fe->tuner_priv; | ||
1250 | int rc = -EINVAL; | ||
1251 | u32 lo_freq; | ||
1252 | |||
1253 | tuner_dbg("should set frequency to %d kHz, bw %d MHz\n", | ||
1254 | freq / 1000, bw); | ||
1255 | |||
1256 | rc = r820t_set_tv_standard(priv, bw, type, std, delsys); | ||
1257 | if (rc < 0) | ||
1258 | goto err; | ||
1259 | |||
1260 | if ((type == V4L2_TUNER_ANALOG_TV) && (std == V4L2_STD_SECAM_LC)) | ||
1261 | lo_freq = freq - priv->int_freq; | ||
1262 | else | ||
1263 | lo_freq = freq + priv->int_freq; | ||
1264 | |||
1265 | rc = r820t_set_mux(priv, lo_freq); | ||
1266 | if (rc < 0) | ||
1267 | goto err; | ||
1268 | |||
1269 | rc = r820t_set_pll(priv, type, lo_freq); | ||
1270 | if (rc < 0 || !priv->has_lock) | ||
1271 | goto err; | ||
1272 | |||
1273 | rc = r820t_sysfreq_sel(priv, freq, type, std, delsys); | ||
1274 | if (rc < 0) | ||
1275 | goto err; | ||
1276 | |||
1277 | tuner_dbg("%s: PLL locked on frequency %d Hz, gain=%d\n", | ||
1278 | __func__, freq, r820t_read_gain(priv)); | ||
1279 | |||
1280 | err: | ||
1281 | |||
1282 | if (rc < 0) | ||
1283 | tuner_dbg("%s: failed=%d\n", __func__, rc); | ||
1284 | return rc; | ||
1285 | } | ||
1286 | |||
1287 | /* | ||
1288 | * r820t standby logic | ||
1289 | */ | ||
1290 | |||
1291 | static int r820t_standby(struct r820t_priv *priv) | ||
1292 | { | ||
1293 | int rc; | ||
1294 | |||
1295 | /* If device was not initialized yet, don't need to standby */ | ||
1296 | if (!priv->init_done) | ||
1297 | return 0; | ||
1298 | |||
1299 | rc = r820t_write_reg(priv, 0x06, 0xb1); | ||
1300 | if (rc < 0) | ||
1301 | return rc; | ||
1302 | rc = r820t_write_reg(priv, 0x05, 0x03); | ||
1303 | if (rc < 0) | ||
1304 | return rc; | ||
1305 | rc = r820t_write_reg(priv, 0x07, 0x3a); | ||
1306 | if (rc < 0) | ||
1307 | return rc; | ||
1308 | rc = r820t_write_reg(priv, 0x08, 0x40); | ||
1309 | if (rc < 0) | ||
1310 | return rc; | ||
1311 | rc = r820t_write_reg(priv, 0x09, 0xc0); | ||
1312 | if (rc < 0) | ||
1313 | return rc; | ||
1314 | rc = r820t_write_reg(priv, 0x0a, 0x36); | ||
1315 | if (rc < 0) | ||
1316 | return rc; | ||
1317 | rc = r820t_write_reg(priv, 0x0c, 0x35); | ||
1318 | if (rc < 0) | ||
1319 | return rc; | ||
1320 | rc = r820t_write_reg(priv, 0x0f, 0x68); | ||
1321 | if (rc < 0) | ||
1322 | return rc; | ||
1323 | rc = r820t_write_reg(priv, 0x11, 0x03); | ||
1324 | if (rc < 0) | ||
1325 | return rc; | ||
1326 | rc = r820t_write_reg(priv, 0x17, 0xf4); | ||
1327 | if (rc < 0) | ||
1328 | return rc; | ||
1329 | rc = r820t_write_reg(priv, 0x19, 0x0c); | ||
1330 | |||
1331 | /* Force initial calibration */ | ||
1332 | priv->type = -1; | ||
1333 | |||
1334 | return rc; | ||
1335 | } | ||
1336 | |||
1337 | /* | ||
1338 | * r820t device init logic | ||
1339 | */ | ||
1340 | |||
1341 | static int r820t_xtal_check(struct r820t_priv *priv) | ||
1342 | { | ||
1343 | int rc, i; | ||
1344 | u8 data[3], val; | ||
1345 | |||
1346 | /* Initialize the shadow registers */ | ||
1347 | memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array)); | ||
1348 | |||
1349 | /* cap 30pF & Drive Low */ | ||
1350 | rc = r820t_write_reg_mask(priv, 0x10, 0x0b, 0x0b); | ||
1351 | if (rc < 0) | ||
1352 | return rc; | ||
1353 | |||
1354 | /* set pll autotune = 128kHz */ | ||
1355 | rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x0c); | ||
1356 | if (rc < 0) | ||
1357 | return rc; | ||
1358 | |||
1359 | /* set manual initial reg = 111111; */ | ||
1360 | rc = r820t_write_reg_mask(priv, 0x13, 0x7f, 0x7f); | ||
1361 | if (rc < 0) | ||
1362 | return rc; | ||
1363 | |||
1364 | /* set auto */ | ||
1365 | rc = r820t_write_reg_mask(priv, 0x13, 0x00, 0x40); | ||
1366 | if (rc < 0) | ||
1367 | return rc; | ||
1368 | |||
1369 | /* Try several xtal capacitor alternatives */ | ||
1370 | for (i = 0; i < ARRAY_SIZE(r820t_xtal_capacitor); i++) { | ||
1371 | rc = r820t_write_reg_mask(priv, 0x10, | ||
1372 | r820t_xtal_capacitor[i][0], 0x1b); | ||
1373 | if (rc < 0) | ||
1374 | return rc; | ||
1375 | |||
1376 | usleep_range(5000, 6000); | ||
1377 | |||
1378 | rc = r820t_read(priv, 0x00, data, sizeof(data)); | ||
1379 | if (rc < 0) | ||
1380 | return rc; | ||
1381 | if ((!data[2]) & 0x40) | ||
1382 | continue; | ||
1383 | |||
1384 | val = data[2] & 0x3f; | ||
1385 | |||
1386 | if (priv->cfg->xtal == 16000000 && (val > 29 || val < 23)) | ||
1387 | break; | ||
1388 | |||
1389 | if (val != 0x3f) | ||
1390 | break; | ||
1391 | } | ||
1392 | |||
1393 | if (i == ARRAY_SIZE(r820t_xtal_capacitor)) | ||
1394 | return -EINVAL; | ||
1395 | |||
1396 | return r820t_xtal_capacitor[i][1]; | ||
1397 | } | ||
1398 | |||
1399 | static int r820t_imr_prepare(struct r820t_priv *priv) | ||
1400 | { | ||
1401 | int rc; | ||
1402 | |||
1403 | /* Initialize the shadow registers */ | ||
1404 | memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array)); | ||
1405 | |||
1406 | /* lna off (air-in off) */ | ||
1407 | rc = r820t_write_reg_mask(priv, 0x05, 0x20, 0x20); | ||
1408 | if (rc < 0) | ||
1409 | return rc; | ||
1410 | |||
1411 | /* mixer gain mode = manual */ | ||
1412 | rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10); | ||
1413 | if (rc < 0) | ||
1414 | return rc; | ||
1415 | |||
1416 | /* filter corner = lowest */ | ||
1417 | rc = r820t_write_reg_mask(priv, 0x0a, 0x0f, 0x0f); | ||
1418 | if (rc < 0) | ||
1419 | return rc; | ||
1420 | |||
1421 | /* filter bw=+2cap, hp=5M */ | ||
1422 | rc = r820t_write_reg_mask(priv, 0x0b, 0x60, 0x6f); | ||
1423 | if (rc < 0) | ||
1424 | return rc; | ||
1425 | |||
1426 | /* adc=on, vga code mode, gain = 26.5dB */ | ||
1427 | rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f); | ||
1428 | if (rc < 0) | ||
1429 | return rc; | ||
1430 | |||
1431 | /* ring clk = on */ | ||
1432 | rc = r820t_write_reg_mask(priv, 0x0f, 0, 0x08); | ||
1433 | if (rc < 0) | ||
1434 | return rc; | ||
1435 | |||
1436 | /* ring power = on */ | ||
1437 | rc = r820t_write_reg_mask(priv, 0x18, 0x10, 0x10); | ||
1438 | if (rc < 0) | ||
1439 | return rc; | ||
1440 | |||
1441 | /* from ring = ring pll in */ | ||
1442 | rc = r820t_write_reg_mask(priv, 0x1c, 0x02, 0x02); | ||
1443 | if (rc < 0) | ||
1444 | return rc; | ||
1445 | |||
1446 | /* sw_pdect = det3 */ | ||
1447 | rc = r820t_write_reg_mask(priv, 0x1e, 0x80, 0x80); | ||
1448 | if (rc < 0) | ||
1449 | return rc; | ||
1450 | |||
1451 | /* Set filt_3dB */ | ||
1452 | rc = r820t_write_reg_mask(priv, 0x06, 0x20, 0x20); | ||
1453 | |||
1454 | return rc; | ||
1455 | } | ||
1456 | |||
1457 | static int r820t_multi_read(struct r820t_priv *priv) | ||
1458 | { | ||
1459 | int rc, i; | ||
1460 | u8 data[2], min = 0, max = 255, sum = 0; | ||
1461 | |||
1462 | usleep_range(5000, 6000); | ||
1463 | |||
1464 | for (i = 0; i < 6; i++) { | ||
1465 | rc = r820t_read(priv, 0x00, data, sizeof(data)); | ||
1466 | if (rc < 0) | ||
1467 | return rc; | ||
1468 | |||
1469 | sum += data[1]; | ||
1470 | |||
1471 | if (data[1] < min) | ||
1472 | min = data[1]; | ||
1473 | |||
1474 | if (data[1] > max) | ||
1475 | max = data[1]; | ||
1476 | } | ||
1477 | rc = sum - max - min; | ||
1478 | |||
1479 | return rc; | ||
1480 | } | ||
1481 | |||
1482 | static int r820t_imr_cross(struct r820t_priv *priv, | ||
1483 | struct r820t_sect_type iq_point[3], | ||
1484 | u8 *x_direct) | ||
1485 | { | ||
1486 | struct r820t_sect_type cross[5]; /* (0,0)(0,Q-1)(0,I-1)(Q-1,0)(I-1,0) */ | ||
1487 | struct r820t_sect_type tmp; | ||
1488 | int i, rc; | ||
1489 | u8 reg08, reg09; | ||
1490 | |||
1491 | reg08 = r820t_read_cache_reg(priv, 8) & 0xc0; | ||
1492 | reg09 = r820t_read_cache_reg(priv, 9) & 0xc0; | ||
1493 | |||
1494 | tmp.gain_x = 0; | ||
1495 | tmp.phase_y = 0; | ||
1496 | tmp.value = 255; | ||
1497 | |||
1498 | for (i = 0; i < 5; i++) { | ||
1499 | switch (i) { | ||
1500 | case 0: | ||
1501 | cross[i].gain_x = reg08; | ||
1502 | cross[i].phase_y = reg09; | ||
1503 | break; | ||
1504 | case 1: | ||
1505 | cross[i].gain_x = reg08; /* 0 */ | ||
1506 | cross[i].phase_y = reg09 + 1; /* Q-1 */ | ||
1507 | break; | ||
1508 | case 2: | ||
1509 | cross[i].gain_x = reg08; /* 0 */ | ||
1510 | cross[i].phase_y = (reg09 | 0x20) + 1; /* I-1 */ | ||
1511 | break; | ||
1512 | case 3: | ||
1513 | cross[i].gain_x = reg08 + 1; /* Q-1 */ | ||
1514 | cross[i].phase_y = reg09; | ||
1515 | break; | ||
1516 | default: | ||
1517 | cross[i].gain_x = (reg08 | 0x20) + 1; /* I-1 */ | ||
1518 | cross[i].phase_y = reg09; | ||
1519 | } | ||
1520 | |||
1521 | rc = r820t_write_reg(priv, 0x08, cross[i].gain_x); | ||
1522 | if (rc < 0) | ||
1523 | return rc; | ||
1524 | |||
1525 | rc = r820t_write_reg(priv, 0x09, cross[i].phase_y); | ||
1526 | if (rc < 0) | ||
1527 | return rc; | ||
1528 | |||
1529 | rc = r820t_multi_read(priv); | ||
1530 | if (rc < 0) | ||
1531 | return rc; | ||
1532 | |||
1533 | cross[i].value = rc; | ||
1534 | |||
1535 | if (cross[i].value < tmp.value) | ||
1536 | memcpy(&tmp, &cross[i], sizeof(tmp)); | ||
1537 | } | ||
1538 | |||
1539 | if ((tmp.phase_y & 0x1f) == 1) { /* y-direction */ | ||
1540 | *x_direct = 0; | ||
1541 | |||
1542 | iq_point[0] = cross[0]; | ||
1543 | iq_point[1] = cross[1]; | ||
1544 | iq_point[2] = cross[2]; | ||
1545 | } else { /* (0,0) or x-direction */ | ||
1546 | *x_direct = 1; | ||
1547 | |||
1548 | iq_point[0] = cross[0]; | ||
1549 | iq_point[1] = cross[3]; | ||
1550 | iq_point[2] = cross[4]; | ||
1551 | } | ||
1552 | return 0; | ||
1553 | } | ||
1554 | |||
1555 | static void r820t_compre_cor(struct r820t_sect_type iq[3]) | ||
1556 | { | ||
1557 | int i; | ||
1558 | |||
1559 | for (i = 3; i > 0; i--) { | ||
1560 | if (iq[0].value > iq[i - 1].value) | ||
1561 | swap(iq[0], iq[i - 1]); | ||
1562 | } | ||
1563 | } | ||
1564 | |||
1565 | static int r820t_compre_step(struct r820t_priv *priv, | ||
1566 | struct r820t_sect_type iq[3], u8 reg) | ||
1567 | { | ||
1568 | int rc; | ||
1569 | struct r820t_sect_type tmp; | ||
1570 | |||
1571 | /* | ||
1572 | * Purpose: if (Gain<9 or Phase<9), Gain+1 or Phase+1 and compare | ||
1573 | * with min value: | ||
1574 | * new < min => update to min and continue | ||
1575 | * new > min => Exit | ||
1576 | */ | ||
1577 | |||
1578 | /* min value already saved in iq[0] */ | ||
1579 | tmp.phase_y = iq[0].phase_y; | ||
1580 | tmp.gain_x = iq[0].gain_x; | ||
1581 | |||
1582 | while (((tmp.gain_x & 0x1f) < IMR_TRIAL) && | ||
1583 | ((tmp.phase_y & 0x1f) < IMR_TRIAL)) { | ||
1584 | if (reg == 0x08) | ||
1585 | tmp.gain_x++; | ||
1586 | else | ||
1587 | tmp.phase_y++; | ||
1588 | |||
1589 | rc = r820t_write_reg(priv, 0x08, tmp.gain_x); | ||
1590 | if (rc < 0) | ||
1591 | return rc; | ||
1592 | |||
1593 | rc = r820t_write_reg(priv, 0x09, tmp.phase_y); | ||
1594 | if (rc < 0) | ||
1595 | return rc; | ||
1596 | |||
1597 | rc = r820t_multi_read(priv); | ||
1598 | if (rc < 0) | ||
1599 | return rc; | ||
1600 | tmp.value = rc; | ||
1601 | |||
1602 | if (tmp.value <= iq[0].value) { | ||
1603 | iq[0].gain_x = tmp.gain_x; | ||
1604 | iq[0].phase_y = tmp.phase_y; | ||
1605 | iq[0].value = tmp.value; | ||
1606 | } else { | ||
1607 | return 0; | ||
1608 | } | ||
1609 | |||
1610 | } | ||
1611 | |||
1612 | return 0; | ||
1613 | } | ||
1614 | |||
1615 | static int r820t_iq_tree(struct r820t_priv *priv, | ||
1616 | struct r820t_sect_type iq[3], | ||
1617 | u8 fix_val, u8 var_val, u8 fix_reg) | ||
1618 | { | ||
1619 | int rc, i; | ||
1620 | u8 tmp, var_reg; | ||
1621 | |||
1622 | /* | ||
1623 | * record IMC results by input gain/phase location then adjust | ||
1624 | * gain or phase positive 1 step and negtive 1 step, | ||
1625 | * both record results | ||
1626 | */ | ||
1627 | |||
1628 | if (fix_reg == 0x08) | ||
1629 | var_reg = 0x09; | ||
1630 | else | ||
1631 | var_reg = 0x08; | ||
1632 | |||
1633 | for (i = 0; i < 3; i++) { | ||
1634 | rc = r820t_write_reg(priv, fix_reg, fix_val); | ||
1635 | if (rc < 0) | ||
1636 | return rc; | ||
1637 | |||
1638 | rc = r820t_write_reg(priv, var_reg, var_val); | ||
1639 | if (rc < 0) | ||
1640 | return rc; | ||
1641 | |||
1642 | rc = r820t_multi_read(priv); | ||
1643 | if (rc < 0) | ||
1644 | return rc; | ||
1645 | iq[i].value = rc; | ||
1646 | |||
1647 | if (fix_reg == 0x08) { | ||
1648 | iq[i].gain_x = fix_val; | ||
1649 | iq[i].phase_y = var_val; | ||
1650 | } else { | ||
1651 | iq[i].phase_y = fix_val; | ||
1652 | iq[i].gain_x = var_val; | ||
1653 | } | ||
1654 | |||
1655 | if (i == 0) { /* try right-side point */ | ||
1656 | var_val++; | ||
1657 | } else if (i == 1) { /* try left-side point */ | ||
1658 | /* if absolute location is 1, change I/Q direction */ | ||
1659 | if ((var_val & 0x1f) < 0x02) { | ||
1660 | tmp = 2 - (var_val & 0x1f); | ||
1661 | |||
1662 | /* b[5]:I/Q selection. 0:Q-path, 1:I-path */ | ||
1663 | if (var_val & 0x20) { | ||
1664 | var_val &= 0xc0; | ||
1665 | var_val |= tmp; | ||
1666 | } else { | ||
1667 | var_val |= 0x20 | tmp; | ||
1668 | } | ||
1669 | } else { | ||
1670 | var_val -= 2; | ||
1671 | } | ||
1672 | } | ||
1673 | } | ||
1674 | |||
1675 | return 0; | ||
1676 | } | ||
1677 | |||
1678 | static int r820t_section(struct r820t_priv *priv, | ||
1679 | struct r820t_sect_type *iq_point) | ||
1680 | { | ||
1681 | int rc; | ||
1682 | struct r820t_sect_type compare_iq[3], compare_bet[3]; | ||
1683 | |||
1684 | /* Try X-1 column and save min result to compare_bet[0] */ | ||
1685 | if (!(iq_point->gain_x & 0x1f)) | ||
1686 | compare_iq[0].gain_x = ((iq_point->gain_x) & 0xdf) + 1; /* Q-path, Gain=1 */ | ||
1687 | else | ||
1688 | compare_iq[0].gain_x = iq_point->gain_x - 1; /* left point */ | ||
1689 | compare_iq[0].phase_y = iq_point->phase_y; | ||
1690 | |||
1691 | /* y-direction */ | ||
1692 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1693 | compare_iq[0].phase_y, 0x08); | ||
1694 | if (rc < 0) | ||
1695 | return rc; | ||
1696 | |||
1697 | r820t_compre_cor(compare_iq); | ||
1698 | |||
1699 | compare_bet[0] = compare_iq[0]; | ||
1700 | |||
1701 | /* Try X column and save min result to compare_bet[1] */ | ||
1702 | compare_iq[0].gain_x = iq_point->gain_x; | ||
1703 | compare_iq[0].phase_y = iq_point->phase_y; | ||
1704 | |||
1705 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1706 | compare_iq[0].phase_y, 0x08); | ||
1707 | if (rc < 0) | ||
1708 | return rc; | ||
1709 | |||
1710 | r820t_compre_cor(compare_iq); | ||
1711 | |||
1712 | compare_bet[1] = compare_iq[0]; | ||
1713 | |||
1714 | /* Try X+1 column and save min result to compare_bet[2] */ | ||
1715 | if ((iq_point->gain_x & 0x1f) == 0x00) | ||
1716 | compare_iq[0].gain_x = ((iq_point->gain_x) | 0x20) + 1; /* I-path, Gain=1 */ | ||
1717 | else | ||
1718 | compare_iq[0].gain_x = iq_point->gain_x + 1; | ||
1719 | compare_iq[0].phase_y = iq_point->phase_y; | ||
1720 | |||
1721 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1722 | compare_iq[0].phase_y, 0x08); | ||
1723 | if (rc < 0) | ||
1724 | return rc; | ||
1725 | |||
1726 | r820t_compre_cor(compare_iq); | ||
1727 | |||
1728 | compare_bet[2] = compare_iq[0]; | ||
1729 | |||
1730 | r820t_compre_cor(compare_bet); | ||
1731 | |||
1732 | *iq_point = compare_bet[0]; | ||
1733 | |||
1734 | return 0; | ||
1735 | } | ||
1736 | |||
1737 | static int r820t_vga_adjust(struct r820t_priv *priv) | ||
1738 | { | ||
1739 | int rc; | ||
1740 | u8 vga_count; | ||
1741 | |||
1742 | /* increase vga power to let image significant */ | ||
1743 | for (vga_count = 12; vga_count < 16; vga_count++) { | ||
1744 | rc = r820t_write_reg_mask(priv, 0x0c, vga_count, 0x0f); | ||
1745 | if (rc < 0) | ||
1746 | return rc; | ||
1747 | |||
1748 | usleep_range(10000, 11000); | ||
1749 | |||
1750 | rc = r820t_multi_read(priv); | ||
1751 | if (rc < 0) | ||
1752 | return rc; | ||
1753 | |||
1754 | if (rc > 40 * 4) | ||
1755 | break; | ||
1756 | } | ||
1757 | |||
1758 | return 0; | ||
1759 | } | ||
1760 | |||
1761 | static int r820t_iq(struct r820t_priv *priv, struct r820t_sect_type *iq_pont) | ||
1762 | { | ||
1763 | struct r820t_sect_type compare_iq[3]; | ||
1764 | int rc; | ||
1765 | u8 x_direction = 0; /* 1:x, 0:y */ | ||
1766 | u8 dir_reg, other_reg; | ||
1767 | |||
1768 | r820t_vga_adjust(priv); | ||
1769 | |||
1770 | rc = r820t_imr_cross(priv, compare_iq, &x_direction); | ||
1771 | if (rc < 0) | ||
1772 | return rc; | ||
1773 | |||
1774 | if (x_direction == 1) { | ||
1775 | dir_reg = 0x08; | ||
1776 | other_reg = 0x09; | ||
1777 | } else { | ||
1778 | dir_reg = 0x09; | ||
1779 | other_reg = 0x08; | ||
1780 | } | ||
1781 | |||
1782 | /* compare and find min of 3 points. determine i/q direction */ | ||
1783 | r820t_compre_cor(compare_iq); | ||
1784 | |||
1785 | /* increase step to find min value of this direction */ | ||
1786 | rc = r820t_compre_step(priv, compare_iq, dir_reg); | ||
1787 | if (rc < 0) | ||
1788 | return rc; | ||
1789 | |||
1790 | /* the other direction */ | ||
1791 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1792 | compare_iq[0].phase_y, dir_reg); | ||
1793 | if (rc < 0) | ||
1794 | return rc; | ||
1795 | |||
1796 | /* compare and find min of 3 points. determine i/q direction */ | ||
1797 | r820t_compre_cor(compare_iq); | ||
1798 | |||
1799 | /* increase step to find min value on this direction */ | ||
1800 | rc = r820t_compre_step(priv, compare_iq, other_reg); | ||
1801 | if (rc < 0) | ||
1802 | return rc; | ||
1803 | |||
1804 | /* check 3 points again */ | ||
1805 | rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, | ||
1806 | compare_iq[0].phase_y, other_reg); | ||
1807 | if (rc < 0) | ||
1808 | return rc; | ||
1809 | |||
1810 | r820t_compre_cor(compare_iq); | ||
1811 | |||
1812 | /* section-9 check */ | ||
1813 | rc = r820t_section(priv, compare_iq); | ||
1814 | |||
1815 | *iq_pont = compare_iq[0]; | ||
1816 | |||
1817 | /* reset gain/phase control setting */ | ||
1818 | rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f); | ||
1819 | if (rc < 0) | ||
1820 | return rc; | ||
1821 | |||
1822 | rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f); | ||
1823 | |||
1824 | return rc; | ||
1825 | } | ||
1826 | |||
1827 | static int r820t_f_imr(struct r820t_priv *priv, struct r820t_sect_type *iq_pont) | ||
1828 | { | ||
1829 | int rc; | ||
1830 | |||
1831 | r820t_vga_adjust(priv); | ||
1832 | |||
1833 | /* | ||
1834 | * search surrounding points from previous point | ||
1835 | * try (x-1), (x), (x+1) columns, and find min IMR result point | ||
1836 | */ | ||
1837 | rc = r820t_section(priv, iq_pont); | ||
1838 | if (rc < 0) | ||
1839 | return rc; | ||
1840 | |||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag) | ||
1845 | { | ||
1846 | struct r820t_sect_type imr_point; | ||
1847 | int rc; | ||
1848 | u32 ring_vco, ring_freq, ring_ref; | ||
1849 | u8 n_ring, n; | ||
1850 | int reg18, reg19, reg1f; | ||
1851 | |||
1852 | if (priv->cfg->xtal > 24000000) | ||
1853 | ring_ref = priv->cfg->xtal / 2; | ||
1854 | else | ||
1855 | ring_ref = priv->cfg->xtal; | ||
1856 | |||
1857 | for (n = 0; n < 16; n++) { | ||
1858 | if ((16 + n) * 8 * ring_ref >= 3100000) { | ||
1859 | n_ring = n; | ||
1860 | break; | ||
1861 | } | ||
1862 | |||
1863 | /* n_ring not found */ | ||
1864 | if (n == 15) | ||
1865 | n_ring = n; | ||
1866 | } | ||
1867 | |||
1868 | reg18 = r820t_read_cache_reg(priv, 0x18); | ||
1869 | reg19 = r820t_read_cache_reg(priv, 0x19); | ||
1870 | reg1f = r820t_read_cache_reg(priv, 0x1f); | ||
1871 | |||
1872 | reg18 &= 0xf0; /* set ring[3:0] */ | ||
1873 | reg18 |= n_ring; | ||
1874 | |||
1875 | ring_vco = (16 + n_ring) * 8 * ring_ref; | ||
1876 | |||
1877 | reg18 &= 0xdf; /* clear ring_se23 */ | ||
1878 | reg19 &= 0xfc; /* clear ring_seldiv */ | ||
1879 | reg1f &= 0xfc; /* clear ring_att */ | ||
1880 | |||
1881 | switch (imr_mem) { | ||
1882 | case 0: | ||
1883 | ring_freq = ring_vco / 48; | ||
1884 | reg18 |= 0x20; /* ring_se23 = 1 */ | ||
1885 | reg19 |= 0x03; /* ring_seldiv = 3 */ | ||
1886 | reg1f |= 0x02; /* ring_att 10 */ | ||
1887 | break; | ||
1888 | case 1: | ||
1889 | ring_freq = ring_vco / 16; | ||
1890 | reg18 |= 0x00; /* ring_se23 = 0 */ | ||
1891 | reg19 |= 0x02; /* ring_seldiv = 2 */ | ||
1892 | reg1f |= 0x00; /* pw_ring 00 */ | ||
1893 | break; | ||
1894 | case 2: | ||
1895 | ring_freq = ring_vco / 8; | ||
1896 | reg18 |= 0x00; /* ring_se23 = 0 */ | ||
1897 | reg19 |= 0x01; /* ring_seldiv = 1 */ | ||
1898 | reg1f |= 0x03; /* pw_ring 11 */ | ||
1899 | break; | ||
1900 | case 3: | ||
1901 | ring_freq = ring_vco / 6; | ||
1902 | reg18 |= 0x20; /* ring_se23 = 1 */ | ||
1903 | reg19 |= 0x00; /* ring_seldiv = 0 */ | ||
1904 | reg1f |= 0x03; /* pw_ring 11 */ | ||
1905 | break; | ||
1906 | case 4: | ||
1907 | ring_freq = ring_vco / 4; | ||
1908 | reg18 |= 0x00; /* ring_se23 = 0 */ | ||
1909 | reg19 |= 0x00; /* ring_seldiv = 0 */ | ||
1910 | reg1f |= 0x01; /* pw_ring 01 */ | ||
1911 | break; | ||
1912 | default: | ||
1913 | ring_freq = ring_vco / 4; | ||
1914 | reg18 |= 0x00; /* ring_se23 = 0 */ | ||
1915 | reg19 |= 0x00; /* ring_seldiv = 0 */ | ||
1916 | reg1f |= 0x01; /* pw_ring 01 */ | ||
1917 | break; | ||
1918 | } | ||
1919 | |||
1920 | |||
1921 | /* write pw_ring, n_ring, ringdiv2 registers */ | ||
1922 | |||
1923 | /* n_ring, ring_se23 */ | ||
1924 | rc = r820t_write_reg(priv, 0x18, reg18); | ||
1925 | if (rc < 0) | ||
1926 | return rc; | ||
1927 | |||
1928 | /* ring_sediv */ | ||
1929 | rc = r820t_write_reg(priv, 0x19, reg19); | ||
1930 | if (rc < 0) | ||
1931 | return rc; | ||
1932 | |||
1933 | /* pw_ring */ | ||
1934 | rc = r820t_write_reg(priv, 0x1f, reg1f); | ||
1935 | if (rc < 0) | ||
1936 | return rc; | ||
1937 | |||
1938 | /* mux input freq ~ rf_in freq */ | ||
1939 | rc = r820t_set_mux(priv, (ring_freq - 5300) * 1000); | ||
1940 | if (rc < 0) | ||
1941 | return rc; | ||
1942 | |||
1943 | rc = r820t_set_pll(priv, V4L2_TUNER_DIGITAL_TV, | ||
1944 | (ring_freq - 5300) * 1000); | ||
1945 | if (!priv->has_lock) | ||
1946 | rc = -EINVAL; | ||
1947 | if (rc < 0) | ||
1948 | return rc; | ||
1949 | |||
1950 | if (im_flag) { | ||
1951 | rc = r820t_iq(priv, &imr_point); | ||
1952 | } else { | ||
1953 | imr_point.gain_x = priv->imr_data[3].gain_x; | ||
1954 | imr_point.phase_y = priv->imr_data[3].phase_y; | ||
1955 | imr_point.value = priv->imr_data[3].value; | ||
1956 | |||
1957 | rc = r820t_f_imr(priv, &imr_point); | ||
1958 | } | ||
1959 | if (rc < 0) | ||
1960 | return rc; | ||
1961 | |||
1962 | /* save IMR value */ | ||
1963 | switch (imr_mem) { | ||
1964 | case 0: | ||
1965 | priv->imr_data[0].gain_x = imr_point.gain_x; | ||
1966 | priv->imr_data[0].phase_y = imr_point.phase_y; | ||
1967 | priv->imr_data[0].value = imr_point.value; | ||
1968 | break; | ||
1969 | case 1: | ||
1970 | priv->imr_data[1].gain_x = imr_point.gain_x; | ||
1971 | priv->imr_data[1].phase_y = imr_point.phase_y; | ||
1972 | priv->imr_data[1].value = imr_point.value; | ||
1973 | break; | ||
1974 | case 2: | ||
1975 | priv->imr_data[2].gain_x = imr_point.gain_x; | ||
1976 | priv->imr_data[2].phase_y = imr_point.phase_y; | ||
1977 | priv->imr_data[2].value = imr_point.value; | ||
1978 | break; | ||
1979 | case 3: | ||
1980 | priv->imr_data[3].gain_x = imr_point.gain_x; | ||
1981 | priv->imr_data[3].phase_y = imr_point.phase_y; | ||
1982 | priv->imr_data[3].value = imr_point.value; | ||
1983 | break; | ||
1984 | case 4: | ||
1985 | priv->imr_data[4].gain_x = imr_point.gain_x; | ||
1986 | priv->imr_data[4].phase_y = imr_point.phase_y; | ||
1987 | priv->imr_data[4].value = imr_point.value; | ||
1988 | break; | ||
1989 | default: | ||
1990 | priv->imr_data[4].gain_x = imr_point.gain_x; | ||
1991 | priv->imr_data[4].phase_y = imr_point.phase_y; | ||
1992 | priv->imr_data[4].value = imr_point.value; | ||
1993 | break; | ||
1994 | } | ||
1995 | |||
1996 | return 0; | ||
1997 | } | ||
1998 | |||
1999 | static int r820t_imr_callibrate(struct r820t_priv *priv) | ||
2000 | { | ||
2001 | int rc, i; | ||
2002 | int xtal_cap = 0; | ||
2003 | |||
2004 | if (priv->init_done) | ||
2005 | return 0; | ||
2006 | |||
2007 | /* Detect Xtal capacitance */ | ||
2008 | if ((priv->cfg->rafael_chip == CHIP_R820T) || | ||
2009 | (priv->cfg->rafael_chip == CHIP_R828S) || | ||
2010 | (priv->cfg->rafael_chip == CHIP_R820C)) { | ||
2011 | priv->xtal_cap_sel = XTAL_HIGH_CAP_0P; | ||
2012 | } else { | ||
2013 | /* Initialize registers */ | ||
2014 | rc = r820t_write(priv, 0x05, | ||
2015 | r820t_init_array, sizeof(r820t_init_array)); | ||
2016 | if (rc < 0) | ||
2017 | return rc; | ||
2018 | for (i = 0; i < 3; i++) { | ||
2019 | rc = r820t_xtal_check(priv); | ||
2020 | if (rc < 0) | ||
2021 | return rc; | ||
2022 | if (!i || rc > xtal_cap) | ||
2023 | xtal_cap = rc; | ||
2024 | } | ||
2025 | priv->xtal_cap_sel = xtal_cap; | ||
2026 | } | ||
2027 | |||
2028 | /* | ||
2029 | * Disables IMR callibration. That emulates the same behaviour | ||
2030 | * as what is done by rtl-sdr userspace library. Useful for testing | ||
2031 | */ | ||
2032 | if (no_imr_cal) { | ||
2033 | priv->init_done = true; | ||
2034 | |||
2035 | return 0; | ||
2036 | } | ||
2037 | |||
2038 | /* Initialize registers */ | ||
2039 | rc = r820t_write(priv, 0x05, | ||
2040 | r820t_init_array, sizeof(r820t_init_array)); | ||
2041 | if (rc < 0) | ||
2042 | return rc; | ||
2043 | |||
2044 | rc = r820t_imr_prepare(priv); | ||
2045 | if (rc < 0) | ||
2046 | return rc; | ||
2047 | |||
2048 | rc = r820t_imr(priv, 3, true); | ||
2049 | if (rc < 0) | ||
2050 | return rc; | ||
2051 | rc = r820t_imr(priv, 1, false); | ||
2052 | if (rc < 0) | ||
2053 | return rc; | ||
2054 | rc = r820t_imr(priv, 0, false); | ||
2055 | if (rc < 0) | ||
2056 | return rc; | ||
2057 | rc = r820t_imr(priv, 2, false); | ||
2058 | if (rc < 0) | ||
2059 | return rc; | ||
2060 | rc = r820t_imr(priv, 4, false); | ||
2061 | if (rc < 0) | ||
2062 | return rc; | ||
2063 | |||
2064 | priv->init_done = true; | ||
2065 | priv->imr_done = true; | ||
2066 | |||
2067 | return 0; | ||
2068 | } | ||
2069 | |||
2070 | #if 0 | ||
2071 | /* Not used, for now */ | ||
2072 | static int r820t_gpio(struct r820t_priv *priv, bool enable) | ||
2073 | { | ||
2074 | return r820t_write_reg_mask(priv, 0x0f, enable ? 1 : 0, 0x01); | ||
2075 | } | ||
2076 | #endif | ||
2077 | |||
2078 | /* | ||
2079 | * r820t frontend operations and tuner attach code | ||
2080 | * | ||
2081 | * All driver locks and i2c control are only in this part of the code | ||
2082 | */ | ||
2083 | |||
2084 | static int r820t_init(struct dvb_frontend *fe) | ||
2085 | { | ||
2086 | struct r820t_priv *priv = fe->tuner_priv; | ||
2087 | int rc; | ||
2088 | |||
2089 | tuner_dbg("%s:\n", __func__); | ||
2090 | |||
2091 | mutex_lock(&priv->lock); | ||
2092 | if (fe->ops.i2c_gate_ctrl) | ||
2093 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
2094 | |||
2095 | rc = r820t_imr_callibrate(priv); | ||
2096 | if (rc < 0) | ||
2097 | goto err; | ||
2098 | |||
2099 | /* Initialize registers */ | ||
2100 | rc = r820t_write(priv, 0x05, | ||
2101 | r820t_init_array, sizeof(r820t_init_array)); | ||
2102 | |||
2103 | err: | ||
2104 | if (fe->ops.i2c_gate_ctrl) | ||
2105 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
2106 | mutex_unlock(&priv->lock); | ||
2107 | |||
2108 | if (rc < 0) | ||
2109 | tuner_dbg("%s: failed=%d\n", __func__, rc); | ||
2110 | return rc; | ||
2111 | } | ||
2112 | |||
2113 | static int r820t_sleep(struct dvb_frontend *fe) | ||
2114 | { | ||
2115 | struct r820t_priv *priv = fe->tuner_priv; | ||
2116 | int rc; | ||
2117 | |||
2118 | tuner_dbg("%s:\n", __func__); | ||
2119 | |||
2120 | mutex_lock(&priv->lock); | ||
2121 | if (fe->ops.i2c_gate_ctrl) | ||
2122 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
2123 | |||
2124 | rc = r820t_standby(priv); | ||
2125 | |||
2126 | if (fe->ops.i2c_gate_ctrl) | ||
2127 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
2128 | mutex_unlock(&priv->lock); | ||
2129 | |||
2130 | tuner_dbg("%s: failed=%d\n", __func__, rc); | ||
2131 | return rc; | ||
2132 | } | ||
2133 | |||
2134 | static int r820t_set_analog_freq(struct dvb_frontend *fe, | ||
2135 | struct analog_parameters *p) | ||
2136 | { | ||
2137 | struct r820t_priv *priv = fe->tuner_priv; | ||
2138 | unsigned bw; | ||
2139 | int rc; | ||
2140 | |||
2141 | tuner_dbg("%s called\n", __func__); | ||
2142 | |||
2143 | /* if std is not defined, choose one */ | ||
2144 | if (!p->std) | ||
2145 | p->std = V4L2_STD_MN; | ||
2146 | |||
2147 | if ((p->std == V4L2_STD_PAL_M) || (p->std == V4L2_STD_NTSC)) | ||
2148 | bw = 6; | ||
2149 | else | ||
2150 | bw = 8; | ||
2151 | |||
2152 | mutex_lock(&priv->lock); | ||
2153 | if (fe->ops.i2c_gate_ctrl) | ||
2154 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
2155 | |||
2156 | rc = generic_set_freq(fe, 62500l * p->frequency, bw, | ||
2157 | V4L2_TUNER_ANALOG_TV, p->std, SYS_UNDEFINED); | ||
2158 | |||
2159 | if (fe->ops.i2c_gate_ctrl) | ||
2160 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
2161 | mutex_unlock(&priv->lock); | ||
2162 | |||
2163 | return rc; | ||
2164 | } | ||
2165 | |||
2166 | static int r820t_set_params(struct dvb_frontend *fe) | ||
2167 | { | ||
2168 | struct r820t_priv *priv = fe->tuner_priv; | ||
2169 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
2170 | int rc; | ||
2171 | unsigned bw; | ||
2172 | |||
2173 | tuner_dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", | ||
2174 | __func__, c->delivery_system, c->frequency, c->bandwidth_hz); | ||
2175 | |||
2176 | mutex_lock(&priv->lock); | ||
2177 | if (fe->ops.i2c_gate_ctrl) | ||
2178 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
2179 | |||
2180 | bw = (c->bandwidth_hz + 500000) / 1000000; | ||
2181 | if (!bw) | ||
2182 | bw = 8; | ||
2183 | |||
2184 | rc = generic_set_freq(fe, c->frequency, bw, | ||
2185 | V4L2_TUNER_DIGITAL_TV, 0, c->delivery_system); | ||
2186 | |||
2187 | if (fe->ops.i2c_gate_ctrl) | ||
2188 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
2189 | mutex_unlock(&priv->lock); | ||
2190 | |||
2191 | if (rc) | ||
2192 | tuner_dbg("%s: failed=%d\n", __func__, rc); | ||
2193 | return rc; | ||
2194 | } | ||
2195 | |||
2196 | static int r820t_signal(struct dvb_frontend *fe, u16 *strength) | ||
2197 | { | ||
2198 | struct r820t_priv *priv = fe->tuner_priv; | ||
2199 | int rc = 0; | ||
2200 | |||
2201 | mutex_lock(&priv->lock); | ||
2202 | if (fe->ops.i2c_gate_ctrl) | ||
2203 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
2204 | |||
2205 | if (priv->has_lock) { | ||
2206 | rc = r820t_read_gain(priv); | ||
2207 | if (rc < 0) | ||
2208 | goto err; | ||
2209 | |||
2210 | /* A higher gain at LNA means a lower signal strength */ | ||
2211 | *strength = (45 - rc) << 4 | 0xff; | ||
2212 | if (*strength == 0xff) | ||
2213 | *strength = 0; | ||
2214 | } else { | ||
2215 | *strength = 0; | ||
2216 | } | ||
2217 | |||
2218 | err: | ||
2219 | if (fe->ops.i2c_gate_ctrl) | ||
2220 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
2221 | mutex_unlock(&priv->lock); | ||
2222 | |||
2223 | tuner_dbg("%s: %s, gain=%d strength=%d\n", | ||
2224 | __func__, | ||
2225 | priv->has_lock ? "PLL locked" : "no signal", | ||
2226 | rc, *strength); | ||
2227 | |||
2228 | return 0; | ||
2229 | } | ||
2230 | |||
2231 | static int r820t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
2232 | { | ||
2233 | struct r820t_priv *priv = fe->tuner_priv; | ||
2234 | |||
2235 | tuner_dbg("%s:\n", __func__); | ||
2236 | |||
2237 | *frequency = priv->int_freq; | ||
2238 | |||
2239 | return 0; | ||
2240 | } | ||
2241 | |||
2242 | static int r820t_release(struct dvb_frontend *fe) | ||
2243 | { | ||
2244 | struct r820t_priv *priv = fe->tuner_priv; | ||
2245 | |||
2246 | tuner_dbg("%s:\n", __func__); | ||
2247 | |||
2248 | mutex_lock(&r820t_list_mutex); | ||
2249 | |||
2250 | if (priv) | ||
2251 | hybrid_tuner_release_state(priv); | ||
2252 | |||
2253 | mutex_unlock(&r820t_list_mutex); | ||
2254 | |||
2255 | fe->tuner_priv = NULL; | ||
2256 | |||
2257 | kfree(fe->tuner_priv); | ||
2258 | |||
2259 | return 0; | ||
2260 | } | ||
2261 | |||
2262 | static const struct dvb_tuner_ops r820t_tuner_ops = { | ||
2263 | .info = { | ||
2264 | .name = "Rafael Micro R820T", | ||
2265 | .frequency_min = 42000000, | ||
2266 | .frequency_max = 1002000000, | ||
2267 | }, | ||
2268 | .init = r820t_init, | ||
2269 | .release = r820t_release, | ||
2270 | .sleep = r820t_sleep, | ||
2271 | .set_params = r820t_set_params, | ||
2272 | .set_analog_params = r820t_set_analog_freq, | ||
2273 | .get_if_frequency = r820t_get_if_frequency, | ||
2274 | .get_rf_strength = r820t_signal, | ||
2275 | }; | ||
2276 | |||
2277 | struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, | ||
2278 | struct i2c_adapter *i2c, | ||
2279 | const struct r820t_config *cfg) | ||
2280 | { | ||
2281 | struct r820t_priv *priv; | ||
2282 | int rc = -ENODEV; | ||
2283 | u8 data[5]; | ||
2284 | int instance; | ||
2285 | |||
2286 | mutex_lock(&r820t_list_mutex); | ||
2287 | |||
2288 | instance = hybrid_tuner_request_state(struct r820t_priv, priv, | ||
2289 | hybrid_tuner_instance_list, | ||
2290 | i2c, cfg->i2c_addr, | ||
2291 | "r820t"); | ||
2292 | switch (instance) { | ||
2293 | case 0: | ||
2294 | /* memory allocation failure */ | ||
2295 | goto err_no_gate; | ||
2296 | break; | ||
2297 | case 1: | ||
2298 | /* new tuner instance */ | ||
2299 | priv->cfg = cfg; | ||
2300 | |||
2301 | mutex_init(&priv->lock); | ||
2302 | |||
2303 | fe->tuner_priv = priv; | ||
2304 | break; | ||
2305 | case 2: | ||
2306 | /* existing tuner instance */ | ||
2307 | fe->tuner_priv = priv; | ||
2308 | break; | ||
2309 | } | ||
2310 | |||
2311 | memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops, sizeof(r820t_tuner_ops)); | ||
2312 | |||
2313 | if (fe->ops.i2c_gate_ctrl) | ||
2314 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
2315 | |||
2316 | /* check if the tuner is there */ | ||
2317 | rc = r820t_read(priv, 0x00, data, sizeof(data)); | ||
2318 | if (rc < 0) | ||
2319 | goto err; | ||
2320 | |||
2321 | rc = r820t_sleep(fe); | ||
2322 | if (rc < 0) | ||
2323 | goto err; | ||
2324 | |||
2325 | tuner_info("Rafael Micro r820t successfully identified\n"); | ||
2326 | |||
2327 | fe->tuner_priv = priv; | ||
2328 | memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops, | ||
2329 | sizeof(struct dvb_tuner_ops)); | ||
2330 | |||
2331 | if (fe->ops.i2c_gate_ctrl) | ||
2332 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
2333 | |||
2334 | mutex_unlock(&r820t_list_mutex); | ||
2335 | |||
2336 | return fe; | ||
2337 | err: | ||
2338 | if (fe->ops.i2c_gate_ctrl) | ||
2339 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
2340 | |||
2341 | err_no_gate: | ||
2342 | mutex_unlock(&r820t_list_mutex); | ||
2343 | |||
2344 | tuner_info("%s: failed=%d\n", __func__, rc); | ||
2345 | r820t_release(fe); | ||
2346 | return NULL; | ||
2347 | } | ||
2348 | EXPORT_SYMBOL_GPL(r820t_attach); | ||
2349 | |||
2350 | MODULE_DESCRIPTION("Rafael Micro r820t silicon tuner driver"); | ||
2351 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | ||
2352 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h new file mode 100644 index 000000000000..4c0823b21693 --- /dev/null +++ b/drivers/media/tuners/r820t.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Elonics R820T silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> | ||
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 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef R820T_H | ||
22 | #define R820T_H | ||
23 | |||
24 | #include <linux/kconfig.h> | ||
25 | #include "dvb_frontend.h" | ||
26 | |||
27 | enum r820t_chip { | ||
28 | CHIP_R820T, | ||
29 | CHIP_R620D, | ||
30 | CHIP_R828D, | ||
31 | CHIP_R828, | ||
32 | CHIP_R828S, | ||
33 | CHIP_R820C, | ||
34 | }; | ||
35 | |||
36 | struct r820t_config { | ||
37 | u8 i2c_addr; /* 0x34 */ | ||
38 | u32 xtal; | ||
39 | enum r820t_chip rafael_chip; | ||
40 | unsigned max_i2c_msg_len; | ||
41 | bool use_diplexer; | ||
42 | }; | ||
43 | |||
44 | #if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T) | ||
45 | struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, | ||
46 | struct i2c_adapter *i2c, | ||
47 | const struct r820t_config *cfg); | ||
48 | #else | ||
49 | static inline struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, | ||
50 | struct i2c_adapter *i2c, | ||
51 | const struct r820t_config *cfg) | ||
52 | { | ||
53 | pr_warn("%s: driver disabled by Kconfig\n", __func__); | ||
54 | return NULL; | ||
55 | } | ||
56 | #endif | ||
57 | |||
58 | #endif | ||
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 9aff03555464..a3c8ecf22078 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig | |||
@@ -143,6 +143,7 @@ config DVB_USB_RTL28XXU | |||
143 | select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT | 143 | select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT |
144 | select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT | 144 | select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT |
145 | select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT | 145 | select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT |
146 | select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT | ||
146 | help | 147 | help |
147 | Say Y here to support the Realtek RTL28xxU DVB USB receiver. | 148 | Say Y here to support the Realtek RTL28xxU DVB USB receiver. |
148 | 149 | ||
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 3d128a5e4794..22015fe1a0f3 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "e4000.h" | 33 | #include "e4000.h" |
34 | #include "fc2580.h" | 34 | #include "fc2580.h" |
35 | #include "tua9001.h" | 35 | #include "tua9001.h" |
36 | #include "r820t.h" | ||
36 | 37 | ||
37 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 38 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
38 | 39 | ||
@@ -375,6 +376,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) | |||
375 | struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf}; | 376 | struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf}; |
376 | struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf}; | 377 | struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf}; |
377 | struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; | 378 | struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; |
379 | struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 5, buf}; | ||
378 | 380 | ||
379 | dev_dbg(&d->udev->dev, "%s:\n", __func__); | 381 | dev_dbg(&d->udev->dev, "%s:\n", __func__); |
380 | 382 | ||
@@ -479,6 +481,14 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) | |||
479 | goto found; | 481 | goto found; |
480 | } | 482 | } |
481 | 483 | ||
484 | /* check R820T by reading tuner stats at I2C addr 0x1a */ | ||
485 | ret = rtl28xxu_ctrl_msg(d, &req_r820t); | ||
486 | if (ret == 0) { | ||
487 | priv->tuner = TUNER_RTL2832_R820T; | ||
488 | priv->tuner_name = "R820T"; | ||
489 | goto found; | ||
490 | } | ||
491 | |||
482 | found: | 492 | found: |
483 | dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name); | 493 | dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name); |
484 | 494 | ||
@@ -589,6 +599,12 @@ static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = { | |||
589 | .tuner = TUNER_RTL2832_E4000, | 599 | .tuner = TUNER_RTL2832_E4000, |
590 | }; | 600 | }; |
591 | 601 | ||
602 | static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = { | ||
603 | .i2c_addr = 0x10, | ||
604 | .xtal = 28800000, | ||
605 | .tuner = TUNER_RTL2832_R820T, | ||
606 | }; | ||
607 | |||
592 | static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, | 608 | static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, |
593 | int cmd, int arg) | 609 | int cmd, int arg) |
594 | { | 610 | { |
@@ -728,6 +744,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) | |||
728 | case TUNER_RTL2832_E4000: | 744 | case TUNER_RTL2832_E4000: |
729 | rtl2832_config = &rtl28xxu_rtl2832_e4000_config; | 745 | rtl2832_config = &rtl28xxu_rtl2832_e4000_config; |
730 | break; | 746 | break; |
747 | case TUNER_RTL2832_R820T: | ||
748 | rtl2832_config = &rtl28xxu_rtl2832_r820t_config; | ||
749 | break; | ||
731 | default: | 750 | default: |
732 | dev_err(&d->udev->dev, "%s: unknown tuner=%s\n", | 751 | dev_err(&d->udev->dev, "%s: unknown tuner=%s\n", |
733 | KBUILD_MODNAME, priv->tuner_name); | 752 | KBUILD_MODNAME, priv->tuner_name); |
@@ -840,6 +859,13 @@ static const struct fc0012_config rtl2832u_fc0012_config = { | |||
840 | .xtal_freq = FC_XTAL_28_8_MHZ, | 859 | .xtal_freq = FC_XTAL_28_8_MHZ, |
841 | }; | 860 | }; |
842 | 861 | ||
862 | static const struct r820t_config rtl2832u_r820t_config = { | ||
863 | .i2c_addr = 0x1a, | ||
864 | .xtal = 28800000, | ||
865 | .max_i2c_msg_len = 2, | ||
866 | .rafael_chip = CHIP_R820T, | ||
867 | }; | ||
868 | |||
843 | static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) | 869 | static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) |
844 | { | 870 | { |
845 | int ret; | 871 | int ret; |
@@ -889,6 +915,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) | |||
889 | fe = dvb_attach(tua9001_attach, adap->fe[0], &d->i2c_adap, | 915 | fe = dvb_attach(tua9001_attach, adap->fe[0], &d->i2c_adap, |
890 | &rtl2832u_tua9001_config); | 916 | &rtl2832u_tua9001_config); |
891 | break; | 917 | break; |
918 | case TUNER_RTL2832_R820T: | ||
919 | fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap, | ||
920 | &rtl2832u_r820t_config); | ||
921 | |||
922 | /* Use tuner to get the signal strength */ | ||
923 | adap->fe[0]->ops.read_signal_strength = | ||
924 | adap->fe[0]->ops.tuner_ops.get_rf_strength; | ||
925 | break; | ||
892 | default: | 926 | default: |
893 | fe = NULL; | 927 | fe = NULL; |
894 | dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, | 928 | dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, |
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h index 2f3af2d3b6ce..533a33127289 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h | |||
@@ -82,6 +82,7 @@ enum rtl28xxu_tuner { | |||
82 | TUNER_RTL2832_E4000, | 82 | TUNER_RTL2832_E4000, |
83 | TUNER_RTL2832_TDA18272, | 83 | TUNER_RTL2832_TDA18272, |
84 | TUNER_RTL2832_FC0013, | 84 | TUNER_RTL2832_FC0013, |
85 | TUNER_RTL2832_R820T, | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | struct rtl28xxu_req { | 88 | struct rtl28xxu_req { |