blob: 98d45c4912bd0514a28785ee963f795957f55383 [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 Krufky31c95842007-10-21 20:48:48 -030024static int tda9887_debug;
25module_param_named(debug, tda9887_debug, int, 0644);
26
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030027#define tda9887_info(fmt, arg...) do {\
Hans Verkuil1cba97d72007-09-14 05:13:54 -030028 printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \
29 i2c_adapter_id(priv->t->i2c->adapter), \
30 priv->t->i2c->addr, ##arg); } while (0)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030031#define tda9887_dbg(fmt, arg...) do {\
Michael Krufky31c95842007-10-21 20:48:48 -030032 if (tda9887_debug) \
Hans Verkuil1cba97d72007-09-14 05:13:54 -030033 printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \
34 i2c_adapter_id(priv->t->i2c->adapter), \
35 priv->t->i2c->addr, ##arg); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Michael Krufkyb2083192007-05-29 22:54:06 -030037struct tda9887_priv {
Michael Krufkydb8a6952007-08-21 01:24:42 -030038 struct tuner_i2c_props i2c_props;
39
Michael Krufkyb2083192007-05-29 22:54:06 -030040 unsigned char data[4];
Michael Krufky4e9154b2007-10-21 19:39:50 -030041
42 struct tuner *t;
Michael Krufkyb2083192007-05-29 22:54:06 -030043};
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45/* ---------------------------------------------------------------------- */
46
47#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49struct tvnorm {
50 v4l2_std_id std;
51 char *name;
52 unsigned char b;
53 unsigned char c;
54 unsigned char e;
55};
56
Linus Torvalds1da177e2005-04-16 15:20:36 -070057/* ---------------------------------------------------------------------- */
58
59//
60// TDA defines
61//
62
63//// first reg (b)
64#define cVideoTrapBypassOFF 0x00 // bit b0
65#define cVideoTrapBypassON 0x01 // bit b0
66
67#define cAutoMuteFmInactive 0x00 // bit b1
68#define cAutoMuteFmActive 0x02 // bit b1
69
70#define cIntercarrier 0x00 // bit b2
71#define cQSS 0x04 // bit b2
72
73#define cPositiveAmTV 0x00 // bit b3:4
74#define cFmRadio 0x08 // bit b3:4
75#define cNegativeFmTV 0x10 // bit b3:4
76
77
78#define cForcedMuteAudioON 0x20 // bit b5
79#define cForcedMuteAudioOFF 0x00 // bit b5
80
81#define cOutputPort1Active 0x00 // bit b6
82#define cOutputPort1Inactive 0x40 // bit b6
83
84#define cOutputPort2Active 0x00 // bit b7
85#define cOutputPort2Inactive 0x80 // bit b7
86
87
88//// second reg (c)
89#define cDeemphasisOFF 0x00 // bit c5
90#define cDeemphasisON 0x20 // bit c5
91
92#define cDeemphasis75 0x00 // bit c6
93#define cDeemphasis50 0x40 // bit c6
94
95#define cAudioGain0 0x00 // bit c7
96#define cAudioGain6 0x80 // bit c7
97
Hans Verkuilf98c55e2006-01-09 15:25:18 -020098#define cTopMask 0x1f // bit c0:4
Hans Verkuilf5b01422006-06-25 15:37:29 -030099#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101//// third reg (e)
102#define cAudioIF_4_5 0x00 // bit e0:1
103#define cAudioIF_5_5 0x01 // bit e0:1
104#define cAudioIF_6_0 0x02 // bit e0:1
105#define cAudioIF_6_5 0x03 // bit e0:1
106
107
Trent Piepho5e082f12007-08-03 18:32:38 -0300108#define cVideoIFMask 0x1c // bit e2:4
109/* Video IF selection in TV Mode (bit B3=0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110#define cVideoIF_58_75 0x00 // bit e2:4
111#define cVideoIF_45_75 0x04 // bit e2:4
112#define cVideoIF_38_90 0x08 // bit e2:4
113#define cVideoIF_38_00 0x0C // bit e2:4
114#define cVideoIF_33_90 0x10 // bit e2:4
115#define cVideoIF_33_40 0x14 // bit e2:4
116#define cRadioIF_45_75 0x18 // bit e2:4
117#define cRadioIF_38_90 0x1C // bit e2:4
118
Trent Piepho5e082f12007-08-03 18:32:38 -0300119/* IF1 selection in Radio Mode (bit B3=1) */
120#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
121#define cRadioIF_41_30 0x04 // bit e2,4
122
123/* Output of AFC pin in radio mode when bit E7=1 */
124#define cRadioAGC_SIF 0x00 // bit e3
125#define cRadioAGC_FM 0x08 // bit e3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127#define cTunerGainNormal 0x00 // bit e5
128#define cTunerGainLow 0x20 // bit e5
129
130#define cGating_18 0x00 // bit e6
131#define cGating_36 0x40 // bit e6
132
133#define cAgcOutON 0x80 // bit e7
134#define cAgcOutOFF 0x00 // bit e7
135
136/* ---------------------------------------------------------------------- */
137
138static struct tvnorm tvnorms[] = {
139 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200140 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
141 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 .b = ( cNegativeFmTV |
143 cQSS ),
144 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200145 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300146 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200147 .e = ( cGating_36 |
148 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 cVideoIF_38_90 ),
150 },{
151 .std = V4L2_STD_PAL_I,
152 .name = "PAL-I",
153 .b = ( cNegativeFmTV |
154 cQSS ),
155 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200156 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300157 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200158 .e = ( cGating_36 |
159 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 cVideoIF_38_90 ),
161 },{
162 .std = V4L2_STD_PAL_DK,
163 .name = "PAL-DK",
164 .b = ( cNegativeFmTV |
165 cQSS ),
166 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200167 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300168 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200169 .e = ( cGating_36 |
170 cAudioIF_6_5 |
171 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200173 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
174 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 .b = ( cNegativeFmTV |
176 cQSS ),
177 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200178 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300179 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200180 .e = ( cGating_36 |
181 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 cVideoIF_45_75 ),
183 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200184 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
185 .name = "SECAM-BGH",
186 .b = ( cPositiveAmTV |
187 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300188 .c = ( cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200189 .e = ( cGating_36 |
190 cAudioIF_5_5 |
191 cVideoIF_38_90 ),
192 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 .std = V4L2_STD_SECAM_L,
194 .name = "SECAM-L",
195 .b = ( cPositiveAmTV |
196 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300197 .c = ( cTopDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800198 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800199 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 cVideoIF_38_90 ),
201 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200202 .std = V4L2_STD_SECAM_LC,
203 .name = "SECAM-L'",
204 .b = ( cOutputPort2Inactive |
205 cPositiveAmTV |
206 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300207 .c = ( cTopDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200208 .e = ( cGating_36 |
209 cAudioIF_6_5 |
210 cVideoIF_33_90 ),
211 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 .std = V4L2_STD_SECAM_DK,
213 .name = "SECAM-DK",
214 .b = ( cNegativeFmTV |
215 cQSS ),
216 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200217 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300218 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200219 .e = ( cGating_36 |
220 cAudioIF_6_5 |
221 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200223 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 .name = "NTSC-M",
225 .b = ( cNegativeFmTV |
226 cQSS ),
227 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200228 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300229 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 .e = ( cGating_36 |
231 cAudioIF_4_5 |
232 cVideoIF_45_75 ),
233 },{
234 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200235 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 .b = ( cNegativeFmTV |
237 cQSS ),
238 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200239 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300240 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 .e = ( cGating_36 |
242 cAudioIF_4_5 |
243 cVideoIF_58_75 ),
244 }
245};
246
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700247static struct tvnorm radio_stereo = {
248 .name = "Radio Stereo",
249 .b = ( cFmRadio |
250 cQSS ),
251 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200252 cAudioGain6 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300253 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200254 .e = ( cTunerGainLow |
255 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700256 cRadioIF_38_90 ),
257};
258
259static struct tvnorm radio_mono = {
260 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 .b = ( cFmRadio |
262 cQSS ),
263 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200264 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300265 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200266 .e = ( cTunerGainLow |
267 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 cRadioIF_38_90 ),
269};
270
271/* ---------------------------------------------------------------------- */
272
Michael Krufky4e9154b2007-10-21 19:39:50 -0300273static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300275 struct tda9887_priv *priv = fe->analog_demod_priv;
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 static char *afc[16] = {
278 "- 12.5 kHz",
279 "- 37.5 kHz",
280 "- 62.5 kHz",
281 "- 87.5 kHz",
282 "-112.5 kHz",
283 "-137.5 kHz",
284 "-162.5 kHz",
285 "-187.5 kHz [min]",
286 "+187.5 kHz [max]",
287 "+162.5 kHz",
288 "+137.5 kHz",
289 "+112.5 kHz",
290 "+ 87.5 kHz",
291 "+ 62.5 kHz",
292 "+ 37.5 kHz",
293 "+ 12.5 kHz",
294 };
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800295 tda9887_info("read: 0x%2x\n", buf[0]);
296 tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
297 tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
298 tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
299 tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
300 tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
Michael Krufky4e9154b2007-10-21 19:39:50 -0300303static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300305 struct tda9887_priv *priv = fe->analog_demod_priv;
306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 static char *sound[4] = {
308 "AM/TV",
309 "FM/radio",
310 "FM/TV",
311 "FM/radio"
312 };
313 static char *adjust[32] = {
314 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
315 "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
316 "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
317 "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
318 };
319 static char *deemph[4] = {
320 "no", "no", "75", "50"
321 };
322 static char *carrier[4] = {
323 "4.5 MHz",
324 "5.5 MHz",
325 "6.0 MHz",
326 "6.5 MHz / AM"
327 };
328 static char *vif[8] = {
329 "58.75 MHz",
330 "45.75 MHz",
331 "38.9 MHz",
332 "38.0 MHz",
333 "33.9 MHz",
334 "33.4 MHz",
335 "45.75 MHz + pin13",
336 "38.9 MHz + pin13",
337 };
338 static char *rif[4] = {
339 "44 MHz",
340 "52 MHz",
341 "52 MHz",
342 "44 MHz",
343 };
344
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800345 tda9887_info("write: byte B 0x%02x\n",buf[1]);
346 tda9887_info(" B0 video mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 (buf[1] & 0x01) ? "video trap" : "sound trap");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800348 tda9887_info(" B1 auto mute fm : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 (buf[1] & 0x02) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800350 tda9887_info(" B2 carrier mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 (buf[1] & 0x04) ? "QSS" : "Intercarrier");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800352 tda9887_info(" B3-4 tv sound/radio : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 sound[(buf[1] & 0x18) >> 3]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800354 tda9887_info(" B5 force mute audio: %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 (buf[1] & 0x20) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800356 tda9887_info(" B6 output port 1 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800358 tda9887_info(" B7 output port 2 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
360
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800361 tda9887_info("write: byte C 0x%02x\n",buf[2]);
362 tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
363 tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
364 tda9887_info(" C7 audio gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 (buf[2] & 0x80) ? "-6" : "0");
366
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800367 tda9887_info("write: byte E 0x%02x\n",buf[3]);
368 tda9887_info(" E0-1 sound carrier : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 carrier[(buf[3] & 0x03)]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800370 tda9887_info(" E6 l pll gating : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 (buf[3] & 0x40) ? "36" : "13");
372
373 if (buf[1] & 0x08) {
374 /* radio */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800375 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 rif[(buf[3] & 0x0c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800377 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 (buf[3] & 0x80)
379 ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
380 : "fm radio carrier afc");
381 } else {
382 /* video */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800383 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 vif[(buf[3] & 0x1c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800385 tda9887_info(" E5 tuner gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 (buf[3] & 0x80)
387 ? ((buf[3] & 0x20) ? "external" : "normal")
388 : ((buf[3] & 0x20) ? "minimum" : "normal"));
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800389 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 (buf[3] & 0x80)
391 ? ((buf[3] & 0x20)
392 ? "pin3 port, pin22 vif agc out"
393 : "pin22 port, pin3 vif acg ext in")
394 : "pin3+pin22 port");
395 }
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800396 tda9887_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397}
398
399/* ---------------------------------------------------------------------- */
400
Michael Krufky4e9154b2007-10-21 19:39:50 -0300401static int tda9887_set_tvnorm(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300403 struct tda9887_priv *priv = fe->analog_demod_priv;
404 struct tuner *t = priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 struct tvnorm *norm = NULL;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300406 char *buf = priv->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 int i;
408
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300409 if (t->mode == V4L2_TUNER_RADIO) {
410 if (t->audmode == V4L2_TUNER_MODE_MONO)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700411 norm = &radio_mono;
412 else
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700413 norm = &radio_stereo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 } else {
415 for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
416 if (tvnorms[i].std & t->std) {
417 norm = tvnorms+i;
418 break;
419 }
420 }
421 }
422 if (NULL == norm) {
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800423 tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return -1;
425 }
426
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800427 tda9887_dbg("configure for: %s\n",norm->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 buf[1] = norm->b;
429 buf[2] = norm->c;
430 buf[3] = norm->e;
431 return 0;
432}
433
434static unsigned int port1 = UNSET;
435static unsigned int port2 = UNSET;
436static unsigned int qss = UNSET;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200437static unsigned int adjust = UNSET;
438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439module_param(port1, int, 0644);
440module_param(port2, int, 0644);
441module_param(qss, int, 0644);
442module_param(adjust, int, 0644);
443
Michael Krufky4e9154b2007-10-21 19:39:50 -0300444static int tda9887_set_insmod(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300446 struct tda9887_priv *priv = fe->analog_demod_priv;
447 char *buf = priv->data;
448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 if (UNSET != port1) {
450 if (port1)
451 buf[1] |= cOutputPort1Inactive;
452 else
453 buf[1] &= ~cOutputPort1Inactive;
454 }
455 if (UNSET != port2) {
456 if (port2)
457 buf[1] |= cOutputPort2Inactive;
458 else
459 buf[1] &= ~cOutputPort2Inactive;
460 }
461
462 if (UNSET != qss) {
463 if (qss)
464 buf[1] |= cQSS;
465 else
466 buf[1] &= ~cQSS;
467 }
468
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200469 if (adjust >= 0x00 && adjust < 0x20) {
470 buf[2] &= ~cTopMask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 buf[2] |= adjust;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 return 0;
474}
475
Michael Krufky4e9154b2007-10-21 19:39:50 -0300476static int tda9887_set_config(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300478 struct tda9887_priv *priv = fe->analog_demod_priv;
479 struct tuner *t = priv->t;
480 char *buf = priv->data;
481
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300482 if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 buf[1] &= ~cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300484 if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 buf[1] |= cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300486 if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 buf[1] &= ~cOutputPort2Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300488 if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 buf[1] |= cOutputPort2Inactive;
490
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300491 if (t->tda9887_config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 buf[1] |= cQSS;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300493 if (t->tda9887_config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 buf[1] &= ~cQSS;
495
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300496 if (t->tda9887_config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 buf[1] |= cAutoMuteFmActive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300498 if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 buf[2] &= ~0x60;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300500 switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 case TDA9887_DEEMPHASIS_NONE:
502 buf[2] |= cDeemphasisOFF;
503 break;
504 case TDA9887_DEEMPHASIS_50:
505 buf[2] |= cDeemphasisON | cDeemphasis50;
506 break;
507 case TDA9887_DEEMPHASIS_75:
508 buf[2] |= cDeemphasisON | cDeemphasis75;
509 break;
510 }
511 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300512 if (t->tda9887_config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200513 buf[2] &= ~cTopMask;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300514 buf[2] |= (t->tda9887_config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200515 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300516 if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800517 buf[1] &= ~cQSS;
Trent Piephod7304de2006-08-24 22:43:45 -0300518 if (t->tda9887_config & TDA9887_GATING_18)
519 buf[3] &= ~cGating_36;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300520
Trent Piepho5e082f12007-08-03 18:32:38 -0300521 if (t->mode == V4L2_TUNER_RADIO) {
522 if (t->tda9887_config & TDA9887_RIF_41_3) {
523 buf[3] &= ~cVideoIFMask;
524 buf[3] |= cRadioIF_41_30;
525 }
526 if (t->tda9887_config & TDA9887_GAIN_NORMAL)
527 buf[3] &= ~cTunerGainLow;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300528 }
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 return 0;
531}
532
533/* ---------------------------------------------------------------------- */
534
Michael Krufky4e9154b2007-10-21 19:39:50 -0300535static int tda9887_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300537 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 unsigned char buf[1];
539 int rc;
540
541 memset(buf,0,sizeof(buf));
Michael Krufkydb8a6952007-08-21 01:24:42 -0300542 if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800543 tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300544 dump_read_message(fe, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return 0;
546}
547
Michael Krufky4e9154b2007-10-21 19:39:50 -0300548static void tda9887_configure(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300550 struct tda9887_priv *priv = fe->analog_demod_priv;
551 struct tuner *t = priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 int rc;
553
Michael Krufkyb2083192007-05-29 22:54:06 -0300554 memset(priv->data,0,sizeof(priv->data));
Michael Krufky4e9154b2007-10-21 19:39:50 -0300555 tda9887_set_tvnorm(fe);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700556
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200557 /* A note on the port settings:
558 These settings tend to depend on the specifics of the board.
559 By default they are set to inactive (bit value 1) by this driver,
560 overwriting any changes made by the tvnorm. This means that it
561 is the responsibility of the module using the tda9887 to set
562 these values in case of changes in the tvnorm.
563 In many cases port 2 should be made active (0) when selecting
564 SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
565
566 For the other standards the tda9887 application note says that
567 the ports should be set to active (0), but, again, that may
568 differ depending on the precise hardware configuration.
569 */
Michael Krufkyb2083192007-05-29 22:54:06 -0300570 priv->data[1] |= cOutputPort1Inactive;
571 priv->data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700572
Michael Krufky4e9154b2007-10-21 19:39:50 -0300573 tda9887_set_config(fe);
574 tda9887_set_insmod(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700576 if (t->mode == T_STANDBY) {
Michael Krufkyb2083192007-05-29 22:54:06 -0300577 priv->data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700578 }
579
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800580 tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
Michael Krufkyb2083192007-05-29 22:54:06 -0300581 priv->data[1],priv->data[2],priv->data[3]);
Michael Krufky31c95842007-10-21 20:48:48 -0300582 if (tda9887_debug > 1)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300583 dump_write_message(fe, priv->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
Michael Krufkydb8a6952007-08-21 01:24:42 -0300585 if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800586 tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Michael Krufky31c95842007-10-21 20:48:48 -0300588 if (tda9887_debug > 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 msleep_interruptible(1000);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300590 tda9887_status(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592}
593
594/* ---------------------------------------------------------------------- */
595
Michael Krufky4e9154b2007-10-21 19:39:50 -0300596static void tda9887_tuner_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300598 struct tda9887_priv *priv = fe->analog_demod_priv;
Michael Krufky31c95842007-10-21 20:48:48 -0300599 tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
600 priv->data[1], priv->data[2], priv->data[3]);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300601}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Michael Krufky4e9154b2007-10-21 19:39:50 -0300603static int tda9887_get_afc(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300604{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300605 struct tda9887_priv *priv = fe->analog_demod_priv;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300606 static int AFC_BITS_2_kHz[] = {
607 -12500, -37500, -62500, -97500,
608 -112500, -137500, -162500, -187500,
609 187500, 162500, 137500, 112500,
610 97500 , 62500, 37500 , 12500
611 };
612 int afc=0;
613 __u8 reg = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Michael Krufkydb8a6952007-08-21 01:24:42 -0300615 if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300616 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700617
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300618 return afc;
619}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700620
Michael Krufky4e9154b2007-10-21 19:39:50 -0300621static void tda9887_standby(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300622{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300623 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300624}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800625
Michael Krufkyc7919d52007-12-08 17:06:30 -0300626static void tda9887_set_params(struct dvb_frontend *fe,
627 struct analog_parameters *params)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300628{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300629 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300630}
631
Michael Krufky4e9154b2007-10-21 19:39:50 -0300632static void tda9887_release(struct dvb_frontend *fe)
Michael Krufky024cf532007-06-04 15:20:11 -0300633{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300634 kfree(fe->analog_demod_priv);
635 fe->analog_demod_priv = NULL;
Michael Krufky024cf532007-06-04 15:20:11 -0300636}
637
Michael Krufky1dde7a42007-10-21 13:40:56 -0300638static struct analog_tuner_ops tda9887_tuner_ops = {
Michael Krufkyc7919d52007-12-08 17:06:30 -0300639 .set_params = tda9887_set_params,
Michael Krufky9af596e2007-06-06 16:15:48 -0300640 .standby = tda9887_standby,
641 .tuner_status = tda9887_tuner_status,
642 .get_afc = tda9887_get_afc,
643 .release = tda9887_release,
644};
645
Michael Krufky31c95842007-10-21 20:48:48 -0300646int tda9887_attach(struct tuner *t)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300647{
Michael Krufkyb2083192007-05-29 22:54:06 -0300648 struct tda9887_priv *priv = NULL;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300649
Michael Krufkyb2083192007-05-29 22:54:06 -0300650 priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
651 if (priv == NULL)
652 return -ENOMEM;
Michael Krufky16f29162007-10-21 15:22:25 -0300653 t->fe.analog_demod_priv = priv;
Michael Krufkyb2083192007-05-29 22:54:06 -0300654
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300655 priv->i2c_props.addr = t->i2c->addr;
656 priv->i2c_props.adap = t->i2c->adapter;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300657 priv->t = t;
Michael Krufkydb8a6952007-08-21 01:24:42 -0300658
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300659 strlcpy(t->i2c->name, "tda9887", sizeof(t->i2c->name));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300660
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300661 tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c->addr,
662 t->i2c->driver->driver.name);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300663
Michael Krufky1dde7a42007-10-21 13:40:56 -0300664 t->fe.ops.analog_demod_ops = &tda9887_tuner_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 return 0;
667}
Michael Krufky31c95842007-10-21 20:48:48 -0300668EXPORT_SYMBOL_GPL(tda9887_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Michael Krufky5ef47302007-10-27 02:17:19 -0300670MODULE_LICENSE("GPL");
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672/*
673 * Overrides for Emacs so that we follow Linus's tabbing style.
674 * ---------------------------------------------------------------------------
675 * Local variables:
676 * c-basic-offset: 8
677 * End:
678 */