blob: 106c93b8203fea587562240b37b8d0564cbb21a3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#include <linux/kernel.h>
3#include <linux/i2c.h>
4#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005#include <linux/init.h>
6#include <linux/errno.h>
7#include <linux/slab.h>
8#include <linux/delay.h>
Michael Krufkyffbb8072007-08-21 01:14:12 -03009#include <linux/videodev.h>
Michael Krufky5e453dc2006-01-09 15:32:31 -020010#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <media/tuner.h>
Michael Krufkyab166052007-12-09 02:26:48 -030012#include "tuner-i2c.h"
Michael Krufky31c95842007-10-21 20:48:48 -030013#include "tda9887.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -080015
Linus Torvalds1da177e2005-04-16 15:20:36 -070016/* Chips:
17 TDA9885 (PAL, NTSC)
18 TDA9886 (PAL, SECAM, NTSC)
19 TDA9887 (PAL, SECAM, NTSC, FM Radio)
20
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030021 Used as part of several tuners
Linus Torvalds1da177e2005-04-16 15:20:36 -070022*/
23
Michael Krufky790ba182007-12-16 21:20:21 -030024static int debug;
25module_param(debug, int, 0644);
26MODULE_PARM_DESC(debug, "enable verbose debug messages");
Michael Krufky31c95842007-10-21 20:48:48 -030027
Michael Krufky790ba182007-12-16 21:20:21 -030028#define PREFIX "tda9887"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Michael Krufkyb2083192007-05-29 22:54:06 -030030struct tda9887_priv {
Michael Krufkydb8a6952007-08-21 01:24:42 -030031 struct tuner_i2c_props i2c_props;
32
Michael Krufkyb2083192007-05-29 22:54:06 -030033 unsigned char data[4];
Michael Krufky710401b2007-12-16 19:53:32 -030034 unsigned int config;
Michael Krufky91c9d4a2007-12-16 20:05:00 -030035 unsigned int mode;
36 unsigned int audmode;
37 v4l2_std_id std;
Michael Krufkyb2083192007-05-29 22:54:06 -030038};
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ---------------------------------------------------------------------- */
41
42#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44struct tvnorm {
45 v4l2_std_id std;
46 char *name;
47 unsigned char b;
48 unsigned char c;
49 unsigned char e;
50};
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052/* ---------------------------------------------------------------------- */
53
54//
55// TDA defines
56//
57
58//// first reg (b)
59#define cVideoTrapBypassOFF 0x00 // bit b0
60#define cVideoTrapBypassON 0x01 // bit b0
61
62#define cAutoMuteFmInactive 0x00 // bit b1
63#define cAutoMuteFmActive 0x02 // bit b1
64
65#define cIntercarrier 0x00 // bit b2
66#define cQSS 0x04 // bit b2
67
68#define cPositiveAmTV 0x00 // bit b3:4
69#define cFmRadio 0x08 // bit b3:4
70#define cNegativeFmTV 0x10 // bit b3:4
71
72
73#define cForcedMuteAudioON 0x20 // bit b5
74#define cForcedMuteAudioOFF 0x00 // bit b5
75
76#define cOutputPort1Active 0x00 // bit b6
77#define cOutputPort1Inactive 0x40 // bit b6
78
79#define cOutputPort2Active 0x00 // bit b7
80#define cOutputPort2Inactive 0x80 // bit b7
81
82
83//// second reg (c)
84#define cDeemphasisOFF 0x00 // bit c5
85#define cDeemphasisON 0x20 // bit c5
86
87#define cDeemphasis75 0x00 // bit c6
88#define cDeemphasis50 0x40 // bit c6
89
90#define cAudioGain0 0x00 // bit c7
91#define cAudioGain6 0x80 // bit c7
92
Hans Verkuilf98c55e2006-01-09 15:25:18 -020093#define cTopMask 0x1f // bit c0:4
Hans Verkuilf5b01422006-06-25 15:37:29 -030094#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96//// third reg (e)
97#define cAudioIF_4_5 0x00 // bit e0:1
98#define cAudioIF_5_5 0x01 // bit e0:1
99#define cAudioIF_6_0 0x02 // bit e0:1
100#define cAudioIF_6_5 0x03 // bit e0:1
101
102
Trent Piepho5e082f12007-08-03 18:32:38 -0300103#define cVideoIFMask 0x1c // bit e2:4
104/* Video IF selection in TV Mode (bit B3=0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105#define cVideoIF_58_75 0x00 // bit e2:4
106#define cVideoIF_45_75 0x04 // bit e2:4
107#define cVideoIF_38_90 0x08 // bit e2:4
108#define cVideoIF_38_00 0x0C // bit e2:4
109#define cVideoIF_33_90 0x10 // bit e2:4
110#define cVideoIF_33_40 0x14 // bit e2:4
111#define cRadioIF_45_75 0x18 // bit e2:4
112#define cRadioIF_38_90 0x1C // bit e2:4
113
Trent Piepho5e082f12007-08-03 18:32:38 -0300114/* IF1 selection in Radio Mode (bit B3=1) */
115#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
116#define cRadioIF_41_30 0x04 // bit e2,4
117
118/* Output of AFC pin in radio mode when bit E7=1 */
119#define cRadioAGC_SIF 0x00 // bit e3
120#define cRadioAGC_FM 0x08 // bit e3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122#define cTunerGainNormal 0x00 // bit e5
123#define cTunerGainLow 0x20 // bit e5
124
125#define cGating_18 0x00 // bit e6
126#define cGating_36 0x40 // bit e6
127
128#define cAgcOutON 0x80 // bit e7
129#define cAgcOutOFF 0x00 // bit e7
130
131/* ---------------------------------------------------------------------- */
132
133static struct tvnorm tvnorms[] = {
134 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200135 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
136 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 .b = ( cNegativeFmTV |
138 cQSS ),
139 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200140 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300141 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200142 .e = ( cGating_36 |
143 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 cVideoIF_38_90 ),
145 },{
146 .std = V4L2_STD_PAL_I,
147 .name = "PAL-I",
148 .b = ( cNegativeFmTV |
149 cQSS ),
150 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200151 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300152 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200153 .e = ( cGating_36 |
154 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 cVideoIF_38_90 ),
156 },{
157 .std = V4L2_STD_PAL_DK,
158 .name = "PAL-DK",
159 .b = ( cNegativeFmTV |
160 cQSS ),
161 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200162 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300163 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200164 .e = ( cGating_36 |
165 cAudioIF_6_5 |
166 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200168 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
169 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 .b = ( cNegativeFmTV |
171 cQSS ),
172 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200173 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300174 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200175 .e = ( cGating_36 |
176 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 cVideoIF_45_75 ),
178 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200179 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
180 .name = "SECAM-BGH",
181 .b = ( cPositiveAmTV |
182 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300183 .c = ( cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200184 .e = ( cGating_36 |
185 cAudioIF_5_5 |
186 cVideoIF_38_90 ),
187 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 .std = V4L2_STD_SECAM_L,
189 .name = "SECAM-L",
190 .b = ( cPositiveAmTV |
191 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300192 .c = ( cTopDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800193 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800194 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 cVideoIF_38_90 ),
196 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200197 .std = V4L2_STD_SECAM_LC,
198 .name = "SECAM-L'",
199 .b = ( cOutputPort2Inactive |
200 cPositiveAmTV |
201 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300202 .c = ( cTopDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200203 .e = ( cGating_36 |
204 cAudioIF_6_5 |
205 cVideoIF_33_90 ),
206 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 .std = V4L2_STD_SECAM_DK,
208 .name = "SECAM-DK",
209 .b = ( cNegativeFmTV |
210 cQSS ),
211 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200212 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300213 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200214 .e = ( cGating_36 |
215 cAudioIF_6_5 |
216 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200218 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 .name = "NTSC-M",
220 .b = ( cNegativeFmTV |
221 cQSS ),
222 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200223 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300224 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 .e = ( cGating_36 |
226 cAudioIF_4_5 |
227 cVideoIF_45_75 ),
228 },{
229 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200230 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 .b = ( cNegativeFmTV |
232 cQSS ),
233 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200234 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300235 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 .e = ( cGating_36 |
237 cAudioIF_4_5 |
238 cVideoIF_58_75 ),
239 }
240};
241
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700242static struct tvnorm radio_stereo = {
243 .name = "Radio Stereo",
244 .b = ( cFmRadio |
245 cQSS ),
246 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200247 cAudioGain6 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300248 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200249 .e = ( cTunerGainLow |
250 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700251 cRadioIF_38_90 ),
252};
253
254static struct tvnorm radio_mono = {
255 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 .b = ( cFmRadio |
257 cQSS ),
258 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200259 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300260 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200261 .e = ( cTunerGainLow |
262 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 cRadioIF_38_90 ),
264};
265
266/* ---------------------------------------------------------------------- */
267
Michael Krufky4e9154b2007-10-21 19:39:50 -0300268static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300270 struct tda9887_priv *priv = fe->analog_demod_priv;
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 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 };
Michael Krufky790ba182007-12-16 21:20:21 -0300290 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
Michael Krufky4e9154b2007-10-21 19:39:50 -0300298static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300300 struct tda9887_priv *priv = fe->analog_demod_priv;
301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 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
Michael Krufky790ba182007-12-16 21:20:21 -0300340 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)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Michael Krufky790ba182007-12-16 21:20:21 -0300356 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Michael Krufky790ba182007-12-16 21:20:21 -0300364 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370 if (buf[1] & 0x08) {
371 /* radio */
Michael Krufky790ba182007-12-16 21:20:21 -0300372 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 } else {
380 /* video */
Michael Krufky790ba182007-12-16 21:20:21 -0300381 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
Michael Krufky790ba182007-12-16 21:20:21 -0300393 tuner_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
395
396/* ---------------------------------------------------------------------- */
397
Michael Krufky4e9154b2007-10-21 19:39:50 -0300398static int tda9887_set_tvnorm(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300400 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 struct tvnorm *norm = NULL;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300402 char *buf = priv->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 int i;
404
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300405 if (priv->mode == V4L2_TUNER_RADIO) {
406 if (priv->audmode == V4L2_TUNER_MODE_MONO)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700407 norm = &radio_mono;
408 else
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700409 norm = &radio_stereo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 } else {
411 for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300412 if (tvnorms[i].std & priv->std) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 norm = tvnorms+i;
414 break;
415 }
416 }
417 }
418 if (NULL == norm) {
Michael Krufky790ba182007-12-16 21:20:21 -0300419 tuner_dbg("Unsupported tvnorm entry - audio muted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return -1;
421 }
422
Michael Krufky790ba182007-12-16 21:20:21 -0300423 tuner_dbg("configure for: %s\n", norm->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 buf[1] = norm->b;
425 buf[2] = norm->c;
426 buf[3] = norm->e;
427 return 0;
428}
429
430static unsigned int port1 = UNSET;
431static unsigned int port2 = UNSET;
432static unsigned int qss = UNSET;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200433static unsigned int adjust = UNSET;
434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435module_param(port1, int, 0644);
436module_param(port2, int, 0644);
437module_param(qss, int, 0644);
438module_param(adjust, int, 0644);
439
Michael Krufky4e9154b2007-10-21 19:39:50 -0300440static int tda9887_set_insmod(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300442 struct tda9887_priv *priv = fe->analog_demod_priv;
443 char *buf = priv->data;
444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 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
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200465 if (adjust >= 0x00 && adjust < 0x20) {
466 buf[2] &= ~cTopMask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 buf[2] |= adjust;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 return 0;
470}
471
Michael Krufky710401b2007-12-16 19:53:32 -0300472static int tda9887_do_config(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300474 struct tda9887_priv *priv = fe->analog_demod_priv;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300475 char *buf = priv->data;
476
Michael Krufky710401b2007-12-16 19:53:32 -0300477 if (priv->config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 buf[1] &= ~cOutputPort1Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300479 if (priv->config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 buf[1] |= cOutputPort1Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300481 if (priv->config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 buf[1] &= ~cOutputPort2Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300483 if (priv->config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 buf[1] |= cOutputPort2Inactive;
485
Michael Krufky710401b2007-12-16 19:53:32 -0300486 if (priv->config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 buf[1] |= cQSS;
Michael Krufky710401b2007-12-16 19:53:32 -0300488 if (priv->config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 buf[1] &= ~cQSS;
490
Michael Krufky710401b2007-12-16 19:53:32 -0300491 if (priv->config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 buf[1] |= cAutoMuteFmActive;
Michael Krufky710401b2007-12-16 19:53:32 -0300493 if (priv->config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 buf[2] &= ~0x60;
Michael Krufky710401b2007-12-16 19:53:32 -0300495 switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 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 }
Michael Krufky710401b2007-12-16 19:53:32 -0300507 if (priv->config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200508 buf[2] &= ~cTopMask;
Michael Krufky710401b2007-12-16 19:53:32 -0300509 buf[2] |= (priv->config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200510 }
Michael Krufky710401b2007-12-16 19:53:32 -0300511 if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300512 (priv->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800513 buf[1] &= ~cQSS;
Michael Krufky710401b2007-12-16 19:53:32 -0300514 if (priv->config & TDA9887_GATING_18)
Trent Piephod7304de2006-08-24 22:43:45 -0300515 buf[3] &= ~cGating_36;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300516
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300517 if (priv->mode == V4L2_TUNER_RADIO) {
Michael Krufky710401b2007-12-16 19:53:32 -0300518 if (priv->config & TDA9887_RIF_41_3) {
Trent Piepho5e082f12007-08-03 18:32:38 -0300519 buf[3] &= ~cVideoIFMask;
520 buf[3] |= cRadioIF_41_30;
521 }
Michael Krufky710401b2007-12-16 19:53:32 -0300522 if (priv->config & TDA9887_GAIN_NORMAL)
Trent Piepho5e082f12007-08-03 18:32:38 -0300523 buf[3] &= ~cTunerGainLow;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300524 }
525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 return 0;
527}
528
529/* ---------------------------------------------------------------------- */
530
Michael Krufky4e9154b2007-10-21 19:39:50 -0300531static int tda9887_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300533 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 unsigned char buf[1];
535 int rc;
536
537 memset(buf,0,sizeof(buf));
Michael Krufkydb8a6952007-08-21 01:24:42 -0300538 if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
Michael Krufky790ba182007-12-16 21:20:21 -0300539 tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300540 dump_read_message(fe, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 return 0;
542}
543
Michael Krufky4e9154b2007-10-21 19:39:50 -0300544static void tda9887_configure(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300546 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 int rc;
548
Michael Krufkyb2083192007-05-29 22:54:06 -0300549 memset(priv->data,0,sizeof(priv->data));
Michael Krufky4e9154b2007-10-21 19:39:50 -0300550 tda9887_set_tvnorm(fe);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700551
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200552 /* 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 */
Michael Krufkyb2083192007-05-29 22:54:06 -0300565 priv->data[1] |= cOutputPort1Inactive;
566 priv->data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700567
Michael Krufky710401b2007-12-16 19:53:32 -0300568 tda9887_do_config(fe);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300569 tda9887_set_insmod(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300571 if (priv->mode == T_STANDBY)
Michael Krufkyb2083192007-05-29 22:54:06 -0300572 priv->data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700573
Michael Krufky790ba182007-12-16 21:20:21 -0300574 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)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300577 dump_write_message(fe, priv->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Michael Krufkydb8a6952007-08-21 01:24:42 -0300579 if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
Michael Krufky790ba182007-12-16 21:20:21 -0300580 tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Michael Krufky790ba182007-12-16 21:20:21 -0300582 if (debug > 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 msleep_interruptible(1000);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300584 tda9887_status(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
588/* ---------------------------------------------------------------------- */
589
Michael Krufky4e9154b2007-10-21 19:39:50 -0300590static void tda9887_tuner_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300592 struct tda9887_priv *priv = fe->analog_demod_priv;
Michael Krufky790ba182007-12-16 21:20:21 -0300593 tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
594 priv->data[1], priv->data[2], priv->data[3]);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300595}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Michael Krufky4e9154b2007-10-21 19:39:50 -0300597static int tda9887_get_afc(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300598{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300599 struct tda9887_priv *priv = fe->analog_demod_priv;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300600 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Michael Krufkydb8a6952007-08-21 01:24:42 -0300609 if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300610 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700611
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300612 return afc;
613}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700614
Michael Krufky4e9154b2007-10-21 19:39:50 -0300615static void tda9887_standby(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300616{
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300617 struct tda9887_priv *priv = fe->analog_demod_priv;
618
619 priv->mode = T_STANDBY;
620
Michael Krufky4e9154b2007-10-21 19:39:50 -0300621 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300622}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800623
Michael Krufkyc7919d52007-12-08 17:06:30 -0300624static void tda9887_set_params(struct dvb_frontend *fe,
625 struct analog_parameters *params)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300626{
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300627 struct tda9887_priv *priv = fe->analog_demod_priv;
628
629 priv->mode = params->mode;
630 priv->audmode = params->audmode;
631 priv->std = params->std;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300632 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300633}
634
Michael Krufky710401b2007-12-16 19:53:32 -0300635static 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
Michael Krufky4e9154b2007-10-21 19:39:50 -0300645static void tda9887_release(struct dvb_frontend *fe)
Michael Krufky024cf532007-06-04 15:20:11 -0300646{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300647 kfree(fe->analog_demod_priv);
648 fe->analog_demod_priv = NULL;
Michael Krufky024cf532007-06-04 15:20:11 -0300649}
650
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300651static struct analog_demod_ops tda9887_ops = {
Michael Krufkya55db8c2007-12-09 13:52:51 -0300652 .info = {
Michael Krufky0f2ce982008-01-21 10:55:37 -0300653 .name = "tda9887",
Michael Krufkya55db8c2007-12-09 13:52:51 -0300654 },
Michael Krufkyc7919d52007-12-08 17:06:30 -0300655 .set_params = tda9887_set_params,
Michael Krufky9af596e2007-06-06 16:15:48 -0300656 .standby = tda9887_standby,
657 .tuner_status = tda9887_tuner_status,
658 .get_afc = tda9887_get_afc,
659 .release = tda9887_release,
Michael Krufky710401b2007-12-16 19:53:32 -0300660 .set_config = tda9887_set_config,
Michael Krufky9af596e2007-06-06 16:15:48 -0300661};
662
Michael Krufky8ca40832007-12-16 20:11:46 -0300663struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
664 struct i2c_adapter *i2c_adap,
665 u8 i2c_addr)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300666{
Michael Krufkyb2083192007-05-29 22:54:06 -0300667 struct tda9887_priv *priv = NULL;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300668
Michael Krufkyb2083192007-05-29 22:54:06 -0300669 priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
670 if (priv == NULL)
Michael Krufky8ca40832007-12-16 20:11:46 -0300671 return NULL;
672 fe->analog_demod_priv = priv;
Michael Krufkyb2083192007-05-29 22:54:06 -0300673
Michael Krufky8ca40832007-12-16 20:11:46 -0300674 priv->i2c_props.addr = i2c_addr;
675 priv->i2c_props.adap = i2c_adap;
Michael Krufky71021d22007-12-17 09:49:33 -0300676 priv->mode = T_STANDBY;
Michael Krufkydb8a6952007-08-21 01:24:42 -0300677
Michael Krufky790ba182007-12-16 21:20:21 -0300678 tuner_info("tda988[5/6/7] found\n");
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300679
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300680 memcpy(&fe->ops.analog_ops, &tda9887_ops,
681 sizeof(struct analog_demod_ops));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300682
Michael Krufky8ca40832007-12-16 20:11:46 -0300683 return fe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684}
Michael Krufky31c95842007-10-21 20:48:48 -0300685EXPORT_SYMBOL_GPL(tda9887_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Michael Krufky5ef47302007-10-27 02:17:19 -0300687MODULE_LICENSE("GPL");
688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689/*
690 * Overrides for Emacs so that we follow Linus's tabbing style.
691 * ---------------------------------------------------------------------------
692 * Local variables:
693 * c-basic-offset: 8
694 * End:
695 */