blob: bf14bd79e2fc599b7216e43d0a1c78564479dd7e [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007#include <linux/delay.h>
Hans Verkuilf894dfd2008-07-25 07:39:54 -03008#include <linux/videodev2.h>
Michael Krufky5e453dc2006-01-09 15:32:31 -02009#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <media/tuner.h>
Michael Krufkyab166052007-12-09 02:26:48 -030011#include "tuner-i2c.h"
Michael Krufky31c95842007-10-21 20:48:48 -030012#include "tda9887.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -080014
Linus Torvalds1da177e2005-04-16 15:20:36 -070015/* Chips:
16 TDA9885 (PAL, NTSC)
17 TDA9886 (PAL, SECAM, NTSC)
18 TDA9887 (PAL, SECAM, NTSC, FM Radio)
19
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030020 Used as part of several tuners
Linus Torvalds1da177e2005-04-16 15:20:36 -070021*/
22
Michael Krufky790ba182007-12-16 21:20:21 -030023static int debug;
24module_param(debug, int, 0644);
25MODULE_PARM_DESC(debug, "enable verbose debug messages");
Michael Krufky31c95842007-10-21 20:48:48 -030026
Michael Krufkyac8b63b2008-04-22 14:45:51 -030027static DEFINE_MUTEX(tda9887_list_mutex);
28static LIST_HEAD(hybrid_tuner_instance_list);
29
Michael Krufkyb2083192007-05-29 22:54:06 -030030struct tda9887_priv {
Michael Krufkydb8a6952007-08-21 01:24:42 -030031 struct tuner_i2c_props i2c_props;
Michael Krufkyac8b63b2008-04-22 14:45:51 -030032 struct list_head hybrid_tuner_instance_list;
Michael Krufkydb8a6952007-08-21 01:24:42 -030033
Michael Krufkyb2083192007-05-29 22:54:06 -030034 unsigned char data[4];
Michael Krufky710401b2007-12-16 19:53:32 -030035 unsigned int config;
Michael Krufky91c9d4a2007-12-16 20:05:00 -030036 unsigned int mode;
37 unsigned int audmode;
38 v4l2_std_id std;
Michael Krufkyb2083192007-05-29 22:54:06 -030039};
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* ---------------------------------------------------------------------- */
42
43#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45struct tvnorm {
46 v4l2_std_id std;
47 char *name;
48 unsigned char b;
49 unsigned char c;
50 unsigned char e;
51};
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053/* ---------------------------------------------------------------------- */
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
Hans Verkuilf98c55e2006-01-09 15:25:18 -020094#define cTopMask 0x1f // bit c0:4
Hans Verkuilf5b01422006-06-25 15:37:29 -030095#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
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
Trent Piepho5e082f12007-08-03 18:32:38 -0300104#define cVideoIFMask 0x1c // bit e2:4
105/* Video IF selection in TV Mode (bit B3=0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106#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
Trent Piepho5e082f12007-08-03 18:32:38 -0300115/* 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
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
134static struct tvnorm tvnorms[] = {
135 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200136 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
137 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 .b = ( cNegativeFmTV |
139 cQSS ),
140 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200141 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300142 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200143 .e = ( cGating_36 |
144 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 cVideoIF_38_90 ),
146 },{
147 .std = V4L2_STD_PAL_I,
148 .name = "PAL-I",
149 .b = ( cNegativeFmTV |
150 cQSS ),
151 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200152 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300153 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200154 .e = ( cGating_36 |
155 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 cVideoIF_38_90 ),
157 },{
158 .std = V4L2_STD_PAL_DK,
159 .name = "PAL-DK",
160 .b = ( cNegativeFmTV |
161 cQSS ),
162 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200163 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300164 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200165 .e = ( cGating_36 |
166 cAudioIF_6_5 |
167 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200169 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
170 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 .b = ( cNegativeFmTV |
172 cQSS ),
173 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200174 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300175 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200176 .e = ( cGating_36 |
177 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 cVideoIF_45_75 ),
179 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200180 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
181 .name = "SECAM-BGH",
Frederic CANDb84ca9f2008-10-30 04:53:07 -0300182 .b = ( cNegativeFmTV |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200183 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300184 .c = ( cTopDefault),
Frederic CANDb84ca9f2008-10-30 04:53:07 -0300185 .e = ( cAudioIF_5_5 |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200186 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
Roel Kluinf14a2972009-10-23 07:59:42 -0300465 if (adjust < 0x20) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200466 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 Krufkyac8b63b2008-04-22 14:45:51 -0300647 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
Michael Krufky4e9154b2007-10-21 19:39:50 -0300656 fe->analog_demod_priv = NULL;
Michael Krufky024cf532007-06-04 15:20:11 -0300657}
658
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300659static struct analog_demod_ops tda9887_ops = {
Michael Krufkya55db8c2007-12-09 13:52:51 -0300660 .info = {
Michael Krufky0f2ce982008-01-21 10:55:37 -0300661 .name = "tda9887",
Michael Krufkya55db8c2007-12-09 13:52:51 -0300662 },
Michael Krufkyc7919d52007-12-08 17:06:30 -0300663 .set_params = tda9887_set_params,
Michael Krufky9af596e2007-06-06 16:15:48 -0300664 .standby = tda9887_standby,
665 .tuner_status = tda9887_tuner_status,
666 .get_afc = tda9887_get_afc,
667 .release = tda9887_release,
Michael Krufky710401b2007-12-16 19:53:32 -0300668 .set_config = tda9887_set_config,
Michael Krufky9af596e2007-06-06 16:15:48 -0300669};
670
Michael Krufky8ca40832007-12-16 20:11:46 -0300671struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
672 struct i2c_adapter *i2c_adap,
673 u8 i2c_addr)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300674{
Michael Krufkyb2083192007-05-29 22:54:06 -0300675 struct tda9887_priv *priv = NULL;
Michael Krufkyac8b63b2008-04-22 14:45:51 -0300676 int instance;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300677
Michael Krufkyac8b63b2008-04-22 14:45:51 -0300678 mutex_lock(&tda9887_list_mutex);
679
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);
Michael Krufky8ca40832007-12-16 20:11:46 -0300686 return NULL;
Michael Krufkyac8b63b2008-04-22 14:45:51 -0300687 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 }
Michael Krufkyb2083192007-05-29 22:54:06 -0300696
Michael Krufkyac8b63b2008-04-22 14:45:51 -0300697 mutex_unlock(&tda9887_list_mutex);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300698
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300699 memcpy(&fe->ops.analog_ops, &tda9887_ops,
700 sizeof(struct analog_demod_ops));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300701
Michael Krufky8ca40832007-12-16 20:11:46 -0300702 return fe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703}
Michael Krufky31c95842007-10-21 20:48:48 -0300704EXPORT_SYMBOL_GPL(tda9887_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Michael Krufky5ef47302007-10-27 02:17:19 -0300706MODULE_LICENSE("GPL");
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708/*
709 * Overrides for Emacs so that we follow Linus's tabbing style.
710 * ---------------------------------------------------------------------------
711 * Local variables:
712 * c-basic-offset: 8
713 * End:
714 */