diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2007-10-22 08:56:38 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:01:06 -0500 |
commit | 5bea1cd3871351d70cc7624af138f8aa68b7be77 (patch) | |
tree | 77db506f3fb668e33e091aaa1cda2cf09da85085 | |
parent | ce1f8bdb0cbe9c5f57cf0256ef75fce06152547f (diff) |
V4L/DVB (6435): tda8290: add support for NXP TDA18271 tuner and TDA8295 analog demod
Add basic support for NXP TDA8295 analog demod and TDA18271 tuner silicon.
TDA8295 + TDA8275a not yet tested.
TDA8290 + TDA18271 not yet supported.
Digital mode of TDA18271 not yet tested & needs more work.
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | Documentation/video4linux/CARDLIST.tuner | 1 | ||||
-rw-r--r-- | drivers/media/Kconfig | 3 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/Kconfig | 7 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda18271.c | 1054 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/tda18271.h | 40 | ||||
-rw-r--r-- | drivers/media/video/tda8290.c | 319 | ||||
-rw-r--r-- | drivers/media/video/tda8290.h | 8 | ||||
-rw-r--r-- | drivers/media/video/tuner-core.c | 5 | ||||
-rw-r--r-- | drivers/media/video/tuner-types.c | 3 | ||||
-rw-r--r-- | drivers/media/video/tveeprom.c | 2 | ||||
-rw-r--r-- | include/media/tuner.h | 2 |
12 files changed, 1437 insertions, 8 deletions
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index 84c3ac7c33d9..ac47b48715dd 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner | |||
@@ -73,3 +73,4 @@ tuner=71 - Xceive xc2028/xc3028 tuner | |||
73 | tuner=72 - Thomson FE6600 | 73 | tuner=72 - Thomson FE6600 |
74 | tuner=73 - Samsung TCPG 6121P30A | 74 | tuner=73 - Samsung TCPG 6121P30A |
75 | tuner=75 - Philips TEA5761 FM Radio | 75 | tuner=75 - Philips TEA5761 FM Radio |
76 | tuner=76 - tda8295+18271 | ||
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index d363d0cae38b..e52229380984 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig | |||
@@ -105,9 +105,10 @@ config TUNER_MT20XX | |||
105 | Say Y here to include support for the MT2032 / MT2050 tuner. | 105 | Say Y here to include support for the MT2032 / MT2050 tuner. |
106 | 106 | ||
107 | config TUNER_TDA8290 | 107 | config TUNER_TDA8290 |
108 | tristate "TDA 8290+8275(a) tuner combo" | 108 | tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" |
109 | depends on I2C | 109 | depends on I2C |
110 | select DVB_TDA827X | 110 | select DVB_TDA827X |
111 | select DVB_TDA18271 | ||
111 | default m if VIDEO_TUNER_CUSTOMIZE | 112 | default m if VIDEO_TUNER_CUSTOMIZE |
112 | help | 113 | help |
113 | Say Y here to include support for Philips TDA8290+8275(a) tuner. | 114 | Say Y here to include support for Philips TDA8290+8275(a) tuner. |
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 59b9ed1f1aec..57178d6e1cf8 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -316,6 +316,13 @@ config DVB_TDA827X | |||
316 | help | 316 | help |
317 | A DVB-T silicon tuner module. Say Y when you want to support this tuner. | 317 | A DVB-T silicon tuner module. Say Y when you want to support this tuner. |
318 | 318 | ||
319 | config DVB_TDA18271 | ||
320 | tristate "NXP TDA18271 silicon tuner" | ||
321 | depends on I2C | ||
322 | default m if DVB_FE_CUSTOMISE | ||
323 | help | ||
324 | A silicon tuner module. Say Y when you want to support this tuner. | ||
325 | |||
319 | config DVB_TUNER_QT1010 | 326 | config DVB_TUNER_QT1010 |
320 | tristate "Quantek QT1010 silicon tuner" | 327 | tristate "Quantek QT1010 silicon tuner" |
321 | depends on DVB_CORE && I2C | 328 | depends on DVB_CORE && I2C |
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 4b8ad1f132aa..457effcda5da 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -39,6 +39,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o | |||
39 | obj-$(CONFIG_DVB_TDA10086) += tda10086.o | 39 | obj-$(CONFIG_DVB_TDA10086) += tda10086.o |
40 | obj-$(CONFIG_DVB_TDA826X) += tda826x.o | 40 | obj-$(CONFIG_DVB_TDA826X) += tda826x.o |
41 | obj-$(CONFIG_DVB_TDA827X) += tda827x.o | 41 | obj-$(CONFIG_DVB_TDA827X) += tda827x.o |
42 | obj-$(CONFIG_DVB_TDA18271) += tda18271.o | ||
42 | obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o | 43 | obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o |
43 | obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o | 44 | obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o |
44 | obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o | 45 | obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o |
diff --git a/drivers/media/dvb/frontends/tda18271.c b/drivers/media/dvb/frontends/tda18271.c new file mode 100644 index 000000000000..3395f2bda498 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271.c | |||
@@ -0,0 +1,1054 @@ | |||
1 | /* | ||
2 | tda18271.c - driver for the Philips / NXP TDA18271 silicon tuner | ||
3 | |||
4 | Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) | ||
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 | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/videodev2.h> | ||
24 | |||
25 | #include "tda18271.h" | ||
26 | |||
27 | static int debug; | ||
28 | module_param(debug, int, 0644); | ||
29 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
30 | |||
31 | #define tuner_dbg(fmt, arg...) do {\ | ||
32 | if (debug > 0) \ | ||
33 | printk(KERN_DEBUG fmt, ##arg); } while (0) | ||
34 | |||
35 | #define tuner_extra_dbg(fmt, arg...) do {\ | ||
36 | if (debug > 1) \ | ||
37 | printk(KERN_DEBUG fmt, ##arg); } while (0) | ||
38 | |||
39 | #define R_ID 0x00 /* ID byte */ | ||
40 | #define R_TM 0x01 /* Thermo byte */ | ||
41 | #define R_PL 0x02 /* Power level byte */ | ||
42 | #define R_EP1 0x03 /* Easy Prog byte 1 */ | ||
43 | #define R_EP2 0x04 /* Easy Prog byte 2 */ | ||
44 | #define R_EP3 0x05 /* Easy Prog byte 3 */ | ||
45 | #define R_EP4 0x06 /* Easy Prog byte 4 */ | ||
46 | #define R_EP5 0x07 /* Easy Prog byte 5 */ | ||
47 | #define R_CPD 0x08 /* Cal Post-Divider byte */ | ||
48 | #define R_CD1 0x09 /* Cal Divider byte 1 */ | ||
49 | #define R_CD2 0x0a /* Cal Divider byte 2 */ | ||
50 | #define R_CD3 0x0b /* Cal Divider byte 3 */ | ||
51 | #define R_MPD 0x0c /* Main Post-Divider byte */ | ||
52 | #define R_MD1 0x0d /* Main Divider byte 1 */ | ||
53 | #define R_MD2 0x0e /* Main Divider byte 2 */ | ||
54 | #define R_MD3 0x0f /* Main Divider byte 3 */ | ||
55 | #define R_EB1 0x10 /* Extended byte 1 */ | ||
56 | #define R_EB2 0x11 /* Extended byte 2 */ | ||
57 | #define R_EB3 0x12 /* Extended byte 3 */ | ||
58 | #define R_EB4 0x13 /* Extended byte 4 */ | ||
59 | #define R_EB5 0x14 /* Extended byte 5 */ | ||
60 | #define R_EB6 0x15 /* Extended byte 6 */ | ||
61 | #define R_EB7 0x16 /* Extended byte 7 */ | ||
62 | #define R_EB8 0x17 /* Extended byte 8 */ | ||
63 | #define R_EB9 0x18 /* Extended byte 9 */ | ||
64 | #define R_EB10 0x19 /* Extended byte 10 */ | ||
65 | #define R_EB11 0x1a /* Extended byte 11 */ | ||
66 | #define R_EB12 0x1b /* Extended byte 12 */ | ||
67 | #define R_EB13 0x1c /* Extended byte 13 */ | ||
68 | #define R_EB14 0x1d /* Extended byte 14 */ | ||
69 | #define R_EB15 0x1e /* Extended byte 15 */ | ||
70 | #define R_EB16 0x1f /* Extended byte 16 */ | ||
71 | #define R_EB17 0x20 /* Extended byte 17 */ | ||
72 | #define R_EB18 0x21 /* Extended byte 18 */ | ||
73 | #define R_EB19 0x22 /* Extended byte 19 */ | ||
74 | #define R_EB20 0x23 /* Extended byte 20 */ | ||
75 | #define R_EB21 0x24 /* Extended byte 21 */ | ||
76 | #define R_EB22 0x25 /* Extended byte 22 */ | ||
77 | #define R_EB23 0x26 /* Extended byte 23 */ | ||
78 | |||
79 | struct tda18271_pll_map { | ||
80 | u32 lomax; | ||
81 | u8 pd; /* post div */ | ||
82 | u8 d; /* div */ | ||
83 | }; | ||
84 | |||
85 | static struct tda18271_pll_map tda18271_main_pll[] = { | ||
86 | { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, | ||
87 | { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, | ||
88 | { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, | ||
89 | { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, | ||
90 | { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, | ||
91 | { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, | ||
92 | { .lomax = 54000, .pd = 0x59, .d = 0x90 }, | ||
93 | { .lomax = 61000, .pd = 0x58, .d = 0x80 }, | ||
94 | { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, | ||
95 | { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, | ||
96 | { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, | ||
97 | { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, | ||
98 | { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, | ||
99 | { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, | ||
100 | { .lomax = 109000, .pd = 0x49, .d = 0x48 }, | ||
101 | { .lomax = 123000, .pd = 0x48, .d = 0x40 }, | ||
102 | { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, | ||
103 | { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, | ||
104 | { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, | ||
105 | { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, | ||
106 | { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, | ||
107 | { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, | ||
108 | { .lomax = 219000, .pd = 0x39, .d = 0x24 }, | ||
109 | { .lomax = 246000, .pd = 0x38, .d = 0x20 }, | ||
110 | { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, | ||
111 | { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, | ||
112 | { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, | ||
113 | { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, | ||
114 | { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, | ||
115 | { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, | ||
116 | { .lomax = 438000, .pd = 0x29, .d = 0x12 }, | ||
117 | { .lomax = 493000, .pd = 0x28, .d = 0x10 }, | ||
118 | { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, | ||
119 | { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, | ||
120 | { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, | ||
121 | { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, | ||
122 | { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, | ||
123 | { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, | ||
124 | { .lomax = 877000, .pd = 0x19, .d = 0x09 }, | ||
125 | { .lomax = 987000, .pd = 0x18, .d = 0x08 }, | ||
126 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
127 | }; | ||
128 | |||
129 | static struct tda18271_pll_map tda18271_cal_pll[] = { | ||
130 | { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, | ||
131 | { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, | ||
132 | { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, | ||
133 | { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, | ||
134 | { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, | ||
135 | { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, | ||
136 | { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, | ||
137 | { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, | ||
138 | { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, | ||
139 | { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, | ||
140 | { .lomax = 88000, .pd = 0xca, .d = 0x50 }, | ||
141 | { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, | ||
142 | { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, | ||
143 | { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, | ||
144 | { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, | ||
145 | { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, | ||
146 | { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, | ||
147 | { .lomax = 176000, .pd = 0xba, .d = 0x28 }, | ||
148 | { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, | ||
149 | { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, | ||
150 | { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, | ||
151 | { .lomax = 271000, .pd = 0xad, .d = 0x1a }, | ||
152 | { .lomax = 294000, .pd = 0xac, .d = 0x18 }, | ||
153 | { .lomax = 321000, .pd = 0xab, .d = 0x16 }, | ||
154 | { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, | ||
155 | { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, | ||
156 | { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, | ||
157 | { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, | ||
158 | { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, | ||
159 | { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, | ||
160 | { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, | ||
161 | { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, | ||
162 | { .lomax = 785000, .pd = 0x99, .d = 0x09 }, | ||
163 | { .lomax = 883000, .pd = 0x98, .d = 0x08 }, | ||
164 | { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, | ||
165 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
166 | }; | ||
167 | |||
168 | struct tda18271_map { | ||
169 | u32 rfmax; | ||
170 | u8 val; | ||
171 | }; | ||
172 | |||
173 | static struct tda18271_map tda18271_bp_filter[] = { | ||
174 | { .rfmax = 62000, .val = 0x00 }, | ||
175 | { .rfmax = 84000, .val = 0x01 }, | ||
176 | { .rfmax = 100000, .val = 0x02 }, | ||
177 | { .rfmax = 140000, .val = 0x03 }, | ||
178 | { .rfmax = 170000, .val = 0x04 }, | ||
179 | { .rfmax = 180000, .val = 0x05 }, | ||
180 | { .rfmax = 865000, .val = 0x06 }, | ||
181 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
182 | }; | ||
183 | |||
184 | static struct tda18271_map tda18271_km[] = { | ||
185 | { .rfmax = 61100, .val = 0x74 }, | ||
186 | { .rfmax = 350000, .val = 0x40 }, | ||
187 | { .rfmax = 720000, .val = 0x30 }, | ||
188 | { .rfmax = 865000, .val = 0x40 }, | ||
189 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
190 | }; | ||
191 | |||
192 | static struct tda18271_map tda18271_rf_band[] = { | ||
193 | { .rfmax = 47900, .val = 0x00 }, | ||
194 | { .rfmax = 61100, .val = 0x01 }, | ||
195 | /* { .rfmax = 152600, .val = 0x02 }, */ | ||
196 | { .rfmax = 121200, .val = 0x02 }, | ||
197 | { .rfmax = 164700, .val = 0x03 }, | ||
198 | { .rfmax = 203500, .val = 0x04 }, | ||
199 | { .rfmax = 457800, .val = 0x05 }, | ||
200 | { .rfmax = 865000, .val = 0x06 }, | ||
201 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
202 | }; | ||
203 | |||
204 | static struct tda18271_map tda18271_gain_taper[] = { | ||
205 | { .rfmax = 45400, .val = 0x1f }, | ||
206 | { .rfmax = 45800, .val = 0x1e }, | ||
207 | { .rfmax = 46200, .val = 0x1d }, | ||
208 | { .rfmax = 46700, .val = 0x1c }, | ||
209 | { .rfmax = 47100, .val = 0x1b }, | ||
210 | { .rfmax = 47500, .val = 0x1a }, | ||
211 | { .rfmax = 47900, .val = 0x19 }, | ||
212 | { .rfmax = 49600, .val = 0x17 }, | ||
213 | { .rfmax = 51200, .val = 0x16 }, | ||
214 | { .rfmax = 52900, .val = 0x15 }, | ||
215 | { .rfmax = 54500, .val = 0x14 }, | ||
216 | { .rfmax = 56200, .val = 0x13 }, | ||
217 | { .rfmax = 57800, .val = 0x12 }, | ||
218 | { .rfmax = 59500, .val = 0x11 }, | ||
219 | { .rfmax = 61100, .val = 0x10 }, | ||
220 | { .rfmax = 67600, .val = 0x0d }, | ||
221 | { .rfmax = 74200, .val = 0x0c }, | ||
222 | { .rfmax = 80700, .val = 0x0b }, | ||
223 | { .rfmax = 87200, .val = 0x0a }, | ||
224 | { .rfmax = 93800, .val = 0x09 }, | ||
225 | { .rfmax = 100300, .val = 0x08 }, | ||
226 | { .rfmax = 106900, .val = 0x07 }, | ||
227 | { .rfmax = 113400, .val = 0x06 }, | ||
228 | { .rfmax = 119900, .val = 0x05 }, | ||
229 | { .rfmax = 126500, .val = 0x04 }, | ||
230 | { .rfmax = 133000, .val = 0x03 }, | ||
231 | { .rfmax = 139500, .val = 0x02 }, | ||
232 | { .rfmax = 146100, .val = 0x01 }, | ||
233 | { .rfmax = 152600, .val = 0x00 }, | ||
234 | { .rfmax = 154300, .val = 0x1f }, | ||
235 | { .rfmax = 156100, .val = 0x1e }, | ||
236 | { .rfmax = 157800, .val = 0x1d }, | ||
237 | { .rfmax = 159500, .val = 0x1c }, | ||
238 | { .rfmax = 161200, .val = 0x1b }, | ||
239 | { .rfmax = 163000, .val = 0x1a }, | ||
240 | { .rfmax = 164700, .val = 0x19 }, | ||
241 | { .rfmax = 170200, .val = 0x17 }, | ||
242 | { .rfmax = 175800, .val = 0x16 }, | ||
243 | { .rfmax = 181300, .val = 0x15 }, | ||
244 | { .rfmax = 186900, .val = 0x14 }, | ||
245 | { .rfmax = 192400, .val = 0x13 }, | ||
246 | { .rfmax = 198000, .val = 0x12 }, | ||
247 | { .rfmax = 203500, .val = 0x11 }, | ||
248 | { .rfmax = 216200, .val = 0x14 }, | ||
249 | { .rfmax = 228900, .val = 0x13 }, | ||
250 | { .rfmax = 241600, .val = 0x12 }, | ||
251 | { .rfmax = 254400, .val = 0x11 }, | ||
252 | { .rfmax = 267100, .val = 0x10 }, | ||
253 | { .rfmax = 279800, .val = 0x0f }, | ||
254 | { .rfmax = 292500, .val = 0x0e }, | ||
255 | { .rfmax = 305200, .val = 0x0d }, | ||
256 | { .rfmax = 317900, .val = 0x0c }, | ||
257 | { .rfmax = 330700, .val = 0x0b }, | ||
258 | { .rfmax = 343400, .val = 0x0a }, | ||
259 | { .rfmax = 356100, .val = 0x09 }, | ||
260 | { .rfmax = 368800, .val = 0x08 }, | ||
261 | { .rfmax = 381500, .val = 0x07 }, | ||
262 | { .rfmax = 394200, .val = 0x06 }, | ||
263 | { .rfmax = 406900, .val = 0x05 }, | ||
264 | { .rfmax = 419700, .val = 0x04 }, | ||
265 | { .rfmax = 432400, .val = 0x03 }, | ||
266 | { .rfmax = 445100, .val = 0x02 }, | ||
267 | { .rfmax = 457800, .val = 0x01 }, | ||
268 | { .rfmax = 476300, .val = 0x19 }, | ||
269 | { .rfmax = 494800, .val = 0x18 }, | ||
270 | { .rfmax = 513300, .val = 0x17 }, | ||
271 | { .rfmax = 531800, .val = 0x16 }, | ||
272 | { .rfmax = 550300, .val = 0x15 }, | ||
273 | { .rfmax = 568900, .val = 0x14 }, | ||
274 | { .rfmax = 587400, .val = 0x13 }, | ||
275 | { .rfmax = 605900, .val = 0x12 }, | ||
276 | { .rfmax = 624400, .val = 0x11 }, | ||
277 | { .rfmax = 642900, .val = 0x10 }, | ||
278 | { .rfmax = 661400, .val = 0x0f }, | ||
279 | { .rfmax = 679900, .val = 0x0e }, | ||
280 | { .rfmax = 698400, .val = 0x0d }, | ||
281 | { .rfmax = 716900, .val = 0x0c }, | ||
282 | { .rfmax = 735400, .val = 0x0b }, | ||
283 | { .rfmax = 753900, .val = 0x0a }, | ||
284 | { .rfmax = 772500, .val = 0x09 }, | ||
285 | { .rfmax = 791000, .val = 0x08 }, | ||
286 | { .rfmax = 809500, .val = 0x07 }, | ||
287 | { .rfmax = 828000, .val = 0x06 }, | ||
288 | { .rfmax = 846500, .val = 0x05 }, | ||
289 | { .rfmax = 865000, .val = 0x04 }, | ||
290 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
291 | }; | ||
292 | |||
293 | static struct tda18271_map tda18271_rf_cal[] = { | ||
294 | { .rfmax = 41000, .val = 0x1e }, | ||
295 | { .rfmax = 43000, .val = 0x30 }, | ||
296 | { .rfmax = 45000, .val = 0x43 }, | ||
297 | { .rfmax = 46000, .val = 0x4d }, | ||
298 | { .rfmax = 47000, .val = 0x54 }, | ||
299 | { .rfmax = 47900, .val = 0x64 }, | ||
300 | { .rfmax = 49100, .val = 0x20 }, | ||
301 | { .rfmax = 50000, .val = 0x22 }, | ||
302 | { .rfmax = 51000, .val = 0x2a }, | ||
303 | { .rfmax = 53000, .val = 0x32 }, | ||
304 | { .rfmax = 55000, .val = 0x35 }, | ||
305 | { .rfmax = 56000, .val = 0x3c }, | ||
306 | { .rfmax = 57000, .val = 0x3f }, | ||
307 | { .rfmax = 58000, .val = 0x48 }, | ||
308 | { .rfmax = 59000, .val = 0x4d }, | ||
309 | { .rfmax = 60000, .val = 0x58 }, | ||
310 | { .rfmax = 61100, .val = 0x5f }, | ||
311 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
312 | }; | ||
313 | |||
314 | /*---------------------------------------------------------------------*/ | ||
315 | |||
316 | #define TDA18271_NUM_REGS 39 | ||
317 | |||
318 | #define TDA18271_ANALOG 0 | ||
319 | #define TDA18271_DIGITAL 1 | ||
320 | |||
321 | struct tda18271_priv { | ||
322 | u8 i2c_addr; | ||
323 | struct i2c_adapter *i2c_adap; | ||
324 | unsigned char tda18271_regs[TDA18271_NUM_REGS]; | ||
325 | int mode; | ||
326 | |||
327 | u32 frequency; | ||
328 | u32 bandwidth; | ||
329 | }; | ||
330 | |||
331 | /*---------------------------------------------------------------------*/ | ||
332 | |||
333 | static void tda18271_dump_regs(struct dvb_frontend *fe) | ||
334 | { | ||
335 | struct tda18271_priv *priv = fe->tuner_priv; | ||
336 | unsigned char *regs = priv->tda18271_regs; | ||
337 | |||
338 | tuner_dbg("=== TDA18271 REG DUMP ===\n"); | ||
339 | tuner_dbg("ID_BYTE = 0x%x\n", 0xff & regs[R_ID]); | ||
340 | tuner_dbg("THERMO_BYTE = 0x%x\n", 0xff & regs[R_TM]); | ||
341 | tuner_dbg("POWER_LEVEL_BYTE = 0x%x\n", 0xff & regs[R_PL]); | ||
342 | tuner_dbg("EASY_PROG_BYTE_1 = 0x%x\n", 0xff & regs[R_EP1]); | ||
343 | tuner_dbg("EASY_PROG_BYTE_2 = 0x%x\n", 0xff & regs[R_EP2]); | ||
344 | tuner_dbg("EASY_PROG_BYTE_3 = 0x%x\n", 0xff & regs[R_EP3]); | ||
345 | tuner_dbg("EASY_PROG_BYTE_4 = 0x%x\n", 0xff & regs[R_EP4]); | ||
346 | tuner_dbg("EASY_PROG_BYTE_5 = 0x%x\n", 0xff & regs[R_EP5]); | ||
347 | tuner_dbg("CAL_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_CPD]); | ||
348 | tuner_dbg("CAL_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_CD1]); | ||
349 | tuner_dbg("CAL_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_CD2]); | ||
350 | tuner_dbg("CAL_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_CD3]); | ||
351 | tuner_dbg("MAIN_POST_DIV_BYTE = 0x%x\n", 0xff & regs[R_MPD]); | ||
352 | tuner_dbg("MAIN_DIV_BYTE_1 = 0x%x\n", 0xff & regs[R_MD1]); | ||
353 | tuner_dbg("MAIN_DIV_BYTE_2 = 0x%x\n", 0xff & regs[R_MD2]); | ||
354 | tuner_dbg("MAIN_DIV_BYTE_3 = 0x%x\n", 0xff & regs[R_MD3]); | ||
355 | } | ||
356 | |||
357 | static void tda18271_read_regs(struct dvb_frontend *fe) | ||
358 | { | ||
359 | struct tda18271_priv *priv = fe->tuner_priv; | ||
360 | unsigned char *regs = priv->tda18271_regs; | ||
361 | unsigned char buf = 0x00; | ||
362 | int ret; | ||
363 | struct i2c_msg msg[] = { | ||
364 | { .addr = priv->i2c_addr, .flags = 0, | ||
365 | .buf = &buf, .len = 1 }, | ||
366 | { .addr = priv->i2c_addr, .flags = I2C_M_RD, | ||
367 | .buf = regs, .len = 16 } | ||
368 | }; | ||
369 | |||
370 | if (fe->ops.i2c_gate_ctrl) | ||
371 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
372 | |||
373 | /* read all registers */ | ||
374 | ret = i2c_transfer(priv->i2c_adap, msg, 2); | ||
375 | |||
376 | if (fe->ops.i2c_gate_ctrl) | ||
377 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
378 | |||
379 | if (ret != 2) | ||
380 | printk("ERROR: %s: i2c_transfer returned: %d\n", | ||
381 | __FUNCTION__, ret); | ||
382 | |||
383 | if (debug > 1) | ||
384 | tda18271_dump_regs(fe); | ||
385 | } | ||
386 | |||
387 | static void tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) | ||
388 | { | ||
389 | struct tda18271_priv *priv = fe->tuner_priv; | ||
390 | unsigned char *regs = priv->tda18271_regs; | ||
391 | unsigned char buf[TDA18271_NUM_REGS+1]; | ||
392 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
393 | .buf = buf, .len = len+1 }; | ||
394 | int i, ret; | ||
395 | |||
396 | BUG_ON((len == 0) || (idx+len > sizeof(buf))); | ||
397 | |||
398 | buf[0] = idx; | ||
399 | for (i = 1; i <= len; i++) { | ||
400 | buf[i] = regs[idx-1+i]; | ||
401 | } | ||
402 | |||
403 | if (fe->ops.i2c_gate_ctrl) | ||
404 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
405 | |||
406 | /* write registers */ | ||
407 | ret = i2c_transfer(priv->i2c_adap, &msg, 1); | ||
408 | |||
409 | if (fe->ops.i2c_gate_ctrl) | ||
410 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
411 | |||
412 | if (ret != 1) | ||
413 | printk(KERN_WARNING "ERROR: %s: i2c_transfer returned: %d\n", | ||
414 | __FUNCTION__, ret); | ||
415 | } | ||
416 | |||
417 | /*---------------------------------------------------------------------*/ | ||
418 | |||
419 | static void tda18271_init_regs(struct dvb_frontend *fe) | ||
420 | { | ||
421 | struct tda18271_priv *priv = fe->tuner_priv; | ||
422 | unsigned char *regs = priv->tda18271_regs; | ||
423 | |||
424 | tda18271_read_regs(fe); | ||
425 | |||
426 | /* test IR_CAL_OK to see if we need init */ | ||
427 | if ((regs[R_EP1] & 0x08) != 0) | ||
428 | return; | ||
429 | |||
430 | printk(KERN_INFO "tda18271: initializing registers\n"); | ||
431 | |||
432 | /* initialize registers */ | ||
433 | regs[R_ID] = 0x83; | ||
434 | regs[R_TM] = 0x08; | ||
435 | regs[R_PL] = 0x80; | ||
436 | regs[R_EP1] = 0xc6; | ||
437 | regs[R_EP2] = 0xdf; | ||
438 | regs[R_EP3] = 0x16; | ||
439 | regs[R_EP4] = 0x60; | ||
440 | regs[R_EP5] = 0x80; | ||
441 | regs[R_CPD] = 0x80; | ||
442 | regs[R_CD1] = 0x00; | ||
443 | regs[R_CD2] = 0x00; | ||
444 | regs[R_CD3] = 0x00; | ||
445 | regs[R_MPD] = 0x00; | ||
446 | regs[R_MD1] = 0x00; | ||
447 | regs[R_MD2] = 0x00; | ||
448 | regs[R_MD3] = 0x00; | ||
449 | regs[R_EB1] = 0xff; | ||
450 | regs[R_EB2] = 0x01; | ||
451 | regs[R_EB3] = 0x84; | ||
452 | regs[R_EB4] = 0x41; | ||
453 | regs[R_EB5] = 0x01; | ||
454 | regs[R_EB6] = 0x84; | ||
455 | regs[R_EB7] = 0x40; | ||
456 | regs[R_EB8] = 0x07; | ||
457 | regs[R_EB9] = 0x00; | ||
458 | regs[R_EB10] = 0x00; | ||
459 | regs[R_EB11] = 0x96; | ||
460 | regs[R_EB12] = 0x0f; | ||
461 | regs[R_EB13] = 0xc1; | ||
462 | regs[R_EB14] = 0x00; | ||
463 | regs[R_EB15] = 0x8f; | ||
464 | regs[R_EB16] = 0x00; | ||
465 | regs[R_EB17] = 0x00; | ||
466 | regs[R_EB18] = 0x00; | ||
467 | regs[R_EB19] = 0x00; | ||
468 | regs[R_EB20] = 0x20; | ||
469 | regs[R_EB21] = 0x33; | ||
470 | regs[R_EB22] = 0x48; | ||
471 | regs[R_EB23] = 0xb0; | ||
472 | |||
473 | tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); | ||
474 | /* setup AGC1 & AGC2 */ | ||
475 | regs[R_EB17] = 0x00; | ||
476 | tda18271_write_regs(fe, R_EB17, 1); | ||
477 | regs[R_EB17] = 0x03; | ||
478 | tda18271_write_regs(fe, R_EB17, 1); | ||
479 | regs[R_EB17] = 0x43; | ||
480 | tda18271_write_regs(fe, R_EB17, 1); | ||
481 | regs[R_EB17] = 0x4c; | ||
482 | tda18271_write_regs(fe, R_EB17, 1); | ||
483 | |||
484 | regs[R_EB20] = 0xa0; | ||
485 | tda18271_write_regs(fe, R_EB20, 1); | ||
486 | regs[R_EB20] = 0xa7; | ||
487 | tda18271_write_regs(fe, R_EB20, 1); | ||
488 | regs[R_EB20] = 0xe7; | ||
489 | tda18271_write_regs(fe, R_EB20, 1); | ||
490 | regs[R_EB20] = 0xec; | ||
491 | tda18271_write_regs(fe, R_EB20, 1); | ||
492 | |||
493 | /* image rejection calibration */ | ||
494 | |||
495 | /* low-band */ | ||
496 | regs[R_EP3] = 0x1f; | ||
497 | regs[R_EP4] = 0x66; | ||
498 | regs[R_EP5] = 0x81; | ||
499 | regs[R_CPD] = 0xcc; | ||
500 | regs[R_CD1] = 0x6c; | ||
501 | regs[R_CD2] = 0x00; | ||
502 | regs[R_CD3] = 0x00; | ||
503 | regs[R_MPD] = 0xcd; | ||
504 | regs[R_MD1] = 0x77; | ||
505 | regs[R_MD2] = 0x08; | ||
506 | regs[R_MD3] = 0x00; | ||
507 | |||
508 | tda18271_write_regs(fe, R_EP3, 11); | ||
509 | msleep(5); /* pll locking */ | ||
510 | |||
511 | regs[R_EP1] = 0xc6; | ||
512 | tda18271_write_regs(fe, R_EP1, 1); | ||
513 | msleep(5); /* wanted low measurement */ | ||
514 | |||
515 | regs[R_EP3] = 0x1f; | ||
516 | regs[R_EP4] = 0x66; | ||
517 | regs[R_EP5] = 0x85; | ||
518 | regs[R_CPD] = 0xcb; | ||
519 | regs[R_CD1] = 0x66; | ||
520 | regs[R_CD2] = 0x70; | ||
521 | regs[R_CD3] = 0x00; | ||
522 | |||
523 | tda18271_write_regs(fe, R_EP3, 7); | ||
524 | msleep(5); /* pll locking */ | ||
525 | |||
526 | regs[R_EP2] = 0xdf; | ||
527 | tda18271_write_regs(fe, R_EP2, 1); | ||
528 | msleep(30); /* image low optimization completion */ | ||
529 | |||
530 | /* mid-band */ | ||
531 | regs[R_EP3] = 0x1f; | ||
532 | regs[R_EP4] = 0x66; | ||
533 | regs[R_EP5] = 0x82; | ||
534 | regs[R_CPD] = 0xa8; | ||
535 | regs[R_CD1] = 0x66; | ||
536 | regs[R_CD2] = 0x00; | ||
537 | regs[R_CD3] = 0x00; | ||
538 | regs[R_MPD] = 0xa9; | ||
539 | regs[R_MD1] = 0x73; | ||
540 | regs[R_MD2] = 0x1a; | ||
541 | regs[R_MD3] = 0x00; | ||
542 | |||
543 | tda18271_write_regs(fe, R_EP3, 11); | ||
544 | msleep(5); /* pll locking */ | ||
545 | |||
546 | regs[R_EP1] = 0xc6; | ||
547 | tda18271_write_regs(fe, R_EP1, 1); | ||
548 | msleep(5); /* wanted mid measurement */ | ||
549 | |||
550 | regs[R_EP3] = 0x1f; | ||
551 | regs[R_EP4] = 0x66; | ||
552 | regs[R_EP5] = 0x86; | ||
553 | regs[R_CPD] = 0xa8; | ||
554 | regs[R_CD1] = 0x66; | ||
555 | regs[R_CD2] = 0xa0; | ||
556 | regs[R_CD3] = 0x00; | ||
557 | |||
558 | tda18271_write_regs(fe, R_EP3, 7); | ||
559 | msleep(5); /* pll locking */ | ||
560 | |||
561 | regs[R_EP2] = 0xdf; | ||
562 | tda18271_write_regs(fe, R_EP2, 1); | ||
563 | msleep(30); /* image mid optimization completion */ | ||
564 | |||
565 | /* high-band */ | ||
566 | regs[R_EP3] = 0x1f; | ||
567 | regs[R_EP4] = 0x66; | ||
568 | regs[R_EP5] = 0x83; | ||
569 | regs[R_CPD] = 0x98; | ||
570 | regs[R_CD1] = 0x65; | ||
571 | regs[R_CD2] = 0x00; | ||
572 | regs[R_CD3] = 0x00; | ||
573 | regs[R_MPD] = 0x99; | ||
574 | regs[R_MD1] = 0x71; | ||
575 | regs[R_MD2] = 0xcd; | ||
576 | regs[R_MD3] = 0x00; | ||
577 | |||
578 | tda18271_write_regs(fe, R_EP3, 11); | ||
579 | msleep(5); /* pll locking */ | ||
580 | |||
581 | regs[R_EP1] = 0xc6; | ||
582 | tda18271_write_regs(fe, R_EP1, 1); | ||
583 | msleep(5); /* wanted high measurement */ | ||
584 | |||
585 | regs[R_EP3] = 0x1f; | ||
586 | regs[R_EP4] = 0x66; | ||
587 | regs[R_EP5] = 0x87; | ||
588 | regs[R_CPD] = 0x98; | ||
589 | regs[R_CD1] = 0x65; | ||
590 | regs[R_CD2] = 0x50; | ||
591 | regs[R_CD3] = 0x00; | ||
592 | |||
593 | tda18271_write_regs(fe, R_EP3, 7); | ||
594 | msleep(5); /* pll locking */ | ||
595 | |||
596 | regs[R_EP2] = 0xdf; | ||
597 | |||
598 | tda18271_write_regs(fe, R_EP2, 1); | ||
599 | msleep(30); /* image high optimization completion */ | ||
600 | |||
601 | regs[R_EP4] = 0x64; | ||
602 | tda18271_write_regs(fe, R_EP4, 1); | ||
603 | |||
604 | regs[R_EP1] = 0xc6; | ||
605 | tda18271_write_regs(fe, R_EP1, 1); | ||
606 | } | ||
607 | |||
608 | static int tda18271_tune(struct dvb_frontend *fe, | ||
609 | u32 ifc, u32 freq, u32 bw, u8 std) | ||
610 | { | ||
611 | struct tda18271_priv *priv = fe->tuner_priv; | ||
612 | unsigned char *regs = priv->tda18271_regs; | ||
613 | u32 div, N = 0; | ||
614 | int i; | ||
615 | |||
616 | |||
617 | tuner_dbg("%s: freq = %d, ifc = %d\n", __FUNCTION__, freq, ifc); | ||
618 | |||
619 | tda18271_init_regs(fe); | ||
620 | /* RF tracking filter calibration */ | ||
621 | |||
622 | /* calculate BP_Filter */ | ||
623 | i = 0; | ||
624 | while ((tda18271_bp_filter[i].rfmax * 1000) < freq) { | ||
625 | if (tda18271_bp_filter[i + 1].rfmax == 0) | ||
626 | break; | ||
627 | i++; | ||
628 | } | ||
629 | tuner_extra_dbg("bp filter = 0x%x, i = %d\n", | ||
630 | tda18271_bp_filter[i].val, i); | ||
631 | |||
632 | regs[R_EP1] &= ~0x07; /* clear bp filter bits */ | ||
633 | regs[R_EP1] |= tda18271_bp_filter[i].val; | ||
634 | tda18271_write_regs(fe, R_EP1, 1); | ||
635 | |||
636 | regs[R_EB4] &= 0x07; | ||
637 | regs[R_EB4] |= 0x60; | ||
638 | tda18271_write_regs(fe, R_EB4, 1); | ||
639 | |||
640 | regs[R_EB7] = 0x60; | ||
641 | tda18271_write_regs(fe, R_EB7, 1); | ||
642 | |||
643 | regs[R_EB14] = 0x00; | ||
644 | tda18271_write_regs(fe, R_EB14, 1); | ||
645 | |||
646 | regs[R_EB20] = 0xcc; | ||
647 | tda18271_write_regs(fe, R_EB20, 1); | ||
648 | |||
649 | /* set CAL mode to RF tracking filter calibration */ | ||
650 | regs[R_EB4] |= 0x03; | ||
651 | |||
652 | /* calculate CAL PLL */ | ||
653 | |||
654 | switch (priv->mode) { | ||
655 | case TDA18271_ANALOG: | ||
656 | N = freq - 1250000; | ||
657 | break; | ||
658 | case TDA18271_DIGITAL: | ||
659 | N = freq + bw / 2; | ||
660 | break; | ||
661 | } | ||
662 | |||
663 | i = 0; | ||
664 | while ((tda18271_cal_pll[i].lomax * 1000) < N) { | ||
665 | if (tda18271_cal_pll[i + 1].lomax == 0) | ||
666 | break; | ||
667 | i++; | ||
668 | } | ||
669 | tuner_extra_dbg("cal pll, pd = 0x%x, d = 0x%x, i = %d\n", | ||
670 | tda18271_cal_pll[i].pd, tda18271_cal_pll[i].d, i); | ||
671 | |||
672 | regs[R_CPD] = tda18271_cal_pll[i].pd; | ||
673 | |||
674 | div = ((tda18271_cal_pll[i].d * (N / 1000)) << 7) / 125; | ||
675 | regs[R_CD1] = 0xff & (div >> 16); | ||
676 | regs[R_CD2] = 0xff & (div >> 8); | ||
677 | regs[R_CD3] = 0xff & div; | ||
678 | |||
679 | /* calculate MAIN PLL */ | ||
680 | |||
681 | switch (priv->mode) { | ||
682 | case TDA18271_ANALOG: | ||
683 | N = freq - 250000; | ||
684 | break; | ||
685 | case TDA18271_DIGITAL: | ||
686 | N = freq + bw / 2 + 1000000; | ||
687 | break; | ||
688 | } | ||
689 | |||
690 | i = 0; | ||
691 | while ((tda18271_main_pll[i].lomax * 1000) < N) { | ||
692 | if (tda18271_main_pll[i + 1].lomax == 0) | ||
693 | break; | ||
694 | i++; | ||
695 | } | ||
696 | tuner_extra_dbg("main pll, pd = 0x%x, d = 0x%x, i = %d\n", | ||
697 | tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); | ||
698 | |||
699 | regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); | ||
700 | |||
701 | switch (priv->mode) { | ||
702 | case TDA18271_ANALOG: | ||
703 | regs[R_MPD] &= ~0x08; | ||
704 | break; | ||
705 | case TDA18271_DIGITAL: | ||
706 | regs[R_MPD] |= 0x08; | ||
707 | break; | ||
708 | } | ||
709 | |||
710 | div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; | ||
711 | regs[R_MD1] = 0xff & (div >> 16); | ||
712 | regs[R_MD2] = 0xff & (div >> 8); | ||
713 | regs[R_MD3] = 0xff & div; | ||
714 | |||
715 | tda18271_write_regs(fe, R_EP3, 11); | ||
716 | msleep(5); /* RF tracking filter calibration initialization */ | ||
717 | |||
718 | /* search for K,M,CO for RF Calibration */ | ||
719 | i = 0; | ||
720 | while ((tda18271_km[i].rfmax * 1000) < freq) { | ||
721 | if (tda18271_km[i + 1].rfmax == 0) | ||
722 | break; | ||
723 | i++; | ||
724 | } | ||
725 | tuner_extra_dbg("km = 0x%x, i = %d\n", tda18271_km[i].val, i); | ||
726 | |||
727 | regs[R_EB13] &= 0x83; | ||
728 | regs[R_EB13] |= tda18271_km[i].val; | ||
729 | tda18271_write_regs(fe, R_EB13, 1); | ||
730 | |||
731 | /* search for RF_BAND */ | ||
732 | i = 0; | ||
733 | while ((tda18271_rf_band[i].rfmax * 1000) < freq) { | ||
734 | if (tda18271_rf_band[i + 1].rfmax == 0) | ||
735 | break; | ||
736 | i++; | ||
737 | } | ||
738 | tuner_extra_dbg("rf band = 0x%x, i = %d\n", | ||
739 | tda18271_rf_band[i].val, i); | ||
740 | |||
741 | regs[R_EP2] &= ~0xe0; /* clear rf band bits */ | ||
742 | regs[R_EP2] |= (tda18271_rf_band[i].val << 5); | ||
743 | |||
744 | /* search for Gain_Taper */ | ||
745 | i = 0; | ||
746 | while ((tda18271_gain_taper[i].rfmax * 1000) < freq) { | ||
747 | if (tda18271_gain_taper[i + 1].rfmax == 0) | ||
748 | break; | ||
749 | i++; | ||
750 | } | ||
751 | tuner_extra_dbg("gain taper = 0x%x, i = %d\n", | ||
752 | tda18271_gain_taper[i].val, i); | ||
753 | |||
754 | regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ | ||
755 | regs[R_EP2] |= tda18271_gain_taper[i].val; | ||
756 | |||
757 | tda18271_write_regs(fe, R_EP2, 1); | ||
758 | tda18271_write_regs(fe, R_EP1, 1); | ||
759 | tda18271_write_regs(fe, R_EP2, 1); | ||
760 | tda18271_write_regs(fe, R_EP1, 1); | ||
761 | |||
762 | regs[R_EB4] &= 0x07; | ||
763 | regs[R_EB4] |= 0x40; | ||
764 | tda18271_write_regs(fe, R_EB4, 1); | ||
765 | |||
766 | regs[R_EB7] = 0x40; | ||
767 | tda18271_write_regs(fe, R_EB7, 1); | ||
768 | msleep(10); | ||
769 | |||
770 | regs[R_EB20] = 0xec; | ||
771 | tda18271_write_regs(fe, R_EB20, 1); | ||
772 | msleep(60); /* RF tracking filter calibration completion */ | ||
773 | |||
774 | regs[R_EP4] &= ~0x03; /* set cal mode to normal */ | ||
775 | tda18271_write_regs(fe, R_EP4, 1); | ||
776 | |||
777 | tda18271_write_regs(fe, R_EP1, 1); | ||
778 | |||
779 | /* RF tracking filer correction for VHF_Low band */ | ||
780 | i = 0; | ||
781 | while ((tda18271_rf_cal[i].rfmax * 1000) < freq) { | ||
782 | if (tda18271_rf_cal[i].rfmax == 0) | ||
783 | break; | ||
784 | i++; | ||
785 | } | ||
786 | tuner_extra_dbg("rf cal = 0x%x, i = %d\n", tda18271_rf_cal[i].val, i); | ||
787 | |||
788 | /* VHF_Low band only */ | ||
789 | if (tda18271_rf_cal[i].rfmax != 0) { | ||
790 | regs[R_EB14] = tda18271_rf_cal[i].val; | ||
791 | tda18271_write_regs(fe, R_EB14, 1); | ||
792 | } | ||
793 | |||
794 | /* Channel Configuration */ | ||
795 | |||
796 | switch (priv->mode) { | ||
797 | case TDA18271_ANALOG: | ||
798 | regs[R_EB22] = 0x2c; | ||
799 | break; | ||
800 | case TDA18271_DIGITAL: | ||
801 | regs[R_EB22] = 0x37; | ||
802 | break; | ||
803 | } | ||
804 | tda18271_write_regs(fe, R_EB22, 1); | ||
805 | |||
806 | regs[R_EP1] |= 0x40; /* set dis power level on */ | ||
807 | |||
808 | /* set standard */ | ||
809 | regs[R_EP3] &= ~0x1f; /* clear std bits */ | ||
810 | |||
811 | /* see table 22 */ | ||
812 | regs[R_EP3] |= std; | ||
813 | |||
814 | /* TO DO: * | ||
815 | * ================ * | ||
816 | * FM radio, 0x18 * | ||
817 | * ATSC 6MHz, 0x1c * | ||
818 | * DVB-T 6MHz, 0x1c * | ||
819 | * DVB-T 7MHz, 0x1d * | ||
820 | * DVB-T 8MHz, 0x1e * | ||
821 | * QAM 6MHz, 0x1d * | ||
822 | * QAM 8MHz, 0x1f */ | ||
823 | |||
824 | regs[R_EP4] &= ~0x03; /* set cal mode to normal */ | ||
825 | |||
826 | regs[R_EP4] &= ~0x1c; /* clear if level bits */ | ||
827 | switch (priv->mode) { | ||
828 | case TDA18271_ANALOG: | ||
829 | regs[R_MPD] &= ~0x80; /* IF notch = 0 */ | ||
830 | break; | ||
831 | case TDA18271_DIGITAL: | ||
832 | regs[R_EP4] |= 0x04; | ||
833 | regs[R_MPD] |= 0x80; | ||
834 | break; | ||
835 | } | ||
836 | |||
837 | regs[R_EP4] &= ~0x80; /* turn this bit on only for fm */ | ||
838 | |||
839 | /* FIXME: image rejection validity EP5[2:0] */ | ||
840 | |||
841 | /* calculate MAIN PLL */ | ||
842 | N = freq + ifc; | ||
843 | |||
844 | i = 0; | ||
845 | while ((tda18271_main_pll[i].lomax * 1000) < N) { | ||
846 | if (tda18271_main_pll[i + 1].lomax == 0) | ||
847 | break; | ||
848 | i++; | ||
849 | } | ||
850 | tuner_extra_dbg("main pll, pd = 0x%x, d = 0x%x, i = %d\n", | ||
851 | tda18271_main_pll[i].pd, tda18271_main_pll[i].d, i); | ||
852 | |||
853 | regs[R_MPD] = (0x7f & tda18271_main_pll[i].pd); | ||
854 | switch (priv->mode) { | ||
855 | case TDA18271_ANALOG: | ||
856 | regs[R_MPD] &= ~0x08; | ||
857 | break; | ||
858 | case TDA18271_DIGITAL: | ||
859 | regs[R_MPD] |= 0x08; | ||
860 | break; | ||
861 | } | ||
862 | |||
863 | div = ((tda18271_main_pll[i].d * (N / 1000)) << 7) / 125; | ||
864 | regs[R_MD1] = 0xff & (div >> 16); | ||
865 | regs[R_MD2] = 0xff & (div >> 8); | ||
866 | regs[R_MD3] = 0xff & div; | ||
867 | |||
868 | tda18271_write_regs(fe, R_TM, 15); | ||
869 | msleep(5); | ||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | /* ------------------------------------------------------------------ */ | ||
874 | |||
875 | static int tda18271_set_params(struct dvb_frontend *fe, | ||
876 | struct dvb_frontend_parameters *params) | ||
877 | { | ||
878 | struct tda18271_priv *priv = fe->tuner_priv; | ||
879 | u8 std; | ||
880 | u32 bw, sgIF = 0; | ||
881 | |||
882 | u32 freq = params->frequency; | ||
883 | |||
884 | priv->mode = TDA18271_DIGITAL; | ||
885 | |||
886 | /* see table 22 */ | ||
887 | if (fe->ops.info.type == FE_ATSC) { | ||
888 | switch (params->u.vsb.modulation) { | ||
889 | case VSB_8: | ||
890 | case VSB_16: | ||
891 | std = 0x1b; /* device-specific (spec says 0x1c) */ | ||
892 | sgIF = 5380000; | ||
893 | break; | ||
894 | case QAM_64: | ||
895 | case QAM_256: | ||
896 | std = 0x18; /* device-specific (spec says 0x1d) */ | ||
897 | sgIF = 4000000; | ||
898 | break; | ||
899 | default: | ||
900 | printk(KERN_WARNING "%s: modulation not set!\n", | ||
901 | __FUNCTION__); | ||
902 | return -EINVAL; | ||
903 | } | ||
904 | freq += 1750000; /* Adjust to center (+1.75MHZ) */ | ||
905 | bw = 6000000; | ||
906 | } else if (fe->ops.info.type == FE_OFDM) { | ||
907 | switch (params->u.ofdm.bandwidth) { | ||
908 | case BANDWIDTH_6_MHZ: | ||
909 | std = 0x1c; | ||
910 | bw = 6000000; | ||
911 | break; | ||
912 | case BANDWIDTH_7_MHZ: | ||
913 | std = 0x1d; | ||
914 | bw = 7000000; | ||
915 | break; | ||
916 | case BANDWIDTH_8_MHZ: | ||
917 | std = 0x1e; | ||
918 | bw = 8000000; | ||
919 | break; | ||
920 | default: | ||
921 | printk(KERN_WARNING "%s: bandwidth not set!\n", | ||
922 | __FUNCTION__); | ||
923 | return -EINVAL; | ||
924 | } | ||
925 | } else { | ||
926 | printk(KERN_WARNING "%s: modulation type not supported!\n", | ||
927 | __FUNCTION__); | ||
928 | return -EINVAL; | ||
929 | } | ||
930 | |||
931 | return tda18271_tune(fe, sgIF, freq, bw, std); | ||
932 | } | ||
933 | |||
934 | static int tda18271_set_analog_params(struct dvb_frontend *fe, | ||
935 | struct analog_parameters *params) | ||
936 | { | ||
937 | struct tda18271_priv *priv = fe->tuner_priv; | ||
938 | u8 std; | ||
939 | unsigned int sgIF; | ||
940 | char *mode; | ||
941 | |||
942 | priv->mode = TDA18271_ANALOG; | ||
943 | |||
944 | /* see table 22 */ | ||
945 | if (params->std & V4L2_STD_MN) { | ||
946 | std = 0x0d; | ||
947 | sgIF = 92; | ||
948 | mode = "MN"; | ||
949 | } else if (params->std & V4L2_STD_B) { | ||
950 | std = 0x0e; | ||
951 | sgIF = 108; | ||
952 | mode = "B"; | ||
953 | } else if (params->std & V4L2_STD_GH) { | ||
954 | std = 0x0f; | ||
955 | sgIF = 124; | ||
956 | mode = "GH"; | ||
957 | } else if (params->std & V4L2_STD_PAL_I) { | ||
958 | std = 0x0f; | ||
959 | sgIF = 124; | ||
960 | mode = "I"; | ||
961 | } else if (params->std & V4L2_STD_DK) { | ||
962 | std = 0x0f; | ||
963 | sgIF = 124; | ||
964 | mode = "DK"; | ||
965 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
966 | std = 0x0f; | ||
967 | sgIF = 124; | ||
968 | mode = "L"; | ||
969 | } else if (params->std & V4L2_STD_SECAM_LC) { | ||
970 | std = 0x0f; | ||
971 | sgIF = 20; | ||
972 | mode = "LC"; | ||
973 | } else { | ||
974 | std = 0x0f; | ||
975 | sgIF = 124; | ||
976 | mode = "xx"; | ||
977 | } | ||
978 | |||
979 | if (params->mode == V4L2_TUNER_RADIO) | ||
980 | sgIF = 88; /* if frequency is 5.5 MHz */ | ||
981 | |||
982 | tuner_dbg("setting tda18271 to system %s\n", mode); | ||
983 | |||
984 | return tda18271_tune(fe, sgIF * 62500, params->frequency * 62500, | ||
985 | 0, std); | ||
986 | } | ||
987 | |||
988 | static int tda18271_release(struct dvb_frontend *fe) | ||
989 | { | ||
990 | kfree(fe->tuner_priv); | ||
991 | fe->tuner_priv = NULL; | ||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
996 | { | ||
997 | struct tda18271_priv *priv = fe->tuner_priv; | ||
998 | *frequency = priv->frequency; | ||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
1003 | { | ||
1004 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1005 | *bandwidth = priv->bandwidth; | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static struct dvb_tuner_ops tda18271_tuner_ops = { | ||
1010 | .info = { | ||
1011 | .name = "NXP TDA18271HD", | ||
1012 | .frequency_min = 45000000, | ||
1013 | .frequency_max = 864000000, | ||
1014 | .frequency_step = 62500 | ||
1015 | }, | ||
1016 | .set_params = tda18271_set_params, | ||
1017 | .set_analog_params = tda18271_set_analog_params, | ||
1018 | .release = tda18271_release, | ||
1019 | .get_frequency = tda18271_get_frequency, | ||
1020 | .get_bandwidth = tda18271_get_bandwidth, | ||
1021 | }; | ||
1022 | |||
1023 | struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | ||
1024 | struct i2c_adapter *i2c) | ||
1025 | { | ||
1026 | struct tda18271_priv *priv = NULL; | ||
1027 | |||
1028 | tuner_dbg("%s:\n", __FUNCTION__); | ||
1029 | priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); | ||
1030 | if (priv == NULL) | ||
1031 | return NULL; | ||
1032 | |||
1033 | priv->i2c_addr = addr; | ||
1034 | priv->i2c_adap = i2c; | ||
1035 | |||
1036 | memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, | ||
1037 | sizeof(struct dvb_tuner_ops)); | ||
1038 | |||
1039 | fe->tuner_priv = priv; | ||
1040 | |||
1041 | return fe; | ||
1042 | } | ||
1043 | EXPORT_SYMBOL_GPL(tda18271_attach); | ||
1044 | MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); | ||
1045 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
1046 | MODULE_LICENSE("GPL"); | ||
1047 | |||
1048 | /* | ||
1049 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1050 | * --------------------------------------------------------------------------- | ||
1051 | * Local variables: | ||
1052 | * c-basic-offset: 8 | ||
1053 | * End: | ||
1054 | */ | ||
diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h new file mode 100644 index 000000000000..a8a19a7197f0 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | tda18271.h - header for the Philips / NXP TDA18271 silicon tuner | ||
3 | |||
4 | Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) | ||
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 | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __TDA18271_H__ | ||
22 | #define __TDA18271_H__ | ||
23 | |||
24 | #include <linux/i2c.h> | ||
25 | #include "dvb_frontend.h" | ||
26 | |||
27 | #if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) | ||
28 | extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | ||
29 | struct i2c_adapter *i2c); | ||
30 | #else | ||
31 | static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, | ||
32 | u8 addr, | ||
33 | struct i2c_adapter *i2c) | ||
34 | { | ||
35 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); | ||
36 | return NULL; | ||
37 | } | ||
38 | #endif | ||
39 | |||
40 | #endif /* __TDA18271_H__ */ | ||
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 5d30cbcd7361..a38ed9db6403 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c | |||
@@ -25,8 +25,9 @@ | |||
25 | #include <linux/videodev.h> | 25 | #include <linux/videodev.h> |
26 | #include "tda8290.h" | 26 | #include "tda8290.h" |
27 | #include "tda827x.h" | 27 | #include "tda827x.h" |
28 | #include "tda18271.h" | ||
28 | 29 | ||
29 | static int tuner_debug = 0; | 30 | static int tuner_debug; |
30 | module_param_named(debug, tuner_debug, int, 0644); | 31 | module_param_named(debug, tuner_debug, int, 0644); |
31 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | 32 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); |
32 | 33 | ||
@@ -65,6 +66,34 @@ static void tda8290_i2c_bridge(struct tuner *t, int close) | |||
65 | } | 66 | } |
66 | } | 67 | } |
67 | 68 | ||
69 | static void tda8295_i2c_bridge(struct tuner *t, int close) | ||
70 | { | ||
71 | struct tda8290_priv *priv = t->priv; | ||
72 | |||
73 | unsigned char enable[2] = { 0x45, 0xc1 }; | ||
74 | unsigned char disable[2] = { 0x46, 0x00 }; | ||
75 | unsigned char buf[3] = { 0x45, 0x01, 0x00 }; | ||
76 | unsigned char *msg; | ||
77 | if (close) { | ||
78 | msg = enable; | ||
79 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
80 | /* let the bridge stabilize */ | ||
81 | msleep(20); | ||
82 | } else { | ||
83 | msg = disable; | ||
84 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 1); | ||
85 | tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1); | ||
86 | |||
87 | buf[2] = msg[1]; | ||
88 | buf[2] &= ~0x04; | ||
89 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); | ||
90 | msleep(5); | ||
91 | |||
92 | msg[1] |= 0x04; | ||
93 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
94 | } | ||
95 | } | ||
96 | |||
68 | /*---------------------------------------------------------------------*/ | 97 | /*---------------------------------------------------------------------*/ |
69 | 98 | ||
70 | static void set_audio(struct tuner *t) | 99 | static void set_audio(struct tuner *t) |
@@ -233,6 +262,153 @@ static void tda8290_set_freq(struct tuner *t, unsigned int freq) | |||
233 | 262 | ||
234 | /*---------------------------------------------------------------------*/ | 263 | /*---------------------------------------------------------------------*/ |
235 | 264 | ||
265 | static void tda8295_power(struct tuner *t, int enable) | ||
266 | { | ||
267 | struct tda8290_priv *priv = t->priv; | ||
268 | unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ | ||
269 | |||
270 | tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); | ||
271 | tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); | ||
272 | |||
273 | if (enable) | ||
274 | buf[1] = 0x01; | ||
275 | else | ||
276 | buf[1] = 0x03; | ||
277 | |||
278 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
279 | } | ||
280 | |||
281 | static void tda8295_set_easy_mode(struct tuner *t, int enable) | ||
282 | { | ||
283 | struct tda8290_priv *priv = t->priv; | ||
284 | unsigned char buf[] = { 0x01, 0x00 }; | ||
285 | |||
286 | tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); | ||
287 | tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); | ||
288 | |||
289 | if (enable) | ||
290 | buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ | ||
291 | else | ||
292 | buf[1] = 0x00; /* reset active bit */ | ||
293 | |||
294 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
295 | } | ||
296 | |||
297 | static void tda8295_set_video_std(struct tuner *t) | ||
298 | { | ||
299 | struct tda8290_priv *priv = t->priv; | ||
300 | unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; | ||
301 | |||
302 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
303 | |||
304 | tda8295_set_easy_mode(t, 1); | ||
305 | msleep(20); | ||
306 | tda8295_set_easy_mode(t, 0); | ||
307 | } | ||
308 | |||
309 | /*---------------------------------------------------------------------*/ | ||
310 | |||
311 | static void tda8295_agc1_out(struct tuner *t, int enable) | ||
312 | { | ||
313 | struct tda8290_priv *priv = t->priv; | ||
314 | unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ | ||
315 | |||
316 | tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); | ||
317 | tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); | ||
318 | |||
319 | if (enable) | ||
320 | buf[1] &= ~0x40; | ||
321 | else | ||
322 | buf[1] |= 0x40; | ||
323 | |||
324 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
325 | } | ||
326 | |||
327 | static void tda8295_agc2_out(struct tuner *t, int enable) | ||
328 | { | ||
329 | struct tda8290_priv *priv = t->priv; | ||
330 | unsigned char set_gpio_cf[] = { 0x44, 0x00 }; | ||
331 | unsigned char set_gpio_val[] = { 0x46, 0x00 }; | ||
332 | |||
333 | tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1); | ||
334 | tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1); | ||
335 | tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1); | ||
336 | tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1); | ||
337 | |||
338 | set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ | ||
339 | |||
340 | if (enable) { | ||
341 | set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ | ||
342 | set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ | ||
343 | } | ||
344 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); | ||
345 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); | ||
346 | } | ||
347 | |||
348 | static int tda8295_has_signal(struct tuner *t) | ||
349 | { | ||
350 | struct tda8290_priv *priv = t->priv; | ||
351 | |||
352 | unsigned char hvpll_stat = 0x26; | ||
353 | unsigned char ret; | ||
354 | |||
355 | tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1); | ||
356 | tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1); | ||
357 | return (ret & 0x01) ? 65535 : 0; | ||
358 | } | ||
359 | |||
360 | /*---------------------------------------------------------------------*/ | ||
361 | |||
362 | static void tda8295_set_freq(struct tuner *t, unsigned int freq) | ||
363 | { | ||
364 | struct tda8290_priv *priv = t->priv; | ||
365 | u16 ifc; | ||
366 | |||
367 | unsigned char blanking_mode[] = { 0x1d, 0x00 }; | ||
368 | |||
369 | struct analog_parameters params = { | ||
370 | .frequency = freq, | ||
371 | .mode = t->mode, | ||
372 | .audmode = t->audmode, | ||
373 | .std = t->std | ||
374 | }; | ||
375 | |||
376 | set_audio(t); | ||
377 | |||
378 | ifc = priv->cfg.sgIF; /* FIXME */ | ||
379 | |||
380 | tuner_dbg("%s: ifc = %u, freq = %d\n", __FUNCTION__, ifc, freq); | ||
381 | |||
382 | tda8295_power(t, 1); | ||
383 | tda8295_agc1_out(t, 1); | ||
384 | |||
385 | tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1); | ||
386 | tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1); | ||
387 | |||
388 | tda8295_set_video_std(t); | ||
389 | |||
390 | blanking_mode[1] = 0x03; | ||
391 | tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); | ||
392 | msleep(20); | ||
393 | |||
394 | tda8295_i2c_bridge(t, 1); | ||
395 | |||
396 | if (t->fe.ops.tuner_ops.set_analog_params) | ||
397 | t->fe.ops.tuner_ops.set_analog_params(&t->fe, ¶ms); | ||
398 | |||
399 | if (priv->cfg.agcf) | ||
400 | priv->cfg.agcf(&t->fe); | ||
401 | |||
402 | if (tda8295_has_signal(t)) | ||
403 | tuner_dbg("tda8295 is locked\n"); | ||
404 | else | ||
405 | tuner_dbg("tda8295 not locked, no signal?\n"); | ||
406 | |||
407 | tda8295_i2c_bridge(t, 0); | ||
408 | } | ||
409 | |||
410 | /*---------------------------------------------------------------------*/ | ||
411 | |||
236 | static int tda8290_has_signal(struct tuner *t) | 412 | static int tda8290_has_signal(struct tuner *t) |
237 | { | 413 | { |
238 | struct tda8290_priv *priv = t->priv; | 414 | struct tda8290_priv *priv = t->priv; |
@@ -264,6 +440,13 @@ static void tda8290_standby(struct tuner *t) | |||
264 | tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); | 440 | tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); |
265 | } | 441 | } |
266 | 442 | ||
443 | static void tda8295_standby(struct tuner *t) | ||
444 | { | ||
445 | tda8295_agc1_out(t, 0); /* Put AGC in tri-state */ | ||
446 | |||
447 | tda8295_power(t, 0); | ||
448 | } | ||
449 | |||
267 | static void tda8290_init_if(struct tuner *t) | 450 | static void tda8290_init_if(struct tuner *t) |
268 | { | 451 | { |
269 | struct tda8290_priv *priv = t->priv; | 452 | struct tda8290_priv *priv = t->priv; |
@@ -279,6 +462,35 @@ static void tda8290_init_if(struct tuner *t) | |||
279 | tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); | 462 | tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); |
280 | } | 463 | } |
281 | 464 | ||
465 | static void tda8295_init_if(struct tuner *t) | ||
466 | { | ||
467 | struct tda8290_priv *priv = t->priv; | ||
468 | |||
469 | static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; | ||
470 | static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; | ||
471 | static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; | ||
472 | static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; | ||
473 | static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; | ||
474 | static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; | ||
475 | static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; | ||
476 | |||
477 | tda8295_power(t, 1); | ||
478 | |||
479 | tda8295_set_easy_mode(t, 0); | ||
480 | tda8295_set_video_std(t); | ||
481 | |||
482 | tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); | ||
483 | tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); | ||
484 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); | ||
485 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); | ||
486 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); | ||
487 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); | ||
488 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); | ||
489 | |||
490 | tda8295_agc1_out(t, 0); | ||
491 | tda8295_agc2_out(t, 0); | ||
492 | } | ||
493 | |||
282 | static void tda8290_init_tuner(struct tuner *t) | 494 | static void tda8290_init_tuner(struct tuner *t) |
283 | { | 495 | { |
284 | struct tda8290_priv *priv = t->priv; | 496 | struct tda8290_priv *priv = t->priv; |
@@ -298,7 +510,7 @@ static void tda8290_init_tuner(struct tuner *t) | |||
298 | 510 | ||
299 | /*---------------------------------------------------------------------*/ | 511 | /*---------------------------------------------------------------------*/ |
300 | 512 | ||
301 | static void tda8290_release(struct tuner *t) | 513 | static void tda829x_release(struct tuner *t) |
302 | { | 514 | { |
303 | if (t->fe.ops.tuner_ops.release) | 515 | if (t->fe.ops.tuner_ops.release) |
304 | t->fe.ops.tuner_ops.release(&t->fe); | 516 | t->fe.ops.tuner_ops.release(&t->fe); |
@@ -312,7 +524,15 @@ static struct tuner_operations tda8290_tuner_ops = { | |||
312 | .set_radio_freq = tda8290_set_freq, | 524 | .set_radio_freq = tda8290_set_freq, |
313 | .has_signal = tda8290_has_signal, | 525 | .has_signal = tda8290_has_signal, |
314 | .standby = tda8290_standby, | 526 | .standby = tda8290_standby, |
315 | .release = tda8290_release, | 527 | .release = tda829x_release, |
528 | }; | ||
529 | |||
530 | static struct tuner_operations tda8295_tuner_ops = { | ||
531 | .set_tv_freq = tda8295_set_freq, | ||
532 | .set_radio_freq = tda8295_set_freq, | ||
533 | .has_signal = tda8295_has_signal, | ||
534 | .standby = tda8295_standby, | ||
535 | .release = tda829x_release, | ||
316 | }; | 536 | }; |
317 | 537 | ||
318 | int tda8290_attach(struct tuner *t) | 538 | int tda8290_attach(struct tuner *t) |
@@ -403,6 +623,95 @@ int tda8290_attach(struct tuner *t) | |||
403 | tda8290_init_if(t); | 623 | tda8290_init_if(t); |
404 | return 0; | 624 | return 0; |
405 | } | 625 | } |
626 | EXPORT_SYMBOL_GPL(tda8290_attach); | ||
627 | |||
628 | int tda8295_attach(struct tuner *t) | ||
629 | { | ||
630 | struct tda8290_priv *priv = NULL; | ||
631 | u8 data; | ||
632 | int i, ret, tuners_found; | ||
633 | u32 tuner_addrs; | ||
634 | struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; | ||
635 | |||
636 | priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); | ||
637 | if (priv == NULL) | ||
638 | return -ENOMEM; | ||
639 | t->priv = priv; | ||
640 | |||
641 | priv->i2c_props.addr = t->i2c.addr; | ||
642 | priv->i2c_props.adap = t->i2c.adapter; | ||
643 | |||
644 | tda8295_i2c_bridge(t, 1); | ||
645 | /* probe for tuner chip */ | ||
646 | tuners_found = 0; | ||
647 | tuner_addrs = 0; | ||
648 | for (i = 0x60; i <= 0x63; i++) { | ||
649 | msg.addr = i; | ||
650 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
651 | if (ret == 1) { | ||
652 | tuners_found++; | ||
653 | tuner_addrs = (tuner_addrs << 8) + i; | ||
654 | } | ||
655 | } | ||
656 | /* if there is more than one tuner, we expect the right one is | ||
657 | behind the bridge and we choose the highest address that doesn't | ||
658 | give a response now | ||
659 | */ | ||
660 | tda8295_i2c_bridge(t, 0); | ||
661 | if (tuners_found > 1) | ||
662 | for (i = 0; i < tuners_found; i++) { | ||
663 | msg.addr = tuner_addrs & 0xff; | ||
664 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
665 | if (ret == 1) | ||
666 | tuner_addrs = tuner_addrs >> 8; | ||
667 | else | ||
668 | break; | ||
669 | } | ||
670 | if (tuner_addrs == 0) { | ||
671 | tuner_addrs = 0x60; | ||
672 | tuner_info("could not clearly identify tuner address, " | ||
673 | "defaulting to %x\n", tuner_addrs); | ||
674 | } else { | ||
675 | tuner_addrs = tuner_addrs & 0xff; | ||
676 | tuner_info("setting tuner address to %x\n", tuner_addrs); | ||
677 | } | ||
678 | priv->tda827x_addr = tuner_addrs; | ||
679 | msg.addr = tuner_addrs; | ||
680 | |||
681 | tda8295_i2c_bridge(t, 1); | ||
682 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
683 | tda8295_i2c_bridge(t, 0); | ||
684 | if (ret != 1) | ||
685 | tuner_warn("TDA827x access failed!\n"); | ||
686 | if ((data & 0x3c) == 0) { | ||
687 | strlcpy(t->i2c.name, "tda8295+18271", sizeof(t->i2c.name)); | ||
688 | tda18271_attach(&t->fe, priv->tda827x_addr, | ||
689 | priv->i2c_props.adap); | ||
690 | priv->tda827x_ver = 4; | ||
691 | } else { | ||
692 | strlcpy(t->i2c.name, "tda8295+75a", sizeof(t->i2c.name)); | ||
693 | tda827x_attach(&t->fe, priv->tda827x_addr, | ||
694 | priv->i2c_props.adap, &priv->cfg); | ||
695 | |||
696 | /* FIXME: tda827x module doesn't probe the tuner until | ||
697 | * tda827x_initial_sleep is called | ||
698 | */ | ||
699 | if (t->fe.ops.tuner_ops.sleep) | ||
700 | t->fe.ops.tuner_ops.sleep(&t->fe); | ||
701 | priv->tda827x_ver = 2; | ||
702 | } | ||
703 | priv->tda827x_ver |= 1; /* signifies 8295 vs 8290 */ | ||
704 | tuner_info("type set to %s\n", t->i2c.name); | ||
705 | |||
706 | memcpy(&t->ops, &tda8295_tuner_ops, sizeof(struct tuner_operations)); | ||
707 | |||
708 | priv->cfg.tda827x_lpsel = 0; | ||
709 | t->mode = V4L2_TUNER_ANALOG_TV; | ||
710 | |||
711 | tda8295_init_if(t); | ||
712 | return 0; | ||
713 | } | ||
714 | EXPORT_SYMBOL_GPL(tda8295_attach); | ||
406 | 715 | ||
407 | int tda8290_probe(struct tuner *t) | 716 | int tda8290_probe(struct tuner *t) |
408 | { | 717 | { |
@@ -434,12 +743,10 @@ int tda8290_probe(struct tuner *t) | |||
434 | tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); | 743 | tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); |
435 | return -1; | 744 | return -1; |
436 | } | 745 | } |
437 | |||
438 | EXPORT_SYMBOL_GPL(tda8290_probe); | 746 | EXPORT_SYMBOL_GPL(tda8290_probe); |
439 | EXPORT_SYMBOL_GPL(tda8290_attach); | ||
440 | 747 | ||
441 | MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); | 748 | MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); |
442 | MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); | 749 | MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); |
443 | MODULE_LICENSE("GPL"); | 750 | MODULE_LICENSE("GPL"); |
444 | 751 | ||
445 | /* | 752 | /* |
diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 9b63e62b3a0f..dbbcb0f001e0 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h | |||
@@ -24,6 +24,7 @@ | |||
24 | extern int tda8290_probe(struct tuner *t); | 24 | extern int tda8290_probe(struct tuner *t); |
25 | 25 | ||
26 | extern int tda8290_attach(struct tuner *t); | 26 | extern int tda8290_attach(struct tuner *t); |
27 | extern int tda8295_attach(struct tuner *t); | ||
27 | #else | 28 | #else |
28 | static inline int tda8290_probe(struct tuner *t) | 29 | static inline int tda8290_probe(struct tuner *t) |
29 | { | 30 | { |
@@ -37,6 +38,13 @@ static inline int tda8290_attach(struct tuner *t) | |||
37 | __FUNCTION__); | 38 | __FUNCTION__); |
38 | return -EINVAL; | 39 | return -EINVAL; |
39 | } | 40 | } |
41 | |||
42 | static inline int tda8295_attach(struct tuner *t) | ||
43 | { | ||
44 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
45 | __FUNCTION__); | ||
46 | return -EINVAL; | ||
47 | } | ||
40 | #endif | 48 | #endif |
41 | 49 | ||
42 | #endif /* __TDA8290_H__ */ | 50 | #endif /* __TDA8290_H__ */ |
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 99558c708ae7..6ae8cb205d8e 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -278,6 +278,11 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
278 | tda8290_attach(t); | 278 | tda8290_attach(t); |
279 | break; | 279 | break; |
280 | } | 280 | } |
281 | case TUNER_PHILIPS_TDA8295: | ||
282 | { | ||
283 | tda8295_attach(t); | ||
284 | break; | ||
285 | } | ||
281 | case TUNER_TEA5767: | 286 | case TUNER_TEA5767: |
282 | if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { | 287 | if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { |
283 | t->type = TUNER_ABSENT; | 288 | t->type = TUNER_ABSENT; |
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index ac363f019227..4a674c436cf4 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c | |||
@@ -1475,6 +1475,9 @@ struct tunertype tuners[] = { | |||
1475 | .name = "Philips TEA5761 FM Radio", | 1475 | .name = "Philips TEA5761 FM Radio", |
1476 | /* see tea5767.c for details */ | 1476 | /* see tea5767.c for details */ |
1477 | }, | 1477 | }, |
1478 | [TUNER_PHILIPS_TDA8295] = { /* Philips PAL|NTSC */ | ||
1479 | .name = "tda8295+18271", | ||
1480 | /* see tda8290.c for details */ }, | ||
1478 | }; | 1481 | }; |
1479 | 1482 | ||
1480 | unsigned const int tuner_count = ARRAY_SIZE(tuners); | 1483 | unsigned const int tuner_count = ARRAY_SIZE(tuners); |
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 4b2c4034f5b3..27bfe6d3a33c 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c | |||
@@ -257,7 +257,7 @@ hauppauge_tuner[] = | |||
257 | { TUNER_ABSENT, "LG TAPQ_H702F"}, | 257 | { TUNER_ABSENT, "LG TAPQ_H702F"}, |
258 | { TUNER_ABSENT, "TCL M09WPP_4N_E"}, | 258 | { TUNER_ABSENT, "TCL M09WPP_4N_E"}, |
259 | { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, | 259 | { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, |
260 | { TUNER_ABSENT, "Philips 18271_8295"}, | 260 | { TUNER_PHILIPS_TDA8295, "Philips 18271_8295"}, |
261 | }; | 261 | }; |
262 | 262 | ||
263 | static struct HAUPPAUGE_AUDIOIC | 263 | static struct HAUPPAUGE_AUDIOIC |
diff --git a/include/media/tuner.h b/include/media/tuner.h index d49392d90e56..faacd2d50b72 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h | |||
@@ -124,6 +124,8 @@ extern int tuner_debug; | |||
124 | #define TUNER_TDA9887 74 /* This tuner should be used only internally */ | 124 | #define TUNER_TDA9887 74 /* This tuner should be used only internally */ |
125 | #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ | 125 | #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ |
126 | 126 | ||
127 | #define TUNER_PHILIPS_TDA8295 76 | ||
128 | |||
127 | /* tv card specific */ | 129 | /* tv card specific */ |
128 | #define TDA9887_PRESENT (1<<0) | 130 | #define TDA9887_PRESENT (1<<0) |
129 | #define TDA9887_PORT1_INACTIVE (1<<1) | 131 | #define TDA9887_PORT1_INACTIVE (1<<1) |