blob: 87ffb0e84a7a063cd34589d8705e00d1a9b1b28b [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 {\
Hans Verkuil343f92c2006-06-25 11:02:02 -030025 printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030026 i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
27#define tda9887_dbg(fmt, arg...) do {\
28 if (tuner_debug) \
Hans Verkuil343f92c2006-06-25 11:02:02 -030029 printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030030 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
Hans Verkuilf5b01422006-06-25 15:37:29 -030087#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89//// third reg (e)
90#define cAudioIF_4_5 0x00 // bit e0:1
91#define cAudioIF_5_5 0x01 // bit e0:1
92#define cAudioIF_6_0 0x02 // bit e0:1
93#define cAudioIF_6_5 0x03 // bit e0:1
94
95
96#define cVideoIF_58_75 0x00 // bit e2:4
97#define cVideoIF_45_75 0x04 // bit e2:4
98#define cVideoIF_38_90 0x08 // bit e2:4
99#define cVideoIF_38_00 0x0C // bit e2:4
100#define cVideoIF_33_90 0x10 // bit e2:4
101#define cVideoIF_33_40 0x14 // bit e2:4
102#define cRadioIF_45_75 0x18 // bit e2:4
103#define cRadioIF_38_90 0x1C // bit e2:4
104
105
106#define cTunerGainNormal 0x00 // bit e5
107#define cTunerGainLow 0x20 // bit e5
108
109#define cGating_18 0x00 // bit e6
110#define cGating_36 0x40 // bit e6
111
112#define cAgcOutON 0x80 // bit e7
113#define cAgcOutOFF 0x00 // bit e7
114
115/* ---------------------------------------------------------------------- */
116
117static struct tvnorm tvnorms[] = {
118 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200119 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
120 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 .b = ( cNegativeFmTV |
122 cQSS ),
123 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200124 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300125 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200126 .e = ( cGating_36 |
127 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 cVideoIF_38_90 ),
129 },{
130 .std = V4L2_STD_PAL_I,
131 .name = "PAL-I",
132 .b = ( cNegativeFmTV |
133 cQSS ),
134 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200135 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300136 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200137 .e = ( cGating_36 |
138 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 cVideoIF_38_90 ),
140 },{
141 .std = V4L2_STD_PAL_DK,
142 .name = "PAL-DK",
143 .b = ( cNegativeFmTV |
144 cQSS ),
145 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200146 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300147 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200148 .e = ( cGating_36 |
149 cAudioIF_6_5 |
150 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200152 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
153 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 .b = ( cNegativeFmTV |
155 cQSS ),
156 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200157 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300158 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200159 .e = ( cGating_36 |
160 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 cVideoIF_45_75 ),
162 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200163 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
164 .name = "SECAM-BGH",
165 .b = ( cPositiveAmTV |
166 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300167 .c = ( cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200168 .e = ( cGating_36 |
169 cAudioIF_5_5 |
170 cVideoIF_38_90 ),
171 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 .std = V4L2_STD_SECAM_L,
173 .name = "SECAM-L",
174 .b = ( cPositiveAmTV |
175 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300176 .c = ( cTopDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800177 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800178 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 cVideoIF_38_90 ),
180 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200181 .std = V4L2_STD_SECAM_LC,
182 .name = "SECAM-L'",
183 .b = ( cOutputPort2Inactive |
184 cPositiveAmTV |
185 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300186 .c = ( cTopDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200187 .e = ( cGating_36 |
188 cAudioIF_6_5 |
189 cVideoIF_33_90 ),
190 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 .std = V4L2_STD_SECAM_DK,
192 .name = "SECAM-DK",
193 .b = ( cNegativeFmTV |
194 cQSS ),
195 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200196 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300197 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200198 .e = ( cGating_36 |
199 cAudioIF_6_5 |
200 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200202 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 .name = "NTSC-M",
204 .b = ( cNegativeFmTV |
205 cQSS ),
206 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200207 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300208 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 .e = ( cGating_36 |
210 cAudioIF_4_5 |
211 cVideoIF_45_75 ),
212 },{
213 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200214 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 .b = ( cNegativeFmTV |
216 cQSS ),
217 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200218 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300219 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 .e = ( cGating_36 |
221 cAudioIF_4_5 |
222 cVideoIF_58_75 ),
223 }
224};
225
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700226static struct tvnorm radio_stereo = {
227 .name = "Radio Stereo",
228 .b = ( cFmRadio |
229 cQSS ),
230 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200231 cAudioGain6 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300232 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200233 .e = ( cTunerGainLow |
234 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700235 cRadioIF_38_90 ),
236};
237
238static struct tvnorm radio_mono = {
239 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 .b = ( cFmRadio |
241 cQSS ),
242 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200243 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300244 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200245 .e = ( cTunerGainLow |
246 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 cRadioIF_38_90 ),
248};
249
250/* ---------------------------------------------------------------------- */
251
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300252static void dump_read_message(struct tuner *t, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
254 static char *afc[16] = {
255 "- 12.5 kHz",
256 "- 37.5 kHz",
257 "- 62.5 kHz",
258 "- 87.5 kHz",
259 "-112.5 kHz",
260 "-137.5 kHz",
261 "-162.5 kHz",
262 "-187.5 kHz [min]",
263 "+187.5 kHz [max]",
264 "+162.5 kHz",
265 "+137.5 kHz",
266 "+112.5 kHz",
267 "+ 87.5 kHz",
268 "+ 62.5 kHz",
269 "+ 37.5 kHz",
270 "+ 12.5 kHz",
271 };
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800272 tda9887_info("read: 0x%2x\n", buf[0]);
273 tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
274 tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
275 tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
276 tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
277 tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278}
279
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300280static void dump_write_message(struct tuner *t, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
282 static char *sound[4] = {
283 "AM/TV",
284 "FM/radio",
285 "FM/TV",
286 "FM/radio"
287 };
288 static char *adjust[32] = {
289 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
290 "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
291 "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
292 "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
293 };
294 static char *deemph[4] = {
295 "no", "no", "75", "50"
296 };
297 static char *carrier[4] = {
298 "4.5 MHz",
299 "5.5 MHz",
300 "6.0 MHz",
301 "6.5 MHz / AM"
302 };
303 static char *vif[8] = {
304 "58.75 MHz",
305 "45.75 MHz",
306 "38.9 MHz",
307 "38.0 MHz",
308 "33.9 MHz",
309 "33.4 MHz",
310 "45.75 MHz + pin13",
311 "38.9 MHz + pin13",
312 };
313 static char *rif[4] = {
314 "44 MHz",
315 "52 MHz",
316 "52 MHz",
317 "44 MHz",
318 };
319
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800320 tda9887_info("write: byte B 0x%02x\n",buf[1]);
321 tda9887_info(" B0 video mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 (buf[1] & 0x01) ? "video trap" : "sound trap");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800323 tda9887_info(" B1 auto mute fm : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 (buf[1] & 0x02) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800325 tda9887_info(" B2 carrier mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 (buf[1] & 0x04) ? "QSS" : "Intercarrier");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800327 tda9887_info(" B3-4 tv sound/radio : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 sound[(buf[1] & 0x18) >> 3]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800329 tda9887_info(" B5 force mute audio: %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 (buf[1] & 0x20) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800331 tda9887_info(" B6 output port 1 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800333 tda9887_info(" B7 output port 2 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
335
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800336 tda9887_info("write: byte C 0x%02x\n",buf[2]);
337 tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
338 tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
339 tda9887_info(" C7 audio gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 (buf[2] & 0x80) ? "-6" : "0");
341
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800342 tda9887_info("write: byte E 0x%02x\n",buf[3]);
343 tda9887_info(" E0-1 sound carrier : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 carrier[(buf[3] & 0x03)]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800345 tda9887_info(" E6 l pll gating : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 (buf[3] & 0x40) ? "36" : "13");
347
348 if (buf[1] & 0x08) {
349 /* radio */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800350 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 rif[(buf[3] & 0x0c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800352 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 (buf[3] & 0x80)
354 ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
355 : "fm radio carrier afc");
356 } else {
357 /* video */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800358 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 vif[(buf[3] & 0x1c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800360 tda9887_info(" E5 tuner gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 (buf[3] & 0x80)
362 ? ((buf[3] & 0x20) ? "external" : "normal")
363 : ((buf[3] & 0x20) ? "minimum" : "normal"));
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800364 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 (buf[3] & 0x80)
366 ? ((buf[3] & 0x20)
367 ? "pin3 port, pin22 vif agc out"
368 : "pin22 port, pin3 vif acg ext in")
369 : "pin3+pin22 port");
370 }
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800371 tda9887_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372}
373
374/* ---------------------------------------------------------------------- */
375
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300376static int tda9887_set_tvnorm(struct tuner *t, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
378 struct tvnorm *norm = NULL;
379 int i;
380
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300381 if (t->mode == V4L2_TUNER_RADIO) {
382 if (t->audmode == V4L2_TUNER_MODE_MONO)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700383 norm = &radio_mono;
384 else
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700385 norm = &radio_stereo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 } else {
387 for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
388 if (tvnorms[i].std & t->std) {
389 norm = tvnorms+i;
390 break;
391 }
392 }
393 }
394 if (NULL == norm) {
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800395 tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 return -1;
397 }
398
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800399 tda9887_dbg("configure for: %s\n",norm->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 buf[1] = norm->b;
401 buf[2] = norm->c;
402 buf[3] = norm->e;
403 return 0;
404}
405
406static unsigned int port1 = UNSET;
407static unsigned int port2 = UNSET;
408static unsigned int qss = UNSET;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200409static unsigned int adjust = UNSET;
410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411module_param(port1, int, 0644);
412module_param(port2, int, 0644);
413module_param(qss, int, 0644);
414module_param(adjust, int, 0644);
415
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300416static int tda9887_set_insmod(struct tuner *t, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 if (UNSET != port1) {
419 if (port1)
420 buf[1] |= cOutputPort1Inactive;
421 else
422 buf[1] &= ~cOutputPort1Inactive;
423 }
424 if (UNSET != port2) {
425 if (port2)
426 buf[1] |= cOutputPort2Inactive;
427 else
428 buf[1] &= ~cOutputPort2Inactive;
429 }
430
431 if (UNSET != qss) {
432 if (qss)
433 buf[1] |= cQSS;
434 else
435 buf[1] &= ~cQSS;
436 }
437
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200438 if (adjust >= 0x00 && adjust < 0x20) {
439 buf[2] &= ~cTopMask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 buf[2] |= adjust;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 return 0;
443}
444
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300445static int tda9887_set_config(struct tuner *t, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300447 if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 buf[1] &= ~cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300449 if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 buf[1] |= cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300451 if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 buf[1] &= ~cOutputPort2Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300453 if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 buf[1] |= cOutputPort2Inactive;
455
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300456 if (t->tda9887_config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 buf[1] |= cQSS;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300458 if (t->tda9887_config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 buf[1] &= ~cQSS;
460
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300461 if (t->tda9887_config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 buf[1] |= cAutoMuteFmActive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300463 if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 buf[2] &= ~0x60;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300465 switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 case TDA9887_DEEMPHASIS_NONE:
467 buf[2] |= cDeemphasisOFF;
468 break;
469 case TDA9887_DEEMPHASIS_50:
470 buf[2] |= cDeemphasisON | cDeemphasis50;
471 break;
472 case TDA9887_DEEMPHASIS_75:
473 buf[2] |= cDeemphasisON | cDeemphasis75;
474 break;
475 }
476 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300477 if (t->tda9887_config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200478 buf[2] &= ~cTopMask;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300479 buf[2] |= (t->tda9887_config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200480 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300481 if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800482 buf[1] &= ~cQSS;
Trent Piephod7304de2006-08-24 22:43:45 -0300483 if (t->tda9887_config & TDA9887_GATING_18)
484 buf[3] &= ~cGating_36;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 return 0;
486}
487
488/* ---------------------------------------------------------------------- */
489
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300490static int tda9887_status(struct tuner *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
492 unsigned char buf[1];
493 int rc;
494
495 memset(buf,0,sizeof(buf));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300496 if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800497 tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800498 dump_read_message(t, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return 0;
500}
501
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300502static void tda9887_configure(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300504 struct tuner *t = i2c_get_clientdata(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 int rc;
506
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300507 memset(t->tda9887_data,0,sizeof(t->tda9887_data));
508 tda9887_set_tvnorm(t,t->tda9887_data);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700509
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200510 /* A note on the port settings:
511 These settings tend to depend on the specifics of the board.
512 By default they are set to inactive (bit value 1) by this driver,
513 overwriting any changes made by the tvnorm. This means that it
514 is the responsibility of the module using the tda9887 to set
515 these values in case of changes in the tvnorm.
516 In many cases port 2 should be made active (0) when selecting
517 SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
518
519 For the other standards the tda9887 application note says that
520 the ports should be set to active (0), but, again, that may
521 differ depending on the precise hardware configuration.
522 */
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300523 t->tda9887_data[1] |= cOutputPort1Inactive;
524 t->tda9887_data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700525
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300526 tda9887_set_config(t,t->tda9887_data);
527 tda9887_set_insmod(t,t->tda9887_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700529 if (t->mode == T_STANDBY) {
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300530 t->tda9887_data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700531 }
532
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800533 tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300534 t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
535 if (tuner_debug > 1)
536 dump_write_message(t, t->tda9887_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300538 if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800539 tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300541 if (tuner_debug > 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 msleep_interruptible(1000);
543 tda9887_status(t);
544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545}
546
547/* ---------------------------------------------------------------------- */
548
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300549static void tda9887_tuner_status(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550{
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300551 struct tuner *t = i2c_get_clientdata(client);
552 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]);
553}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300555static int tda9887_get_afc(struct i2c_client *client)
556{
557 struct tuner *t = i2c_get_clientdata(client);
558 static int AFC_BITS_2_kHz[] = {
559 -12500, -37500, -62500, -97500,
560 -112500, -137500, -162500, -187500,
561 187500, 162500, 137500, 112500,
562 97500 , 62500, 37500 , 12500
563 };
564 int afc=0;
565 __u8 reg = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300567 if (1 == i2c_master_recv(&t->i2c,&reg,1))
568 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700569
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300570 return afc;
571}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700572
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300573static void tda9887_standby(struct i2c_client *client)
574{
575 tda9887_configure(client);
576}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800577
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300578static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
579{
580 tda9887_configure(client);
581}
582
583int tda9887_tuner_init(struct i2c_client *c)
584{
585 struct tuner *t = i2c_get_clientdata(c);
586
587 strlcpy(c->name, "tda9887", sizeof(c->name));
588
589 tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
590 t->i2c.driver->driver.name);
591
592 t->set_tv_freq = tda9887_set_freq;
593 t->set_radio_freq = tda9887_set_freq;
594 t->standby = tda9887_standby;
Hans Verkuilba8fc392006-06-25 15:34:39 -0300595 t->tuner_status = tda9887_tuner_status;
596 t->get_afc = tda9887_get_afc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
598 return 0;
599}
600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601/*
602 * Overrides for Emacs so that we follow Linus's tabbing style.
603 * ---------------------------------------------------------------------------
604 * Local variables:
605 * c-basic-offset: 8
606 * End:
607 */