blob: d506d4bf825335109c1f408d8ff5460671b3e3d6 [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 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 Krufky31c95842007-10-21 20:48:48 -030023static int tda9887_debug;
24module_param_named(debug, tda9887_debug, int, 0644);
25
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030026#define tda9887_info(fmt, arg...) do {\
Hans Verkuil1cba97d72007-09-14 05:13:54 -030027 printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \
28 i2c_adapter_id(priv->t->i2c->adapter), \
29 priv->t->i2c->addr, ##arg); } while (0)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030030#define tda9887_dbg(fmt, arg...) do {\
Michael Krufky31c95842007-10-21 20:48:48 -030031 if (tda9887_debug) \
Hans Verkuil1cba97d72007-09-14 05:13:54 -030032 printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c->name, \
33 i2c_adapter_id(priv->t->i2c->adapter), \
34 priv->t->i2c->addr, ##arg); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Michael Krufkyb2083192007-05-29 22:54:06 -030036struct tda9887_priv {
Michael Krufkydb8a6952007-08-21 01:24:42 -030037 struct tuner_i2c_props i2c_props;
38
Michael Krufkyb2083192007-05-29 22:54:06 -030039 unsigned char data[4];
Michael Krufky4e9154b2007-10-21 19:39:50 -030040
41 struct tuner *t;
Michael Krufkyb2083192007-05-29 22:54:06 -030042};
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44/* ---------------------------------------------------------------------- */
45
46#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48struct tvnorm {
49 v4l2_std_id std;
50 char *name;
51 unsigned char b;
52 unsigned char c;
53 unsigned char e;
54};
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/* ---------------------------------------------------------------------- */
57
58//
59// TDA defines
60//
61
62//// first reg (b)
63#define cVideoTrapBypassOFF 0x00 // bit b0
64#define cVideoTrapBypassON 0x01 // bit b0
65
66#define cAutoMuteFmInactive 0x00 // bit b1
67#define cAutoMuteFmActive 0x02 // bit b1
68
69#define cIntercarrier 0x00 // bit b2
70#define cQSS 0x04 // bit b2
71
72#define cPositiveAmTV 0x00 // bit b3:4
73#define cFmRadio 0x08 // bit b3:4
74#define cNegativeFmTV 0x10 // bit b3:4
75
76
77#define cForcedMuteAudioON 0x20 // bit b5
78#define cForcedMuteAudioOFF 0x00 // bit b5
79
80#define cOutputPort1Active 0x00 // bit b6
81#define cOutputPort1Inactive 0x40 // bit b6
82
83#define cOutputPort2Active 0x00 // bit b7
84#define cOutputPort2Inactive 0x80 // bit b7
85
86
87//// second reg (c)
88#define cDeemphasisOFF 0x00 // bit c5
89#define cDeemphasisON 0x20 // bit c5
90
91#define cDeemphasis75 0x00 // bit c6
92#define cDeemphasis50 0x40 // bit c6
93
94#define cAudioGain0 0x00 // bit c7
95#define cAudioGain6 0x80 // bit c7
96
Hans Verkuilf98c55e2006-01-09 15:25:18 -020097#define cTopMask 0x1f // bit c0:4
Hans Verkuilf5b01422006-06-25 15:37:29 -030098#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100//// third reg (e)
101#define cAudioIF_4_5 0x00 // bit e0:1
102#define cAudioIF_5_5 0x01 // bit e0:1
103#define cAudioIF_6_0 0x02 // bit e0:1
104#define cAudioIF_6_5 0x03 // bit e0:1
105
106
Trent Piepho5e082f12007-08-03 18:32:38 -0300107#define cVideoIFMask 0x1c // bit e2:4
108/* Video IF selection in TV Mode (bit B3=0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#define cVideoIF_58_75 0x00 // bit e2:4
110#define cVideoIF_45_75 0x04 // bit e2:4
111#define cVideoIF_38_90 0x08 // bit e2:4
112#define cVideoIF_38_00 0x0C // bit e2:4
113#define cVideoIF_33_90 0x10 // bit e2:4
114#define cVideoIF_33_40 0x14 // bit e2:4
115#define cRadioIF_45_75 0x18 // bit e2:4
116#define cRadioIF_38_90 0x1C // bit e2:4
117
Trent Piepho5e082f12007-08-03 18:32:38 -0300118/* IF1 selection in Radio Mode (bit B3=1) */
119#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
120#define cRadioIF_41_30 0x04 // bit e2,4
121
122/* Output of AFC pin in radio mode when bit E7=1 */
123#define cRadioAGC_SIF 0x00 // bit e3
124#define cRadioAGC_FM 0x08 // bit e3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126#define cTunerGainNormal 0x00 // bit e5
127#define cTunerGainLow 0x20 // bit e5
128
129#define cGating_18 0x00 // bit e6
130#define cGating_36 0x40 // bit e6
131
132#define cAgcOutON 0x80 // bit e7
133#define cAgcOutOFF 0x00 // bit e7
134
135/* ---------------------------------------------------------------------- */
136
137static struct tvnorm tvnorms[] = {
138 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200139 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
140 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 .b = ( cNegativeFmTV |
142 cQSS ),
143 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200144 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300145 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200146 .e = ( cGating_36 |
147 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 cVideoIF_38_90 ),
149 },{
150 .std = V4L2_STD_PAL_I,
151 .name = "PAL-I",
152 .b = ( cNegativeFmTV |
153 cQSS ),
154 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200155 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300156 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200157 .e = ( cGating_36 |
158 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 cVideoIF_38_90 ),
160 },{
161 .std = V4L2_STD_PAL_DK,
162 .name = "PAL-DK",
163 .b = ( cNegativeFmTV |
164 cQSS ),
165 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200166 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300167 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200168 .e = ( cGating_36 |
169 cAudioIF_6_5 |
170 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200172 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
173 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 .b = ( cNegativeFmTV |
175 cQSS ),
176 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200177 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300178 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200179 .e = ( cGating_36 |
180 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 cVideoIF_45_75 ),
182 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200183 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
184 .name = "SECAM-BGH",
185 .b = ( cPositiveAmTV |
186 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300187 .c = ( cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200188 .e = ( cGating_36 |
189 cAudioIF_5_5 |
190 cVideoIF_38_90 ),
191 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 .std = V4L2_STD_SECAM_L,
193 .name = "SECAM-L",
194 .b = ( cPositiveAmTV |
195 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300196 .c = ( cTopDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800197 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800198 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 cVideoIF_38_90 ),
200 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200201 .std = V4L2_STD_SECAM_LC,
202 .name = "SECAM-L'",
203 .b = ( cOutputPort2Inactive |
204 cPositiveAmTV |
205 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300206 .c = ( cTopDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200207 .e = ( cGating_36 |
208 cAudioIF_6_5 |
209 cVideoIF_33_90 ),
210 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 .std = V4L2_STD_SECAM_DK,
212 .name = "SECAM-DK",
213 .b = ( cNegativeFmTV |
214 cQSS ),
215 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200216 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300217 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200218 .e = ( cGating_36 |
219 cAudioIF_6_5 |
220 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200222 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 .name = "NTSC-M",
224 .b = ( cNegativeFmTV |
225 cQSS ),
226 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200227 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300228 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 .e = ( cGating_36 |
230 cAudioIF_4_5 |
231 cVideoIF_45_75 ),
232 },{
233 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200234 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 .b = ( cNegativeFmTV |
236 cQSS ),
237 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200238 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300239 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 .e = ( cGating_36 |
241 cAudioIF_4_5 |
242 cVideoIF_58_75 ),
243 }
244};
245
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700246static struct tvnorm radio_stereo = {
247 .name = "Radio Stereo",
248 .b = ( cFmRadio |
249 cQSS ),
250 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200251 cAudioGain6 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300252 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200253 .e = ( cTunerGainLow |
254 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700255 cRadioIF_38_90 ),
256};
257
258static struct tvnorm radio_mono = {
259 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 .b = ( cFmRadio |
261 cQSS ),
262 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200263 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300264 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200265 .e = ( cTunerGainLow |
266 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 cRadioIF_38_90 ),
268};
269
270/* ---------------------------------------------------------------------- */
271
Michael Krufky4e9154b2007-10-21 19:39:50 -0300272static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300274 struct tda9887_priv *priv = fe->analog_demod_priv;
275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 static char *afc[16] = {
277 "- 12.5 kHz",
278 "- 37.5 kHz",
279 "- 62.5 kHz",
280 "- 87.5 kHz",
281 "-112.5 kHz",
282 "-137.5 kHz",
283 "-162.5 kHz",
284 "-187.5 kHz [min]",
285 "+187.5 kHz [max]",
286 "+162.5 kHz",
287 "+137.5 kHz",
288 "+112.5 kHz",
289 "+ 87.5 kHz",
290 "+ 62.5 kHz",
291 "+ 37.5 kHz",
292 "+ 12.5 kHz",
293 };
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800294 tda9887_info("read: 0x%2x\n", buf[0]);
295 tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
296 tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
297 tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
298 tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
299 tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
Michael Krufky4e9154b2007-10-21 19:39:50 -0300302static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300304 struct tda9887_priv *priv = fe->analog_demod_priv;
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 static char *sound[4] = {
307 "AM/TV",
308 "FM/radio",
309 "FM/TV",
310 "FM/radio"
311 };
312 static char *adjust[32] = {
313 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
314 "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
315 "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
316 "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
317 };
318 static char *deemph[4] = {
319 "no", "no", "75", "50"
320 };
321 static char *carrier[4] = {
322 "4.5 MHz",
323 "5.5 MHz",
324 "6.0 MHz",
325 "6.5 MHz / AM"
326 };
327 static char *vif[8] = {
328 "58.75 MHz",
329 "45.75 MHz",
330 "38.9 MHz",
331 "38.0 MHz",
332 "33.9 MHz",
333 "33.4 MHz",
334 "45.75 MHz + pin13",
335 "38.9 MHz + pin13",
336 };
337 static char *rif[4] = {
338 "44 MHz",
339 "52 MHz",
340 "52 MHz",
341 "44 MHz",
342 };
343
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800344 tda9887_info("write: byte B 0x%02x\n",buf[1]);
345 tda9887_info(" B0 video mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 (buf[1] & 0x01) ? "video trap" : "sound trap");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800347 tda9887_info(" B1 auto mute fm : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 (buf[1] & 0x02) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800349 tda9887_info(" B2 carrier mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 (buf[1] & 0x04) ? "QSS" : "Intercarrier");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800351 tda9887_info(" B3-4 tv sound/radio : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 sound[(buf[1] & 0x18) >> 3]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800353 tda9887_info(" B5 force mute audio: %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 (buf[1] & 0x20) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800355 tda9887_info(" B6 output port 1 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800357 tda9887_info(" B7 output port 2 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
359
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800360 tda9887_info("write: byte C 0x%02x\n",buf[2]);
361 tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
362 tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
363 tda9887_info(" C7 audio gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 (buf[2] & 0x80) ? "-6" : "0");
365
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800366 tda9887_info("write: byte E 0x%02x\n",buf[3]);
367 tda9887_info(" E0-1 sound carrier : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 carrier[(buf[3] & 0x03)]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800369 tda9887_info(" E6 l pll gating : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 (buf[3] & 0x40) ? "36" : "13");
371
372 if (buf[1] & 0x08) {
373 /* radio */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800374 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 rif[(buf[3] & 0x0c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800376 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 (buf[3] & 0x80)
378 ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
379 : "fm radio carrier afc");
380 } else {
381 /* video */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800382 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 vif[(buf[3] & 0x1c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800384 tda9887_info(" E5 tuner gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 (buf[3] & 0x80)
386 ? ((buf[3] & 0x20) ? "external" : "normal")
387 : ((buf[3] & 0x20) ? "minimum" : "normal"));
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800388 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 (buf[3] & 0x80)
390 ? ((buf[3] & 0x20)
391 ? "pin3 port, pin22 vif agc out"
392 : "pin22 port, pin3 vif acg ext in")
393 : "pin3+pin22 port");
394 }
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800395 tda9887_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396}
397
398/* ---------------------------------------------------------------------- */
399
Michael Krufky4e9154b2007-10-21 19:39:50 -0300400static int tda9887_set_tvnorm(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300402 struct tda9887_priv *priv = fe->analog_demod_priv;
403 struct tuner *t = priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 struct tvnorm *norm = NULL;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300405 char *buf = priv->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 int i;
407
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300408 if (t->mode == V4L2_TUNER_RADIO) {
409 if (t->audmode == V4L2_TUNER_MODE_MONO)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700410 norm = &radio_mono;
411 else
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700412 norm = &radio_stereo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 } else {
414 for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
415 if (tvnorms[i].std & t->std) {
416 norm = tvnorms+i;
417 break;
418 }
419 }
420 }
421 if (NULL == norm) {
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800422 tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 return -1;
424 }
425
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800426 tda9887_dbg("configure for: %s\n",norm->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 buf[1] = norm->b;
428 buf[2] = norm->c;
429 buf[3] = norm->e;
430 return 0;
431}
432
433static unsigned int port1 = UNSET;
434static unsigned int port2 = UNSET;
435static unsigned int qss = UNSET;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200436static unsigned int adjust = UNSET;
437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438module_param(port1, int, 0644);
439module_param(port2, int, 0644);
440module_param(qss, int, 0644);
441module_param(adjust, int, 0644);
442
Michael Krufky4e9154b2007-10-21 19:39:50 -0300443static int tda9887_set_insmod(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300445 struct tda9887_priv *priv = fe->analog_demod_priv;
446 char *buf = priv->data;
447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (UNSET != port1) {
449 if (port1)
450 buf[1] |= cOutputPort1Inactive;
451 else
452 buf[1] &= ~cOutputPort1Inactive;
453 }
454 if (UNSET != port2) {
455 if (port2)
456 buf[1] |= cOutputPort2Inactive;
457 else
458 buf[1] &= ~cOutputPort2Inactive;
459 }
460
461 if (UNSET != qss) {
462 if (qss)
463 buf[1] |= cQSS;
464 else
465 buf[1] &= ~cQSS;
466 }
467
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200468 if (adjust >= 0x00 && adjust < 0x20) {
469 buf[2] &= ~cTopMask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 buf[2] |= adjust;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 return 0;
473}
474
Michael Krufky4e9154b2007-10-21 19:39:50 -0300475static int tda9887_set_config(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300477 struct tda9887_priv *priv = fe->analog_demod_priv;
478 struct tuner *t = priv->t;
479 char *buf = priv->data;
480
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300481 if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 buf[1] &= ~cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300483 if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 buf[1] |= cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300485 if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 buf[1] &= ~cOutputPort2Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300487 if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 buf[1] |= cOutputPort2Inactive;
489
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300490 if (t->tda9887_config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 buf[1] |= cQSS;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300492 if (t->tda9887_config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 buf[1] &= ~cQSS;
494
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300495 if (t->tda9887_config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 buf[1] |= cAutoMuteFmActive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300497 if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 buf[2] &= ~0x60;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300499 switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 case TDA9887_DEEMPHASIS_NONE:
501 buf[2] |= cDeemphasisOFF;
502 break;
503 case TDA9887_DEEMPHASIS_50:
504 buf[2] |= cDeemphasisON | cDeemphasis50;
505 break;
506 case TDA9887_DEEMPHASIS_75:
507 buf[2] |= cDeemphasisON | cDeemphasis75;
508 break;
509 }
510 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300511 if (t->tda9887_config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200512 buf[2] &= ~cTopMask;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300513 buf[2] |= (t->tda9887_config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200514 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300515 if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800516 buf[1] &= ~cQSS;
Trent Piephod7304de2006-08-24 22:43:45 -0300517 if (t->tda9887_config & TDA9887_GATING_18)
518 buf[3] &= ~cGating_36;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300519
Trent Piepho5e082f12007-08-03 18:32:38 -0300520 if (t->mode == V4L2_TUNER_RADIO) {
521 if (t->tda9887_config & TDA9887_RIF_41_3) {
522 buf[3] &= ~cVideoIFMask;
523 buf[3] |= cRadioIF_41_30;
524 }
525 if (t->tda9887_config & TDA9887_GAIN_NORMAL)
526 buf[3] &= ~cTunerGainLow;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300527 }
528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 return 0;
530}
531
532/* ---------------------------------------------------------------------- */
533
Michael Krufky4e9154b2007-10-21 19:39:50 -0300534static int tda9887_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300536 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 unsigned char buf[1];
538 int rc;
539
540 memset(buf,0,sizeof(buf));
Michael Krufkydb8a6952007-08-21 01:24:42 -0300541 if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800542 tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300543 dump_read_message(fe, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 return 0;
545}
546
Michael Krufky4e9154b2007-10-21 19:39:50 -0300547static void tda9887_configure(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300549 struct tda9887_priv *priv = fe->analog_demod_priv;
550 struct tuner *t = priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 int rc;
552
Michael Krufkyb2083192007-05-29 22:54:06 -0300553 memset(priv->data,0,sizeof(priv->data));
Michael Krufky4e9154b2007-10-21 19:39:50 -0300554 tda9887_set_tvnorm(fe);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700555
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200556 /* A note on the port settings:
557 These settings tend to depend on the specifics of the board.
558 By default they are set to inactive (bit value 1) by this driver,
559 overwriting any changes made by the tvnorm. This means that it
560 is the responsibility of the module using the tda9887 to set
561 these values in case of changes in the tvnorm.
562 In many cases port 2 should be made active (0) when selecting
563 SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
564
565 For the other standards the tda9887 application note says that
566 the ports should be set to active (0), but, again, that may
567 differ depending on the precise hardware configuration.
568 */
Michael Krufkyb2083192007-05-29 22:54:06 -0300569 priv->data[1] |= cOutputPort1Inactive;
570 priv->data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700571
Michael Krufky4e9154b2007-10-21 19:39:50 -0300572 tda9887_set_config(fe);
573 tda9887_set_insmod(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700575 if (t->mode == T_STANDBY) {
Michael Krufkyb2083192007-05-29 22:54:06 -0300576 priv->data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700577 }
578
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800579 tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
Michael Krufkyb2083192007-05-29 22:54:06 -0300580 priv->data[1],priv->data[2],priv->data[3]);
Michael Krufky31c95842007-10-21 20:48:48 -0300581 if (tda9887_debug > 1)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300582 dump_write_message(fe, priv->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Michael Krufkydb8a6952007-08-21 01:24:42 -0300584 if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800585 tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Michael Krufky31c95842007-10-21 20:48:48 -0300587 if (tda9887_debug > 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 msleep_interruptible(1000);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300589 tda9887_status(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591}
592
593/* ---------------------------------------------------------------------- */
594
Michael Krufky4e9154b2007-10-21 19:39:50 -0300595static void tda9887_tuner_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300597 struct tda9887_priv *priv = fe->analog_demod_priv;
Michael Krufky31c95842007-10-21 20:48:48 -0300598 tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
599 priv->data[1], priv->data[2], priv->data[3]);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300600}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Michael Krufky4e9154b2007-10-21 19:39:50 -0300602static int tda9887_get_afc(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300603{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300604 struct tda9887_priv *priv = fe->analog_demod_priv;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300605 static int AFC_BITS_2_kHz[] = {
606 -12500, -37500, -62500, -97500,
607 -112500, -137500, -162500, -187500,
608 187500, 162500, 137500, 112500,
609 97500 , 62500, 37500 , 12500
610 };
611 int afc=0;
612 __u8 reg = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Michael Krufkydb8a6952007-08-21 01:24:42 -0300614 if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300615 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700616
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300617 return afc;
618}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700619
Michael Krufky4e9154b2007-10-21 19:39:50 -0300620static void tda9887_standby(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300621{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300622 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300623}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800624
Michael Krufkyc7919d52007-12-08 17:06:30 -0300625static void tda9887_set_params(struct dvb_frontend *fe,
626 struct analog_parameters *params)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300627{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300628 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300629}
630
Michael Krufky4e9154b2007-10-21 19:39:50 -0300631static void tda9887_release(struct dvb_frontend *fe)
Michael Krufky024cf532007-06-04 15:20:11 -0300632{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300633 kfree(fe->analog_demod_priv);
634 fe->analog_demod_priv = NULL;
Michael Krufky024cf532007-06-04 15:20:11 -0300635}
636
Michael Krufky1dde7a42007-10-21 13:40:56 -0300637static struct analog_tuner_ops tda9887_tuner_ops = {
Michael Krufkyc7919d52007-12-08 17:06:30 -0300638 .set_params = tda9887_set_params,
Michael Krufky9af596e2007-06-06 16:15:48 -0300639 .standby = tda9887_standby,
640 .tuner_status = tda9887_tuner_status,
641 .get_afc = tda9887_get_afc,
642 .release = tda9887_release,
643};
644
Michael Krufky31c95842007-10-21 20:48:48 -0300645int tda9887_attach(struct tuner *t)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300646{
Michael Krufkyb2083192007-05-29 22:54:06 -0300647 struct tda9887_priv *priv = NULL;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300648
Michael Krufkyb2083192007-05-29 22:54:06 -0300649 priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
650 if (priv == NULL)
651 return -ENOMEM;
Michael Krufky16f29162007-10-21 15:22:25 -0300652 t->fe.analog_demod_priv = priv;
Michael Krufkyb2083192007-05-29 22:54:06 -0300653
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300654 priv->i2c_props.addr = t->i2c->addr;
655 priv->i2c_props.adap = t->i2c->adapter;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300656 priv->t = t;
Michael Krufkydb8a6952007-08-21 01:24:42 -0300657
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300658 strlcpy(t->i2c->name, "tda9887", sizeof(t->i2c->name));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300659
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300660 tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c->addr,
661 t->i2c->driver->driver.name);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300662
Michael Krufky1dde7a42007-10-21 13:40:56 -0300663 t->fe.ops.analog_demod_ops = &tda9887_tuner_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 return 0;
666}
Michael Krufky31c95842007-10-21 20:48:48 -0300667EXPORT_SYMBOL_GPL(tda9887_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Michael Krufky5ef47302007-10-27 02:17:19 -0300669MODULE_LICENSE("GPL");
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671/*
672 * Overrides for Emacs so that we follow Linus's tabbing style.
673 * ---------------------------------------------------------------------------
674 * Local variables:
675 * c-basic-offset: 8
676 * End:
677 */