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