Commit | Line | Data |
---|---|---|
1da177e4 | 1 | #include <linux/module.h> |
1da177e4 LT |
2 | #include <linux/kernel.h> |
3 | #include <linux/i2c.h> | |
4 | #include <linux/types.h> | |
1da177e4 LT |
5 | #include <linux/init.h> |
6 | #include <linux/errno.h> | |
1da177e4 | 7 | #include <linux/delay.h> |
f894dfd7 | 8 | #include <linux/videodev2.h> |
5e453dc7 | 9 | #include <media/v4l2-common.h> |
1da177e4 | 10 | #include <media/tuner.h> |
ab166050 | 11 | #include "tuner-i2c.h" |
31c9584c | 12 | #include "tda9887.h" |
1da177e4 | 13 | |
674434c6 | 14 | |
1da177e4 LT |
15 | /* Chips: |
16 | TDA9885 (PAL, NTSC) | |
17 | TDA9886 (PAL, SECAM, NTSC) | |
18 | TDA9887 (PAL, SECAM, NTSC, FM Radio) | |
19 | ||
15396236 | 20 | Used as part of several tuners |
1da177e4 LT |
21 | */ |
22 | ||
790ba18e MK |
23 | static int debug; |
24 | module_param(debug, int, 0644); | |
25 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | |
26 | ||
ac8b63b3 MK |
27 | static DEFINE_MUTEX(tda9887_list_mutex); |
28 | static LIST_HEAD(hybrid_tuner_instance_list); | |
29 | ||
b2083199 | 30 | struct tda9887_priv { |
db8a6956 | 31 | struct tuner_i2c_props i2c_props; |
ac8b63b3 | 32 | struct list_head hybrid_tuner_instance_list; |
db8a6956 | 33 | |
b2083199 | 34 | unsigned char data[4]; |
710401b8 | 35 | unsigned int config; |
91c9d4a1 MK |
36 | unsigned int mode; |
37 | unsigned int audmode; | |
38 | v4l2_std_id std; | |
2d351df4 MCC |
39 | |
40 | bool standby; | |
b2083199 | 41 | }; |
1da177e4 LT |
42 | |
43 | /* ---------------------------------------------------------------------- */ | |
44 | ||
45 | #define UNSET (-1U) | |
1da177e4 LT |
46 | |
47 | struct tvnorm { | |
48 | v4l2_std_id std; | |
49 | char *name; | |
50 | unsigned char b; | |
51 | unsigned char c; | |
52 | unsigned char e; | |
53 | }; | |
54 | ||
1da177e4 LT |
55 | /* ---------------------------------------------------------------------- */ |
56 | ||
57 | // | |
58 | // TDA defines | |
59 | // | |
60 | ||
61 | //// first reg (b) | |
62 | #define cVideoTrapBypassOFF 0x00 // bit b0 | |
63 | #define cVideoTrapBypassON 0x01 // bit b0 | |
64 | ||
65 | #define cAutoMuteFmInactive 0x00 // bit b1 | |
66 | #define cAutoMuteFmActive 0x02 // bit b1 | |
67 | ||
68 | #define cIntercarrier 0x00 // bit b2 | |
69 | #define cQSS 0x04 // bit b2 | |
70 | ||
71 | #define cPositiveAmTV 0x00 // bit b3:4 | |
72 | #define cFmRadio 0x08 // bit b3:4 | |
73 | #define cNegativeFmTV 0x10 // bit b3:4 | |
74 | ||
75 | ||
76 | #define cForcedMuteAudioON 0x20 // bit b5 | |
77 | #define cForcedMuteAudioOFF 0x00 // bit b5 | |
78 | ||
79 | #define cOutputPort1Active 0x00 // bit b6 | |
80 | #define cOutputPort1Inactive 0x40 // bit b6 | |
81 | ||
82 | #define cOutputPort2Active 0x00 // bit b7 | |
83 | #define cOutputPort2Inactive 0x80 // bit b7 | |
84 | ||
85 | ||
86 | //// second reg (c) | |
87 | #define cDeemphasisOFF 0x00 // bit c5 | |
88 | #define cDeemphasisON 0x20 // bit c5 | |
89 | ||
90 | #define cDeemphasis75 0x00 // bit c6 | |
91 | #define cDeemphasis50 0x40 // bit c6 | |
92 | ||
93 | #define cAudioGain0 0x00 // bit c7 | |
94 | #define cAudioGain6 0x80 // bit c7 | |
95 | ||
f98c55ea | 96 | #define cTopMask 0x1f // bit c0:4 |
f5b0142a | 97 | #define cTopDefault 0x10 // bit c0:4 |
1da177e4 LT |
98 | |
99 | //// third reg (e) | |
100 | #define cAudioIF_4_5 0x00 // bit e0:1 | |
101 | #define cAudioIF_5_5 0x01 // bit e0:1 | |
102 | #define cAudioIF_6_0 0x02 // bit e0:1 | |
103 | #define cAudioIF_6_5 0x03 // bit e0:1 | |
104 | ||
105 | ||
5e082f15 TP |
106 | #define cVideoIFMask 0x1c // bit e2:4 |
107 | /* Video IF selection in TV Mode (bit B3=0) */ | |
1da177e4 LT |
108 | #define cVideoIF_58_75 0x00 // bit e2:4 |
109 | #define cVideoIF_45_75 0x04 // bit e2:4 | |
110 | #define cVideoIF_38_90 0x08 // bit e2:4 | |
111 | #define cVideoIF_38_00 0x0C // bit e2:4 | |
112 | #define cVideoIF_33_90 0x10 // bit e2:4 | |
113 | #define cVideoIF_33_40 0x14 // bit e2:4 | |
114 | #define cRadioIF_45_75 0x18 // bit e2:4 | |
115 | #define cRadioIF_38_90 0x1C // bit e2:4 | |
116 | ||
5e082f15 TP |
117 | /* IF1 selection in Radio Mode (bit B3=1) */ |
118 | #define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) | |
119 | #define cRadioIF_41_30 0x04 // bit e2,4 | |
120 | ||
121 | /* Output of AFC pin in radio mode when bit E7=1 */ | |
122 | #define cRadioAGC_SIF 0x00 // bit e3 | |
123 | #define cRadioAGC_FM 0x08 // bit e3 | |
1da177e4 LT |
124 | |
125 | #define cTunerGainNormal 0x00 // bit e5 | |
126 | #define cTunerGainLow 0x20 // bit e5 | |
127 | ||
128 | #define cGating_18 0x00 // bit e6 | |
129 | #define cGating_36 0x40 // bit e6 | |
130 | ||
131 | #define cAgcOutON 0x80 // bit e7 | |
132 | #define cAgcOutOFF 0x00 // bit e7 | |
133 | ||
134 | /* ---------------------------------------------------------------------- */ | |
135 | ||
136 | static struct tvnorm tvnorms[] = { | |
137 | { | |
f98c55ea HV |
138 | .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, |
139 | .name = "PAL-BGHN", | |
1da177e4 LT |
140 | .b = ( cNegativeFmTV | |
141 | cQSS ), | |
142 | .c = ( cDeemphasisON | | |
f98c55ea | 143 | cDeemphasis50 | |
f5b0142a | 144 | cTopDefault), |
f98c55ea HV |
145 | .e = ( cGating_36 | |
146 | cAudioIF_5_5 | | |
1da177e4 LT |
147 | cVideoIF_38_90 ), |
148 | },{ | |
149 | .std = V4L2_STD_PAL_I, | |
150 | .name = "PAL-I", | |
151 | .b = ( cNegativeFmTV | | |
152 | cQSS ), | |
153 | .c = ( cDeemphasisON | | |
f98c55ea | 154 | cDeemphasis50 | |
f5b0142a | 155 | cTopDefault), |
f98c55ea HV |
156 | .e = ( cGating_36 | |
157 | cAudioIF_6_0 | | |
1da177e4 LT |
158 | cVideoIF_38_90 ), |
159 | },{ | |
160 | .std = V4L2_STD_PAL_DK, | |
161 | .name = "PAL-DK", | |
162 | .b = ( cNegativeFmTV | | |
163 | cQSS ), | |
164 | .c = ( cDeemphasisON | | |
f98c55ea | 165 | cDeemphasis50 | |
f5b0142a | 166 | cTopDefault), |
f98c55ea HV |
167 | .e = ( cGating_36 | |
168 | cAudioIF_6_5 | | |
169 | cVideoIF_38_90 ), | |
1da177e4 | 170 | },{ |
f98c55ea HV |
171 | .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, |
172 | .name = "PAL-M/Nc", | |
1da177e4 LT |
173 | .b = ( cNegativeFmTV | |
174 | cQSS ), | |
175 | .c = ( cDeemphasisON | | |
f98c55ea | 176 | cDeemphasis75 | |
f5b0142a | 177 | cTopDefault), |
f98c55ea HV |
178 | .e = ( cGating_36 | |
179 | cAudioIF_4_5 | | |
1da177e4 | 180 | cVideoIF_45_75 ), |
f98c55ea HV |
181 | },{ |
182 | .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, | |
183 | .name = "SECAM-BGH", | |
b84ca9f2 | 184 | .b = ( cNegativeFmTV | |
f98c55ea | 185 | cQSS ), |
f5b0142a | 186 | .c = ( cTopDefault), |
b84ca9f2 | 187 | .e = ( cAudioIF_5_5 | |
f98c55ea | 188 | cVideoIF_38_90 ), |
1da177e4 LT |
189 | },{ |
190 | .std = V4L2_STD_SECAM_L, | |
191 | .name = "SECAM-L", | |
192 | .b = ( cPositiveAmTV | | |
193 | cQSS ), | |
f5b0142a | 194 | .c = ( cTopDefault), |
3375c398 | 195 | .e = ( cGating_36 | |
5f7591c0 | 196 | cAudioIF_6_5 | |
1da177e4 | 197 | cVideoIF_38_90 ), |
f3c5987a MCC |
198 | },{ |
199 | .std = V4L2_STD_SECAM_LC, | |
200 | .name = "SECAM-L'", | |
201 | .b = ( cOutputPort2Inactive | | |
202 | cPositiveAmTV | | |
203 | cQSS ), | |
f5b0142a | 204 | .c = ( cTopDefault), |
f3c5987a MCC |
205 | .e = ( cGating_36 | |
206 | cAudioIF_6_5 | | |
207 | cVideoIF_33_90 ), | |
1da177e4 LT |
208 | },{ |
209 | .std = V4L2_STD_SECAM_DK, | |
210 | .name = "SECAM-DK", | |
211 | .b = ( cNegativeFmTV | | |
212 | cQSS ), | |
213 | .c = ( cDeemphasisON | | |
f98c55ea | 214 | cDeemphasis50 | |
f5b0142a | 215 | cTopDefault), |
f98c55ea HV |
216 | .e = ( cGating_36 | |
217 | cAudioIF_6_5 | | |
218 | cVideoIF_38_90 ), | |
1da177e4 | 219 | },{ |
0dfd812d | 220 | .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, |
1da177e4 LT |
221 | .name = "NTSC-M", |
222 | .b = ( cNegativeFmTV | | |
223 | cQSS ), | |
224 | .c = ( cDeemphasisON | | |
f98c55ea | 225 | cDeemphasis75 | |
f5b0142a | 226 | cTopDefault), |
1da177e4 LT |
227 | .e = ( cGating_36 | |
228 | cAudioIF_4_5 | | |
229 | cVideoIF_45_75 ), | |
230 | },{ | |
231 | .std = V4L2_STD_NTSC_M_JP, | |
f98c55ea | 232 | .name = "NTSC-M-JP", |
1da177e4 LT |
233 | .b = ( cNegativeFmTV | |
234 | cQSS ), | |
235 | .c = ( cDeemphasisON | | |
f98c55ea | 236 | cDeemphasis50 | |
f5b0142a | 237 | cTopDefault), |
1da177e4 LT |
238 | .e = ( cGating_36 | |
239 | cAudioIF_4_5 | | |
240 | cVideoIF_58_75 ), | |
241 | } | |
242 | }; | |
243 | ||
56fc08ca MCC |
244 | static struct tvnorm radio_stereo = { |
245 | .name = "Radio Stereo", | |
246 | .b = ( cFmRadio | | |
247 | cQSS ), | |
248 | .c = ( cDeemphasisOFF | | |
f98c55ea | 249 | cAudioGain6 | |
f5b0142a | 250 | cTopDefault), |
f98c55ea HV |
251 | .e = ( cTunerGainLow | |
252 | cAudioIF_5_5 | | |
56fc08ca MCC |
253 | cRadioIF_38_90 ), |
254 | }; | |
255 | ||
256 | static struct tvnorm radio_mono = { | |
257 | .name = "Radio Mono", | |
1da177e4 LT |
258 | .b = ( cFmRadio | |
259 | cQSS ), | |
260 | .c = ( cDeemphasisON | | |
f98c55ea | 261 | cDeemphasis75 | |
f5b0142a | 262 | cTopDefault), |
f98c55ea HV |
263 | .e = ( cTunerGainLow | |
264 | cAudioIF_5_5 | | |
1da177e4 LT |
265 | cRadioIF_38_90 ), |
266 | }; | |
267 | ||
268 | /* ---------------------------------------------------------------------- */ | |
269 | ||
4e9154b8 | 270 | static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) |
1da177e4 | 271 | { |
4e9154b8 MK |
272 | struct tda9887_priv *priv = fe->analog_demod_priv; |
273 | ||
1da177e4 LT |
274 | static char *afc[16] = { |
275 | "- 12.5 kHz", | |
276 | "- 37.5 kHz", | |
277 | "- 62.5 kHz", | |
278 | "- 87.5 kHz", | |
279 | "-112.5 kHz", | |
280 | "-137.5 kHz", | |
281 | "-162.5 kHz", | |
282 | "-187.5 kHz [min]", | |
283 | "+187.5 kHz [max]", | |
284 | "+162.5 kHz", | |
285 | "+137.5 kHz", | |
286 | "+112.5 kHz", | |
287 | "+ 87.5 kHz", | |
288 | "+ 62.5 kHz", | |
289 | "+ 37.5 kHz", | |
290 | "+ 12.5 kHz", | |
291 | }; | |
790ba18e MK |
292 | tuner_info("read: 0x%2x\n", buf[0]); |
293 | tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); | |
294 | tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); | |
295 | tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); | |
296 | tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); | |
297 | tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); | |
1da177e4 LT |
298 | } |
299 | ||
4e9154b8 | 300 | static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) |
1da177e4 | 301 | { |
4e9154b8 MK |
302 | struct tda9887_priv *priv = fe->analog_demod_priv; |
303 | ||
1da177e4 LT |
304 | static char *sound[4] = { |
305 | "AM/TV", | |
306 | "FM/radio", | |
307 | "FM/TV", | |
308 | "FM/radio" | |
309 | }; | |
310 | static char *adjust[32] = { | |
311 | "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", | |
312 | "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", | |
313 | "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", | |
314 | "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15" | |
315 | }; | |
316 | static char *deemph[4] = { | |
317 | "no", "no", "75", "50" | |
318 | }; | |
319 | static char *carrier[4] = { | |
320 | "4.5 MHz", | |
321 | "5.5 MHz", | |
322 | "6.0 MHz", | |
323 | "6.5 MHz / AM" | |
324 | }; | |
325 | static char *vif[8] = { | |
326 | "58.75 MHz", | |
327 | "45.75 MHz", | |
328 | "38.9 MHz", | |
329 | "38.0 MHz", | |
330 | "33.9 MHz", | |
331 | "33.4 MHz", | |
332 | "45.75 MHz + pin13", | |
333 | "38.9 MHz + pin13", | |
334 | }; | |
335 | static char *rif[4] = { | |
336 | "44 MHz", | |
337 | "52 MHz", | |
338 | "52 MHz", | |
339 | "44 MHz", | |
340 | }; | |
341 | ||
790ba18e MK |
342 | tuner_info("write: byte B 0x%02x\n", buf[1]); |
343 | tuner_info(" B0 video mode : %s\n", | |
344 | (buf[1] & 0x01) ? "video trap" : "sound trap"); | |
345 | tuner_info(" B1 auto mute fm : %s\n", | |
346 | (buf[1] & 0x02) ? "yes" : "no"); | |
347 | tuner_info(" B2 carrier mode : %s\n", | |
348 | (buf[1] & 0x04) ? "QSS" : "Intercarrier"); | |
349 | tuner_info(" B3-4 tv sound/radio : %s\n", | |
350 | sound[(buf[1] & 0x18) >> 3]); | |
351 | tuner_info(" B5 force mute audio: %s\n", | |
352 | (buf[1] & 0x20) ? "yes" : "no"); | |
353 | tuner_info(" B6 output port 1 : %s\n", | |
354 | (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); | |
355 | tuner_info(" B7 output port 2 : %s\n", | |
356 | (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); | |
357 | ||
358 | tuner_info("write: byte C 0x%02x\n", buf[2]); | |
359 | tuner_info(" C0-4 top adjustment : %s dB\n", | |
360 | adjust[buf[2] & 0x1f]); | |
361 | tuner_info(" C5-6 de-emphasis : %s\n", | |
362 | deemph[(buf[2] & 0x60) >> 5]); | |
363 | tuner_info(" C7 audio gain : %s\n", | |
364 | (buf[2] & 0x80) ? "-6" : "0"); | |
365 | ||
366 | tuner_info("write: byte E 0x%02x\n", buf[3]); | |
367 | tuner_info(" E0-1 sound carrier : %s\n", | |
368 | carrier[(buf[3] & 0x03)]); | |
369 | tuner_info(" E6 l pll gating : %s\n", | |
370 | (buf[3] & 0x40) ? "36" : "13"); | |
1da177e4 LT |
371 | |
372 | if (buf[1] & 0x08) { | |
373 | /* radio */ | |
790ba18e MK |
374 | tuner_info(" E2-4 video if : %s\n", |
375 | rif[(buf[3] & 0x0c) >> 2]); | |
376 | tuner_info(" E7 vif agc output : %s\n", | |
377 | (buf[3] & 0x80) | |
378 | ? ((buf[3] & 0x10) ? "fm-agc radio" : | |
379 | "sif-agc radio") | |
380 | : "fm radio carrier afc"); | |
1da177e4 LT |
381 | } else { |
382 | /* video */ | |
790ba18e MK |
383 | tuner_info(" E2-4 video if : %s\n", |
384 | vif[(buf[3] & 0x1c) >> 2]); | |
385 | tuner_info(" E5 tuner gain : %s\n", | |
386 | (buf[3] & 0x80) | |
387 | ? ((buf[3] & 0x20) ? "external" : "normal") | |
388 | : ((buf[3] & 0x20) ? "minimum" : "normal")); | |
389 | tuner_info(" E7 vif agc output : %s\n", | |
390 | (buf[3] & 0x80) ? ((buf[3] & 0x20) | |
391 | ? "pin3 port, pin22 vif agc out" | |
392 | : "pin22 port, pin3 vif acg ext in") | |
393 | : "pin3+pin22 port"); | |
1da177e4 | 394 | } |
790ba18e | 395 | tuner_info("--\n"); |
1da177e4 LT |
396 | } |
397 | ||
398 | /* ---------------------------------------------------------------------- */ | |
399 | ||
4e9154b8 | 400 | static int tda9887_set_tvnorm(struct dvb_frontend *fe) |
1da177e4 | 401 | { |
4e9154b8 | 402 | struct tda9887_priv *priv = fe->analog_demod_priv; |
1da177e4 | 403 | struct tvnorm *norm = NULL; |
4e9154b8 | 404 | char *buf = priv->data; |
1da177e4 LT |
405 | int i; |
406 | ||
91c9d4a1 MK |
407 | if (priv->mode == V4L2_TUNER_RADIO) { |
408 | if (priv->audmode == V4L2_TUNER_MODE_MONO) | |
56fc08ca MCC |
409 | norm = &radio_mono; |
410 | else | |
586b0cab | 411 | norm = &radio_stereo; |
1da177e4 LT |
412 | } else { |
413 | for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { | |
91c9d4a1 | 414 | if (tvnorms[i].std & priv->std) { |
1da177e4 LT |
415 | norm = tvnorms+i; |
416 | break; | |
417 | } | |
418 | } | |
419 | } | |
420 | if (NULL == norm) { | |
790ba18e | 421 | tuner_dbg("Unsupported tvnorm entry - audio muted\n"); |
1da177e4 LT |
422 | return -1; |
423 | } | |
424 | ||
790ba18e | 425 | tuner_dbg("configure for: %s\n", norm->name); |
1da177e4 LT |
426 | buf[1] = norm->b; |
427 | buf[2] = norm->c; | |
428 | buf[3] = norm->e; | |
429 | return 0; | |
430 | } | |
431 | ||
432 | static unsigned int port1 = UNSET; | |
433 | static unsigned int port2 = UNSET; | |
434 | static unsigned int qss = UNSET; | |
f98c55ea HV |
435 | static unsigned int adjust = UNSET; |
436 | ||
1da177e4 LT |
437 | module_param(port1, int, 0644); |
438 | module_param(port2, int, 0644); | |
439 | module_param(qss, int, 0644); | |
440 | module_param(adjust, int, 0644); | |
441 | ||
4e9154b8 | 442 | static int tda9887_set_insmod(struct dvb_frontend *fe) |
1da177e4 | 443 | { |
4e9154b8 MK |
444 | struct tda9887_priv *priv = fe->analog_demod_priv; |
445 | char *buf = priv->data; | |
446 | ||
1da177e4 LT |
447 | if (UNSET != port1) { |
448 | if (port1) | |
449 | buf[1] |= cOutputPort1Inactive; | |
450 | else | |
451 | buf[1] &= ~cOutputPort1Inactive; | |
452 | } | |
453 | if (UNSET != port2) { | |
454 | if (port2) | |
455 | buf[1] |= cOutputPort2Inactive; | |
456 | else | |
457 | buf[1] &= ~cOutputPort2Inactive; | |
458 | } | |
459 | ||
460 | if (UNSET != qss) { | |
461 | if (qss) | |
462 | buf[1] |= cQSS; | |
463 | else | |
464 | buf[1] &= ~cQSS; | |
465 | } | |
466 | ||
f14a2972 | 467 | if (adjust < 0x20) { |
f98c55ea | 468 | buf[2] &= ~cTopMask; |
1da177e4 | 469 | buf[2] |= adjust; |
f98c55ea | 470 | } |
1da177e4 LT |
471 | return 0; |
472 | } | |
473 | ||
710401b8 | 474 | static int tda9887_do_config(struct dvb_frontend *fe) |
1da177e4 | 475 | { |
4e9154b8 | 476 | struct tda9887_priv *priv = fe->analog_demod_priv; |
4e9154b8 MK |
477 | char *buf = priv->data; |
478 | ||
710401b8 | 479 | if (priv->config & TDA9887_PORT1_ACTIVE) |
1da177e4 | 480 | buf[1] &= ~cOutputPort1Inactive; |
710401b8 | 481 | if (priv->config & TDA9887_PORT1_INACTIVE) |
1da177e4 | 482 | buf[1] |= cOutputPort1Inactive; |
710401b8 | 483 | if (priv->config & TDA9887_PORT2_ACTIVE) |
1da177e4 | 484 | buf[1] &= ~cOutputPort2Inactive; |
710401b8 | 485 | if (priv->config & TDA9887_PORT2_INACTIVE) |
1da177e4 LT |
486 | buf[1] |= cOutputPort2Inactive; |
487 | ||
710401b8 | 488 | if (priv->config & TDA9887_QSS) |
1da177e4 | 489 | buf[1] |= cQSS; |
710401b8 | 490 | if (priv->config & TDA9887_INTERCARRIER) |
1da177e4 LT |
491 | buf[1] &= ~cQSS; |
492 | ||
710401b8 | 493 | if (priv->config & TDA9887_AUTOMUTE) |
1da177e4 | 494 | buf[1] |= cAutoMuteFmActive; |
710401b8 | 495 | if (priv->config & TDA9887_DEEMPHASIS_MASK) { |
1da177e4 | 496 | buf[2] &= ~0x60; |
710401b8 | 497 | switch (priv->config & TDA9887_DEEMPHASIS_MASK) { |
1da177e4 LT |
498 | case TDA9887_DEEMPHASIS_NONE: |
499 | buf[2] |= cDeemphasisOFF; | |
500 | break; | |
501 | case TDA9887_DEEMPHASIS_50: | |
502 | buf[2] |= cDeemphasisON | cDeemphasis50; | |
503 | break; | |
504 | case TDA9887_DEEMPHASIS_75: | |
505 | buf[2] |= cDeemphasisON | cDeemphasis75; | |
506 | break; | |
507 | } | |
508 | } | |
710401b8 | 509 | if (priv->config & TDA9887_TOP_SET) { |
f98c55ea | 510 | buf[2] &= ~cTopMask; |
710401b8 | 511 | buf[2] |= (priv->config >> 8) & cTopMask; |
f98c55ea | 512 | } |
710401b8 | 513 | if ((priv->config & TDA9887_INTERCARRIER_NTSC) && |
91c9d4a1 | 514 | (priv->std & V4L2_STD_NTSC)) |
3ae1adc6 | 515 | buf[1] &= ~cQSS; |
710401b8 | 516 | if (priv->config & TDA9887_GATING_18) |
d7304dee | 517 | buf[3] &= ~cGating_36; |
cefccc80 | 518 | |
91c9d4a1 | 519 | if (priv->mode == V4L2_TUNER_RADIO) { |
710401b8 | 520 | if (priv->config & TDA9887_RIF_41_3) { |
5e082f15 TP |
521 | buf[3] &= ~cVideoIFMask; |
522 | buf[3] |= cRadioIF_41_30; | |
523 | } | |
710401b8 | 524 | if (priv->config & TDA9887_GAIN_NORMAL) |
5e082f15 | 525 | buf[3] &= ~cTunerGainLow; |
cefccc80 MCC |
526 | } |
527 | ||
1da177e4 LT |
528 | return 0; |
529 | } | |
530 | ||
531 | /* ---------------------------------------------------------------------- */ | |
532 | ||
4e9154b8 | 533 | static int tda9887_status(struct dvb_frontend *fe) |
1da177e4 | 534 | { |
4e9154b8 | 535 | struct tda9887_priv *priv = fe->analog_demod_priv; |
1da177e4 LT |
536 | unsigned char buf[1]; |
537 | int rc; | |
538 | ||
408679cd MCC |
539 | rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1); |
540 | if (rc != 1) | |
790ba18e | 541 | tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); |
4e9154b8 | 542 | dump_read_message(fe, buf); |
1da177e4 LT |
543 | return 0; |
544 | } | |
545 | ||
4e9154b8 | 546 | static void tda9887_configure(struct dvb_frontend *fe) |
1da177e4 | 547 | { |
4e9154b8 | 548 | struct tda9887_priv *priv = fe->analog_demod_priv; |
1da177e4 LT |
549 | int rc; |
550 | ||
b2083199 | 551 | memset(priv->data,0,sizeof(priv->data)); |
4e9154b8 | 552 | tda9887_set_tvnorm(fe); |
56fc08ca | 553 | |
f98c55ea HV |
554 | /* A note on the port settings: |
555 | These settings tend to depend on the specifics of the board. | |
556 | By default they are set to inactive (bit value 1) by this driver, | |
557 | overwriting any changes made by the tvnorm. This means that it | |
558 | is the responsibility of the module using the tda9887 to set | |
559 | these values in case of changes in the tvnorm. | |
560 | In many cases port 2 should be made active (0) when selecting | |
561 | SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. | |
562 | ||
563 | For the other standards the tda9887 application note says that | |
564 | the ports should be set to active (0), but, again, that may | |
565 | differ depending on the precise hardware configuration. | |
566 | */ | |
b2083199 MK |
567 | priv->data[1] |= cOutputPort1Inactive; |
568 | priv->data[1] |= cOutputPort2Inactive; | |
56fc08ca | 569 | |
710401b8 | 570 | tda9887_do_config(fe); |
4e9154b8 | 571 | tda9887_set_insmod(fe); |
1da177e4 | 572 | |
2d351df4 | 573 | if (priv->standby) |
b2083199 | 574 | priv->data[1] |= cForcedMuteAudioON; |
793cf9e6 | 575 | |
790ba18e MK |
576 | tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", |
577 | priv->data[1], priv->data[2], priv->data[3]); | |
578 | if (debug > 1) | |
4e9154b8 | 579 | dump_write_message(fe, priv->data); |
1da177e4 | 580 | |
db8a6956 | 581 | if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) |
790ba18e | 582 | tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); |
1da177e4 | 583 | |
790ba18e | 584 | if (debug > 2) { |
1da177e4 | 585 | msleep_interruptible(1000); |
4e9154b8 | 586 | tda9887_status(fe); |
1da177e4 | 587 | } |
1da177e4 LT |
588 | } |
589 | ||
590 | /* ---------------------------------------------------------------------- */ | |
591 | ||
4e9154b8 | 592 | static void tda9887_tuner_status(struct dvb_frontend *fe) |
1da177e4 | 593 | { |
4e9154b8 | 594 | struct tda9887_priv *priv = fe->analog_demod_priv; |
790ba18e MK |
595 | tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", |
596 | priv->data[1], priv->data[2], priv->data[3]); | |
1da177e4 LT |
597 | } |
598 | ||
a2192cf4 | 599 | static int tda9887_get_afc(struct dvb_frontend *fe, s32 *afc) |
1da177e4 | 600 | { |
4e9154b8 | 601 | struct tda9887_priv *priv = fe->analog_demod_priv; |
a2192cf4 | 602 | static const int AFC_BITS_2_kHz[] = { |
15396236 MCC |
603 | -12500, -37500, -62500, -97500, |
604 | -112500, -137500, -162500, -187500, | |
605 | 187500, 162500, 137500, 112500, | |
606 | 97500 , 62500, 37500 , 12500 | |
607 | }; | |
15396236 | 608 | __u8 reg = 0; |
1da177e4 | 609 | |
a2192cf4 HV |
610 | if (priv->mode != V4L2_TUNER_RADIO) |
611 | return 0; | |
612 | if (1 == tuner_i2c_xfer_recv(&priv->i2c_props, ®, 1)) | |
613 | *afc = AFC_BITS_2_kHz[(reg >> 1) & 0x0f]; | |
614 | return 0; | |
1da177e4 LT |
615 | } |
616 | ||
4e9154b8 | 617 | static void tda9887_standby(struct dvb_frontend *fe) |
1da177e4 | 618 | { |
91c9d4a1 MK |
619 | struct tda9887_priv *priv = fe->analog_demod_priv; |
620 | ||
2d351df4 | 621 | priv->standby = true; |
91c9d4a1 | 622 | |
4e9154b8 | 623 | tda9887_configure(fe); |
1da177e4 LT |
624 | } |
625 | ||
c7919d52 MK |
626 | static void tda9887_set_params(struct dvb_frontend *fe, |
627 | struct analog_parameters *params) | |
1da177e4 | 628 | { |
91c9d4a1 MK |
629 | struct tda9887_priv *priv = fe->analog_demod_priv; |
630 | ||
2d351df4 | 631 | priv->standby = false; |
91c9d4a1 MK |
632 | priv->mode = params->mode; |
633 | priv->audmode = params->audmode; | |
634 | priv->std = params->std; | |
4e9154b8 | 635 | tda9887_configure(fe); |
1da177e4 LT |
636 | } |
637 | ||
710401b8 MK |
638 | static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) |
639 | { | |
640 | struct tda9887_priv *priv = fe->analog_demod_priv; | |
641 | ||
642 | priv->config = *(unsigned int *)priv_cfg; | |
643 | tda9887_configure(fe); | |
644 | ||
645 | return 0; | |
646 | } | |
647 | ||
4e9154b8 | 648 | static void tda9887_release(struct dvb_frontend *fe) |
024cf530 | 649 | { |
ac8b63b3 MK |
650 | struct tda9887_priv *priv = fe->analog_demod_priv; |
651 | ||
652 | mutex_lock(&tda9887_list_mutex); | |
653 | ||
654 | if (priv) | |
655 | hybrid_tuner_release_state(priv); | |
656 | ||
657 | mutex_unlock(&tda9887_list_mutex); | |
658 | ||
4e9154b8 | 659 | fe->analog_demod_priv = NULL; |
024cf530 MK |
660 | } |
661 | ||
bc3e5c7f | 662 | static struct analog_demod_ops tda9887_ops = { |
a55db8cd | 663 | .info = { |
0f2ce983 | 664 | .name = "tda9887", |
a55db8cd | 665 | }, |
c7919d52 | 666 | .set_params = tda9887_set_params, |
9af596eb MK |
667 | .standby = tda9887_standby, |
668 | .tuner_status = tda9887_tuner_status, | |
669 | .get_afc = tda9887_get_afc, | |
670 | .release = tda9887_release, | |
710401b8 | 671 | .set_config = tda9887_set_config, |
9af596eb MK |
672 | }; |
673 | ||
8ca4083b MK |
674 | struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, |
675 | struct i2c_adapter *i2c_adap, | |
676 | u8 i2c_addr) | |
1da177e4 | 677 | { |
b2083199 | 678 | struct tda9887_priv *priv = NULL; |
ac8b63b3 | 679 | int instance; |
1da177e4 | 680 | |
ac8b63b3 | 681 | mutex_lock(&tda9887_list_mutex); |
b2083199 | 682 | |
ac8b63b3 MK |
683 | instance = hybrid_tuner_request_state(struct tda9887_priv, priv, |
684 | hybrid_tuner_instance_list, | |
685 | i2c_adap, i2c_addr, "tda9887"); | |
686 | switch (instance) { | |
687 | case 0: | |
688 | mutex_unlock(&tda9887_list_mutex); | |
689 | return NULL; | |
ac8b63b3 MK |
690 | case 1: |
691 | fe->analog_demod_priv = priv; | |
2d351df4 | 692 | priv->standby = true; |
ac8b63b3 MK |
693 | tuner_info("tda988[5/6/7] found\n"); |
694 | break; | |
695 | default: | |
696 | fe->analog_demod_priv = priv; | |
697 | break; | |
698 | } | |
db8a6956 | 699 | |
ac8b63b3 | 700 | mutex_unlock(&tda9887_list_mutex); |
1da177e4 | 701 | |
bc3e5c7f MK |
702 | memcpy(&fe->ops.analog_ops, &tda9887_ops, |
703 | sizeof(struct analog_demod_ops)); | |
1da177e4 | 704 | |
8ca4083b | 705 | return fe; |
1da177e4 | 706 | } |
31c9584c | 707 | EXPORT_SYMBOL_GPL(tda9887_attach); |
1da177e4 | 708 | |
5ef4730d | 709 | MODULE_LICENSE("GPL"); |