blob: b6ae969563b2ba9e3d6cefde6e51bcd21b7cbc43 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/module.h>
2#include <linux/moduleparam.h>
3#include <linux/kernel.h>
4#include <linux/i2c.h>
5#include <linux/types.h>
6#include <linux/videodev.h>
7#include <linux/init.h>
8#include <linux/errno.h>
9#include <linux/slab.h>
10#include <linux/delay.h>
11
Michael Krufky5e453dc2006-01-09 15:32:31 -020012#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <media/tuner.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
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030024#define tda9887_info(fmt, arg...) do {\
25 printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
26 i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
27#define tda9887_dbg(fmt, arg...) do {\
28 if (tuner_debug) \
29 printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
30 i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33/* ---------------------------------------------------------------------- */
34
35#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37struct tvnorm {
38 v4l2_std_id std;
39 char *name;
40 unsigned char b;
41 unsigned char c;
42 unsigned char e;
43};
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045/* ---------------------------------------------------------------------- */
46
47//
48// TDA defines
49//
50
51//// first reg (b)
52#define cVideoTrapBypassOFF 0x00 // bit b0
53#define cVideoTrapBypassON 0x01 // bit b0
54
55#define cAutoMuteFmInactive 0x00 // bit b1
56#define cAutoMuteFmActive 0x02 // bit b1
57
58#define cIntercarrier 0x00 // bit b2
59#define cQSS 0x04 // bit b2
60
61#define cPositiveAmTV 0x00 // bit b3:4
62#define cFmRadio 0x08 // bit b3:4
63#define cNegativeFmTV 0x10 // bit b3:4
64
65
66#define cForcedMuteAudioON 0x20 // bit b5
67#define cForcedMuteAudioOFF 0x00 // bit b5
68
69#define cOutputPort1Active 0x00 // bit b6
70#define cOutputPort1Inactive 0x40 // bit b6
71
72#define cOutputPort2Active 0x00 // bit b7
73#define cOutputPort2Inactive 0x80 // bit b7
74
75
76//// second reg (c)
77#define cDeemphasisOFF 0x00 // bit c5
78#define cDeemphasisON 0x20 // bit c5
79
80#define cDeemphasis75 0x00 // bit c6
81#define cDeemphasis50 0x40 // bit c6
82
83#define cAudioGain0 0x00 // bit c7
84#define cAudioGain6 0x80 // bit c7
85
Hans Verkuilf98c55e2006-01-09 15:25:18 -020086#define cTopMask 0x1f // bit c0:4
87#define cTopPalSecamDefault 0x14 // bit c0:4
88#define cTopNtscRadioDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90//// third reg (e)
91#define cAudioIF_4_5 0x00 // bit e0:1
92#define cAudioIF_5_5 0x01 // bit e0:1
93#define cAudioIF_6_0 0x02 // bit e0:1
94#define cAudioIF_6_5 0x03 // bit e0:1
95
96
97#define cVideoIF_58_75 0x00 // bit e2:4
98#define cVideoIF_45_75 0x04 // bit e2:4
99#define cVideoIF_38_90 0x08 // bit e2:4
100#define cVideoIF_38_00 0x0C // bit e2:4
101#define cVideoIF_33_90 0x10 // bit e2:4
102#define cVideoIF_33_40 0x14 // bit e2:4
103#define cRadioIF_45_75 0x18 // bit e2:4
104#define cRadioIF_38_90 0x1C // bit e2:4
105
106
107#define cTunerGainNormal 0x00 // bit e5
108#define cTunerGainLow 0x20 // bit e5
109
110#define cGating_18 0x00 // bit e6
111#define cGating_36 0x40 // bit e6
112
113#define cAgcOutON 0x80 // bit e7
114#define cAgcOutOFF 0x00 // bit e7
115
116/* ---------------------------------------------------------------------- */
117
118static struct tvnorm tvnorms[] = {
119 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200120 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
121 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 .b = ( cNegativeFmTV |
123 cQSS ),
124 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200125 cDeemphasis50 |
126 cTopPalSecamDefault),
127 .e = ( cGating_36 |
128 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 cVideoIF_38_90 ),
130 },{
131 .std = V4L2_STD_PAL_I,
132 .name = "PAL-I",
133 .b = ( cNegativeFmTV |
134 cQSS ),
135 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200136 cDeemphasis50 |
137 cTopPalSecamDefault),
138 .e = ( cGating_36 |
139 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 cVideoIF_38_90 ),
141 },{
142 .std = V4L2_STD_PAL_DK,
143 .name = "PAL-DK",
144 .b = ( cNegativeFmTV |
145 cQSS ),
146 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200147 cDeemphasis50 |
148 cTopPalSecamDefault),
149 .e = ( cGating_36 |
150 cAudioIF_6_5 |
151 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200153 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
154 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 .b = ( cNegativeFmTV |
156 cQSS ),
157 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200158 cDeemphasis75 |
159 cTopNtscRadioDefault),
160 .e = ( cGating_36 |
161 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 cVideoIF_45_75 ),
163 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200164 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
165 .name = "SECAM-BGH",
166 .b = ( cPositiveAmTV |
167 cQSS ),
168 .c = ( cTopPalSecamDefault),
169 .e = ( cGating_36 |
170 cAudioIF_5_5 |
171 cVideoIF_38_90 ),
172 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 .std = V4L2_STD_SECAM_L,
174 .name = "SECAM-L",
175 .b = ( cPositiveAmTV |
176 cQSS ),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200177 .c = ( cTopPalSecamDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800178 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800179 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 cVideoIF_38_90 ),
181 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200182 .std = V4L2_STD_SECAM_LC,
183 .name = "SECAM-L'",
184 .b = ( cOutputPort2Inactive |
185 cPositiveAmTV |
186 cQSS ),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200187 .c = ( cTopPalSecamDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200188 .e = ( cGating_36 |
189 cAudioIF_6_5 |
190 cVideoIF_33_90 ),
191 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 .std = V4L2_STD_SECAM_DK,
193 .name = "SECAM-DK",
194 .b = ( cNegativeFmTV |
195 cQSS ),
196 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200197 cDeemphasis50 |
198 cTopPalSecamDefault),
199 .e = ( cGating_36 |
200 cAudioIF_6_5 |
201 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200203 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 .name = "NTSC-M",
205 .b = ( cNegativeFmTV |
206 cQSS ),
207 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200208 cDeemphasis75 |
209 cTopNtscRadioDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 .e = ( cGating_36 |
211 cAudioIF_4_5 |
212 cVideoIF_45_75 ),
213 },{
214 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200215 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 .b = ( cNegativeFmTV |
217 cQSS ),
218 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200219 cDeemphasis50 |
220 cTopNtscRadioDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 .e = ( cGating_36 |
222 cAudioIF_4_5 |
223 cVideoIF_58_75 ),
224 }
225};
226
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700227static struct tvnorm radio_stereo = {
228 .name = "Radio Stereo",
229 .b = ( cFmRadio |
230 cQSS ),
231 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200232 cAudioGain6 |
233 cTopNtscRadioDefault),
234 .e = ( cTunerGainLow |
235 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700236 cRadioIF_38_90 ),
237};
238
239static struct tvnorm radio_mono = {
240 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 .b = ( cFmRadio |
242 cQSS ),
243 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200244 cDeemphasis75 |
245 cTopNtscRadioDefault),
246 .e = ( cTunerGainLow |
247 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 cRadioIF_38_90 ),
249};
250
251/* ---------------------------------------------------------------------- */
252
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300253static void dump_read_message(struct tuner *t, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
255 static char *afc[16] = {
256 "- 12.5 kHz",
257 "- 37.5 kHz",
258 "- 62.5 kHz",
259 "- 87.5 kHz",
260 "-112.5 kHz",
261 "-137.5 kHz",
262 "-162.5 kHz",
263 "-187.5 kHz [min]",
264 "+187.5 kHz [max]",
265 "+162.5 kHz",
266 "+137.5 kHz",
267 "+112.5 kHz",
268 "+ 87.5 kHz",
269 "+ 62.5 kHz",
270 "+ 37.5 kHz",
271 "+ 12.5 kHz",
272 };
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800273 tda9887_info("read: 0x%2x\n", buf[0]);
274 tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
275 tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
276 tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
277 tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
278 tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300281static void dump_write_message(struct tuner *t, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
283 static char *sound[4] = {
284 "AM/TV",
285 "FM/radio",
286 "FM/TV",
287 "FM/radio"
288 };
289 static char *adjust[32] = {
290 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
291 "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
292 "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
293 "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
294 };
295 static char *deemph[4] = {
296 "no", "no", "75", "50"
297 };
298 static char *carrier[4] = {
299 "4.5 MHz",
300 "5.5 MHz",
301 "6.0 MHz",
302 "6.5 MHz / AM"
303 };
304 static char *vif[8] = {
305 "58.75 MHz",
306 "45.75 MHz",
307 "38.9 MHz",
308 "38.0 MHz",
309 "33.9 MHz",
310 "33.4 MHz",
311 "45.75 MHz + pin13",
312 "38.9 MHz + pin13",
313 };
314 static char *rif[4] = {
315 "44 MHz",
316 "52 MHz",
317 "52 MHz",
318 "44 MHz",
319 };
320
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800321 tda9887_info("write: byte B 0x%02x\n",buf[1]);
322 tda9887_info(" B0 video mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 (buf[1] & 0x01) ? "video trap" : "sound trap");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800324 tda9887_info(" B1 auto mute fm : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 (buf[1] & 0x02) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800326 tda9887_info(" B2 carrier mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 (buf[1] & 0x04) ? "QSS" : "Intercarrier");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800328 tda9887_info(" B3-4 tv sound/radio : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 sound[(buf[1] & 0x18) >> 3]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800330 tda9887_info(" B5 force mute audio: %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 (buf[1] & 0x20) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800332 tda9887_info(" B6 output port 1 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800334 tda9887_info(" B7 output port 2 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
336
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800337 tda9887_info("write: byte C 0x%02x\n",buf[2]);
338 tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
339 tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
340 tda9887_info(" C7 audio gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 (buf[2] & 0x80) ? "-6" : "0");
342
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800343 tda9887_info("write: byte E 0x%02x\n",buf[3]);
344 tda9887_info(" E0-1 sound carrier : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 carrier[(buf[3] & 0x03)]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800346 tda9887_info(" E6 l pll gating : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 (buf[3] & 0x40) ? "36" : "13");
348
349 if (buf[1] & 0x08) {
350 /* radio */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800351 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 rif[(buf[3] & 0x0c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800353 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 (buf[3] & 0x80)
355 ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
356 : "fm radio carrier afc");
357 } else {
358 /* video */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800359 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 vif[(buf[3] & 0x1c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800361 tda9887_info(" E5 tuner gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 (buf[3] & 0x80)
363 ? ((buf[3] & 0x20) ? "external" : "normal")
364 : ((buf[3] & 0x20) ? "minimum" : "normal"));
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800365 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 (buf[3] & 0x80)
367 ? ((buf[3] & 0x20)
368 ? "pin3 port, pin22 vif agc out"
369 : "pin22 port, pin3 vif acg ext in")
370 : "pin3+pin22 port");
371 }
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800372 tda9887_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
375/* ---------------------------------------------------------------------- */
376
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300377static int tda9887_set_tvnorm(struct tuner *t, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
379 struct tvnorm *norm = NULL;
380 int i;
381
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300382 if (t->mode == V4L2_TUNER_RADIO) {
383 if (t->audmode == V4L2_TUNER_MODE_MONO)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700384 norm = &radio_mono;
385 else
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700386 norm = &radio_stereo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 } else {
388 for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
389 if (tvnorms[i].std & t->std) {
390 norm = tvnorms+i;
391 break;
392 }
393 }
394 }
395 if (NULL == norm) {
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800396 tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return -1;
398 }
399
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800400 tda9887_dbg("configure for: %s\n",norm->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 buf[1] = norm->b;
402 buf[2] = norm->c;
403 buf[3] = norm->e;
404 return 0;
405}
406
407static unsigned int port1 = UNSET;
408static unsigned int port2 = UNSET;
409static unsigned int qss = UNSET;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200410static unsigned int adjust = UNSET;
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412module_param(port1, int, 0644);
413module_param(port2, int, 0644);
414module_param(qss, int, 0644);
415module_param(adjust, int, 0644);
416
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300417static int tda9887_set_insmod(struct tuner *t, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
419 if (UNSET != port1) {
420 if (port1)
421 buf[1] |= cOutputPort1Inactive;
422 else
423 buf[1] &= ~cOutputPort1Inactive;
424 }
425 if (UNSET != port2) {
426 if (port2)
427 buf[1] |= cOutputPort2Inactive;
428 else
429 buf[1] &= ~cOutputPort2Inactive;
430 }
431
432 if (UNSET != qss) {
433 if (qss)
434 buf[1] |= cQSS;
435 else
436 buf[1] &= ~cQSS;
437 }
438
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200439 if (adjust >= 0x00 && adjust < 0x20) {
440 buf[2] &= ~cTopMask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 buf[2] |= adjust;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 return 0;
444}
445
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300446static int tda9887_set_config(struct tuner *t, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300448 if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 buf[1] &= ~cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300450 if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 buf[1] |= cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300452 if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 buf[1] &= ~cOutputPort2Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300454 if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 buf[1] |= cOutputPort2Inactive;
456
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300457 if (t->tda9887_config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 buf[1] |= cQSS;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300459 if (t->tda9887_config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 buf[1] &= ~cQSS;
461
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300462 if (t->tda9887_config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 buf[1] |= cAutoMuteFmActive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300464 if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 buf[2] &= ~0x60;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300466 switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 case TDA9887_DEEMPHASIS_NONE:
468 buf[2] |= cDeemphasisOFF;
469 break;
470 case TDA9887_DEEMPHASIS_50:
471 buf[2] |= cDeemphasisON | cDeemphasis50;
472 break;
473 case TDA9887_DEEMPHASIS_75:
474 buf[2] |= cDeemphasisON | cDeemphasis75;
475 break;
476 }
477 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300478 if (t->tda9887_config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200479 buf[2] &= ~cTopMask;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300480 buf[2] |= (t->tda9887_config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200481 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300482 if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800483 buf[1] &= ~cQSS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 return 0;
485}
486
487/* ---------------------------------------------------------------------- */
488
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300489static int tda9887_status(struct tuner *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
491 unsigned char buf[1];
492 int rc;
493
494 memset(buf,0,sizeof(buf));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300495 if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800496 tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800497 dump_read_message(t, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return 0;
499}
500
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300501static void tda9887_configure(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300503 struct tuner *t = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 int rc;
505
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300506 memset(t->tda9887_data,0,sizeof(t->tda9887_data));
507 tda9887_set_tvnorm(t,t->tda9887_data);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700508
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200509 /* A note on the port settings:
510 These settings tend to depend on the specifics of the board.
511 By default they are set to inactive (bit value 1) by this driver,
512 overwriting any changes made by the tvnorm. This means that it
513 is the responsibility of the module using the tda9887 to set
514 these values in case of changes in the tvnorm.
515 In many cases port 2 should be made active (0) when selecting
516 SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
517
518 For the other standards the tda9887 application note says that
519 the ports should be set to active (0), but, again, that may
520 differ depending on the precise hardware configuration.
521 */
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300522 t->tda9887_data[1] |= cOutputPort1Inactive;
523 t->tda9887_data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700524
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300525 tda9887_set_config(t,t->tda9887_data);
526 tda9887_set_insmod(t,t->tda9887_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700528 if (t->mode == T_STANDBY) {
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300529 t->tda9887_data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700530 }
531
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800532 tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300533 t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
534 if (tuner_debug > 1)
535 dump_write_message(t, t->tda9887_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300537 if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800538 tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300540 if (tuner_debug > 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 msleep_interruptible(1000);
542 tda9887_status(t);
543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544}
545
546/* ---------------------------------------------------------------------- */
547
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300548static void tda9887_tuner_status(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300550 struct tuner *t = i2c_get_clientdata(client);
551 tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
552}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300554static int tda9887_get_afc(struct i2c_client *client)
555{
556 struct tuner *t = i2c_get_clientdata(client);
557 static int AFC_BITS_2_kHz[] = {
558 -12500, -37500, -62500, -97500,
559 -112500, -137500, -162500, -187500,
560 187500, 162500, 137500, 112500,
561 97500 , 62500, 37500 , 12500
562 };
563 int afc=0;
564 __u8 reg = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300566 if (1 == i2c_master_recv(&t->i2c,&reg,1))
567 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700568
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300569 return afc;
570}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700571
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300572static void tda9887_standby(struct i2c_client *client)
573{
574 tda9887_configure(client);
575}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800576
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300577static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
578{
579 tda9887_configure(client);
580}
581
582int tda9887_tuner_init(struct i2c_client *c)
583{
584 struct tuner *t = i2c_get_clientdata(c);
585
586 strlcpy(c->name, "tda9887", sizeof(c->name));
587
588 tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
589 t->i2c.driver->driver.name);
590
591 t->set_tv_freq = tda9887_set_freq;
592 t->set_radio_freq = tda9887_set_freq;
593 t->standby = tda9887_standby;
594 t->tuner_status=tda9887_tuner_status;
595 t->get_afc=tda9887_get_afc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
597 return 0;
598}
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600/*
601 * Overrides for Emacs so that we follow Linus's tabbing style.
602 * ---------------------------------------------------------------------------
603 * Local variables:
604 * c-basic-offset: 8
605 * End:
606 */