blob: 7686f52cfcf95406ab72f4c3fc5ce670650e4d06 [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 {\
Michael Krufkydaae5892007-12-16 19:14:31 -030028 printk(KERN_INFO "tda9887 %d-%04x: " fmt, \
29 i2c_adapter_id(priv->i2c_props.adap), \
30 priv->i2c_props.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) \
Michael Krufkydaae5892007-12-16 19:14:31 -030033 printk(KERN_INFO "tda9887 %d-%04x: " fmt, \
34 i2c_adapter_id(priv->i2c_props.adap), \
35 priv->i2c_props.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 Krufky710401b2007-12-16 19:53:32 -030041 unsigned int config;
Michael Krufky4e9154b2007-10-21 19:39:50 -030042
43 struct tuner *t;
Michael Krufkyb2083192007-05-29 22:54:06 -030044};
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46/* ---------------------------------------------------------------------- */
47
48#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50struct tvnorm {
51 v4l2_std_id std;
52 char *name;
53 unsigned char b;
54 unsigned char c;
55 unsigned char e;
56};
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058/* ---------------------------------------------------------------------- */
59
60//
61// TDA defines
62//
63
64//// first reg (b)
65#define cVideoTrapBypassOFF 0x00 // bit b0
66#define cVideoTrapBypassON 0x01 // bit b0
67
68#define cAutoMuteFmInactive 0x00 // bit b1
69#define cAutoMuteFmActive 0x02 // bit b1
70
71#define cIntercarrier 0x00 // bit b2
72#define cQSS 0x04 // bit b2
73
74#define cPositiveAmTV 0x00 // bit b3:4
75#define cFmRadio 0x08 // bit b3:4
76#define cNegativeFmTV 0x10 // bit b3:4
77
78
79#define cForcedMuteAudioON 0x20 // bit b5
80#define cForcedMuteAudioOFF 0x00 // bit b5
81
82#define cOutputPort1Active 0x00 // bit b6
83#define cOutputPort1Inactive 0x40 // bit b6
84
85#define cOutputPort2Active 0x00 // bit b7
86#define cOutputPort2Inactive 0x80 // bit b7
87
88
89//// second reg (c)
90#define cDeemphasisOFF 0x00 // bit c5
91#define cDeemphasisON 0x20 // bit c5
92
93#define cDeemphasis75 0x00 // bit c6
94#define cDeemphasis50 0x40 // bit c6
95
96#define cAudioGain0 0x00 // bit c7
97#define cAudioGain6 0x80 // bit c7
98
Hans Verkuilf98c55e2006-01-09 15:25:18 -020099#define cTopMask 0x1f // bit c0:4
Hans Verkuilf5b01422006-06-25 15:37:29 -0300100#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102//// third reg (e)
103#define cAudioIF_4_5 0x00 // bit e0:1
104#define cAudioIF_5_5 0x01 // bit e0:1
105#define cAudioIF_6_0 0x02 // bit e0:1
106#define cAudioIF_6_5 0x03 // bit e0:1
107
108
Trent Piepho5e082f12007-08-03 18:32:38 -0300109#define cVideoIFMask 0x1c // bit e2:4
110/* Video IF selection in TV Mode (bit B3=0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define cVideoIF_58_75 0x00 // bit e2:4
112#define cVideoIF_45_75 0x04 // bit e2:4
113#define cVideoIF_38_90 0x08 // bit e2:4
114#define cVideoIF_38_00 0x0C // bit e2:4
115#define cVideoIF_33_90 0x10 // bit e2:4
116#define cVideoIF_33_40 0x14 // bit e2:4
117#define cRadioIF_45_75 0x18 // bit e2:4
118#define cRadioIF_38_90 0x1C // bit e2:4
119
Trent Piepho5e082f12007-08-03 18:32:38 -0300120/* IF1 selection in Radio Mode (bit B3=1) */
121#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
122#define cRadioIF_41_30 0x04 // bit e2,4
123
124/* Output of AFC pin in radio mode when bit E7=1 */
125#define cRadioAGC_SIF 0x00 // bit e3
126#define cRadioAGC_FM 0x08 // bit e3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128#define cTunerGainNormal 0x00 // bit e5
129#define cTunerGainLow 0x20 // bit e5
130
131#define cGating_18 0x00 // bit e6
132#define cGating_36 0x40 // bit e6
133
134#define cAgcOutON 0x80 // bit e7
135#define cAgcOutOFF 0x00 // bit e7
136
137/* ---------------------------------------------------------------------- */
138
139static struct tvnorm tvnorms[] = {
140 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200141 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
142 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 .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_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 cVideoIF_38_90 ),
151 },{
152 .std = V4L2_STD_PAL_I,
153 .name = "PAL-I",
154 .b = ( cNegativeFmTV |
155 cQSS ),
156 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200157 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300158 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200159 .e = ( cGating_36 |
160 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 cVideoIF_38_90 ),
162 },{
163 .std = V4L2_STD_PAL_DK,
164 .name = "PAL-DK",
165 .b = ( cNegativeFmTV |
166 cQSS ),
167 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200168 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300169 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200170 .e = ( cGating_36 |
171 cAudioIF_6_5 |
172 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200174 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
175 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 .b = ( cNegativeFmTV |
177 cQSS ),
178 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200179 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300180 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200181 .e = ( cGating_36 |
182 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 cVideoIF_45_75 ),
184 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200185 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
186 .name = "SECAM-BGH",
187 .b = ( cPositiveAmTV |
188 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300189 .c = ( cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200190 .e = ( cGating_36 |
191 cAudioIF_5_5 |
192 cVideoIF_38_90 ),
193 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 .std = V4L2_STD_SECAM_L,
195 .name = "SECAM-L",
196 .b = ( cPositiveAmTV |
197 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300198 .c = ( cTopDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800199 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800200 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 cVideoIF_38_90 ),
202 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200203 .std = V4L2_STD_SECAM_LC,
204 .name = "SECAM-L'",
205 .b = ( cOutputPort2Inactive |
206 cPositiveAmTV |
207 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300208 .c = ( cTopDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200209 .e = ( cGating_36 |
210 cAudioIF_6_5 |
211 cVideoIF_33_90 ),
212 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 .std = V4L2_STD_SECAM_DK,
214 .name = "SECAM-DK",
215 .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),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200220 .e = ( cGating_36 |
221 cAudioIF_6_5 |
222 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200224 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 .name = "NTSC-M",
226 .b = ( cNegativeFmTV |
227 cQSS ),
228 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200229 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300230 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 .e = ( cGating_36 |
232 cAudioIF_4_5 |
233 cVideoIF_45_75 ),
234 },{
235 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200236 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 .b = ( cNegativeFmTV |
238 cQSS ),
239 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200240 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300241 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 .e = ( cGating_36 |
243 cAudioIF_4_5 |
244 cVideoIF_58_75 ),
245 }
246};
247
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700248static struct tvnorm radio_stereo = {
249 .name = "Radio Stereo",
250 .b = ( cFmRadio |
251 cQSS ),
252 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200253 cAudioGain6 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300254 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200255 .e = ( cTunerGainLow |
256 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700257 cRadioIF_38_90 ),
258};
259
260static struct tvnorm radio_mono = {
261 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 .b = ( cFmRadio |
263 cQSS ),
264 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200265 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300266 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200267 .e = ( cTunerGainLow |
268 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 cRadioIF_38_90 ),
270};
271
272/* ---------------------------------------------------------------------- */
273
Michael Krufky4e9154b2007-10-21 19:39:50 -0300274static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300276 struct tda9887_priv *priv = fe->analog_demod_priv;
277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 static char *afc[16] = {
279 "- 12.5 kHz",
280 "- 37.5 kHz",
281 "- 62.5 kHz",
282 "- 87.5 kHz",
283 "-112.5 kHz",
284 "-137.5 kHz",
285 "-162.5 kHz",
286 "-187.5 kHz [min]",
287 "+187.5 kHz [max]",
288 "+162.5 kHz",
289 "+137.5 kHz",
290 "+112.5 kHz",
291 "+ 87.5 kHz",
292 "+ 62.5 kHz",
293 "+ 37.5 kHz",
294 "+ 12.5 kHz",
295 };
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800296 tda9887_info("read: 0x%2x\n", buf[0]);
297 tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
298 tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
299 tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
300 tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
301 tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302}
303
Michael Krufky4e9154b2007-10-21 19:39:50 -0300304static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300306 struct tda9887_priv *priv = fe->analog_demod_priv;
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 static char *sound[4] = {
309 "AM/TV",
310 "FM/radio",
311 "FM/TV",
312 "FM/radio"
313 };
314 static char *adjust[32] = {
315 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
316 "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
317 "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
318 "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
319 };
320 static char *deemph[4] = {
321 "no", "no", "75", "50"
322 };
323 static char *carrier[4] = {
324 "4.5 MHz",
325 "5.5 MHz",
326 "6.0 MHz",
327 "6.5 MHz / AM"
328 };
329 static char *vif[8] = {
330 "58.75 MHz",
331 "45.75 MHz",
332 "38.9 MHz",
333 "38.0 MHz",
334 "33.9 MHz",
335 "33.4 MHz",
336 "45.75 MHz + pin13",
337 "38.9 MHz + pin13",
338 };
339 static char *rif[4] = {
340 "44 MHz",
341 "52 MHz",
342 "52 MHz",
343 "44 MHz",
344 };
345
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800346 tda9887_info("write: byte B 0x%02x\n",buf[1]);
347 tda9887_info(" B0 video mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 (buf[1] & 0x01) ? "video trap" : "sound trap");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800349 tda9887_info(" B1 auto mute fm : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 (buf[1] & 0x02) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800351 tda9887_info(" B2 carrier mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 (buf[1] & 0x04) ? "QSS" : "Intercarrier");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800353 tda9887_info(" B3-4 tv sound/radio : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 sound[(buf[1] & 0x18) >> 3]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800355 tda9887_info(" B5 force mute audio: %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 (buf[1] & 0x20) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800357 tda9887_info(" B6 output port 1 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800359 tda9887_info(" B7 output port 2 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
361
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800362 tda9887_info("write: byte C 0x%02x\n",buf[2]);
363 tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
364 tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
365 tda9887_info(" C7 audio gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 (buf[2] & 0x80) ? "-6" : "0");
367
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800368 tda9887_info("write: byte E 0x%02x\n",buf[3]);
369 tda9887_info(" E0-1 sound carrier : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 carrier[(buf[3] & 0x03)]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800371 tda9887_info(" E6 l pll gating : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 (buf[3] & 0x40) ? "36" : "13");
373
374 if (buf[1] & 0x08) {
375 /* radio */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800376 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 rif[(buf[3] & 0x0c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800378 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 (buf[3] & 0x80)
380 ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
381 : "fm radio carrier afc");
382 } else {
383 /* video */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800384 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 vif[(buf[3] & 0x1c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800386 tda9887_info(" E5 tuner gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 (buf[3] & 0x80)
388 ? ((buf[3] & 0x20) ? "external" : "normal")
389 : ((buf[3] & 0x20) ? "minimum" : "normal"));
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800390 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 (buf[3] & 0x80)
392 ? ((buf[3] & 0x20)
393 ? "pin3 port, pin22 vif agc out"
394 : "pin22 port, pin3 vif acg ext in")
395 : "pin3+pin22 port");
396 }
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800397 tda9887_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398}
399
400/* ---------------------------------------------------------------------- */
401
Michael Krufky4e9154b2007-10-21 19:39:50 -0300402static int tda9887_set_tvnorm(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300404 struct tda9887_priv *priv = fe->analog_demod_priv;
405 struct tuner *t = priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 struct tvnorm *norm = NULL;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300407 char *buf = priv->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 int i;
409
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300410 if (t->mode == V4L2_TUNER_RADIO) {
411 if (t->audmode == V4L2_TUNER_MODE_MONO)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700412 norm = &radio_mono;
413 else
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700414 norm = &radio_stereo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 } else {
416 for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
417 if (tvnorms[i].std & t->std) {
418 norm = tvnorms+i;
419 break;
420 }
421 }
422 }
423 if (NULL == norm) {
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800424 tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return -1;
426 }
427
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800428 tda9887_dbg("configure for: %s\n",norm->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 buf[1] = norm->b;
430 buf[2] = norm->c;
431 buf[3] = norm->e;
432 return 0;
433}
434
435static unsigned int port1 = UNSET;
436static unsigned int port2 = UNSET;
437static unsigned int qss = UNSET;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200438static unsigned int adjust = UNSET;
439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440module_param(port1, int, 0644);
441module_param(port2, int, 0644);
442module_param(qss, int, 0644);
443module_param(adjust, int, 0644);
444
Michael Krufky4e9154b2007-10-21 19:39:50 -0300445static int tda9887_set_insmod(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300447 struct tda9887_priv *priv = fe->analog_demod_priv;
448 char *buf = priv->data;
449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (UNSET != port1) {
451 if (port1)
452 buf[1] |= cOutputPort1Inactive;
453 else
454 buf[1] &= ~cOutputPort1Inactive;
455 }
456 if (UNSET != port2) {
457 if (port2)
458 buf[1] |= cOutputPort2Inactive;
459 else
460 buf[1] &= ~cOutputPort2Inactive;
461 }
462
463 if (UNSET != qss) {
464 if (qss)
465 buf[1] |= cQSS;
466 else
467 buf[1] &= ~cQSS;
468 }
469
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200470 if (adjust >= 0x00 && adjust < 0x20) {
471 buf[2] &= ~cTopMask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 buf[2] |= adjust;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 return 0;
475}
476
Michael Krufky710401b2007-12-16 19:53:32 -0300477static int tda9887_do_config(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300479 struct tda9887_priv *priv = fe->analog_demod_priv;
480 struct tuner *t = priv->t;
481 char *buf = priv->data;
482
Michael Krufky710401b2007-12-16 19:53:32 -0300483 if (priv->config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 buf[1] &= ~cOutputPort1Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300485 if (priv->config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 buf[1] |= cOutputPort1Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300487 if (priv->config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 buf[1] &= ~cOutputPort2Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300489 if (priv->config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 buf[1] |= cOutputPort2Inactive;
491
Michael Krufky710401b2007-12-16 19:53:32 -0300492 if (priv->config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 buf[1] |= cQSS;
Michael Krufky710401b2007-12-16 19:53:32 -0300494 if (priv->config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 buf[1] &= ~cQSS;
496
Michael Krufky710401b2007-12-16 19:53:32 -0300497 if (priv->config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 buf[1] |= cAutoMuteFmActive;
Michael Krufky710401b2007-12-16 19:53:32 -0300499 if (priv->config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 buf[2] &= ~0x60;
Michael Krufky710401b2007-12-16 19:53:32 -0300501 switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 case TDA9887_DEEMPHASIS_NONE:
503 buf[2] |= cDeemphasisOFF;
504 break;
505 case TDA9887_DEEMPHASIS_50:
506 buf[2] |= cDeemphasisON | cDeemphasis50;
507 break;
508 case TDA9887_DEEMPHASIS_75:
509 buf[2] |= cDeemphasisON | cDeemphasis75;
510 break;
511 }
512 }
Michael Krufky710401b2007-12-16 19:53:32 -0300513 if (priv->config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200514 buf[2] &= ~cTopMask;
Michael Krufky710401b2007-12-16 19:53:32 -0300515 buf[2] |= (priv->config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200516 }
Michael Krufky710401b2007-12-16 19:53:32 -0300517 if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
518 (t->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800519 buf[1] &= ~cQSS;
Michael Krufky710401b2007-12-16 19:53:32 -0300520 if (priv->config & TDA9887_GATING_18)
Trent Piephod7304de2006-08-24 22:43:45 -0300521 buf[3] &= ~cGating_36;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300522
Trent Piepho5e082f12007-08-03 18:32:38 -0300523 if (t->mode == V4L2_TUNER_RADIO) {
Michael Krufky710401b2007-12-16 19:53:32 -0300524 if (priv->config & TDA9887_RIF_41_3) {
Trent Piepho5e082f12007-08-03 18:32:38 -0300525 buf[3] &= ~cVideoIFMask;
526 buf[3] |= cRadioIF_41_30;
527 }
Michael Krufky710401b2007-12-16 19:53:32 -0300528 if (priv->config & TDA9887_GAIN_NORMAL)
Trent Piepho5e082f12007-08-03 18:32:38 -0300529 buf[3] &= ~cTunerGainLow;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300530 }
531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return 0;
533}
534
535/* ---------------------------------------------------------------------- */
536
Michael Krufky4e9154b2007-10-21 19:39:50 -0300537static int tda9887_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300539 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 unsigned char buf[1];
541 int rc;
542
543 memset(buf,0,sizeof(buf));
Michael Krufkydb8a6952007-08-21 01:24:42 -0300544 if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800545 tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300546 dump_read_message(fe, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 return 0;
548}
549
Michael Krufky4e9154b2007-10-21 19:39:50 -0300550static void tda9887_configure(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300552 struct tda9887_priv *priv = fe->analog_demod_priv;
553 struct tuner *t = priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 int rc;
555
Michael Krufkyb2083192007-05-29 22:54:06 -0300556 memset(priv->data,0,sizeof(priv->data));
Michael Krufky4e9154b2007-10-21 19:39:50 -0300557 tda9887_set_tvnorm(fe);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700558
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200559 /* A note on the port settings:
560 These settings tend to depend on the specifics of the board.
561 By default they are set to inactive (bit value 1) by this driver,
562 overwriting any changes made by the tvnorm. This means that it
563 is the responsibility of the module using the tda9887 to set
564 these values in case of changes in the tvnorm.
565 In many cases port 2 should be made active (0) when selecting
566 SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
567
568 For the other standards the tda9887 application note says that
569 the ports should be set to active (0), but, again, that may
570 differ depending on the precise hardware configuration.
571 */
Michael Krufkyb2083192007-05-29 22:54:06 -0300572 priv->data[1] |= cOutputPort1Inactive;
573 priv->data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700574
Michael Krufky710401b2007-12-16 19:53:32 -0300575 tda9887_do_config(fe);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300576 tda9887_set_insmod(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700578 if (t->mode == T_STANDBY) {
Michael Krufkyb2083192007-05-29 22:54:06 -0300579 priv->data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700580 }
581
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800582 tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
Michael Krufkyb2083192007-05-29 22:54:06 -0300583 priv->data[1],priv->data[2],priv->data[3]);
Michael Krufky31c95842007-10-21 20:48:48 -0300584 if (tda9887_debug > 1)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300585 dump_write_message(fe, priv->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Michael Krufkydb8a6952007-08-21 01:24:42 -0300587 if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800588 tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Michael Krufky31c95842007-10-21 20:48:48 -0300590 if (tda9887_debug > 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 msleep_interruptible(1000);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300592 tda9887_status(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594}
595
596/* ---------------------------------------------------------------------- */
597
Michael Krufky4e9154b2007-10-21 19:39:50 -0300598static void tda9887_tuner_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300600 struct tda9887_priv *priv = fe->analog_demod_priv;
Michael Krufky31c95842007-10-21 20:48:48 -0300601 tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
602 priv->data[1], priv->data[2], priv->data[3]);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300603}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
Michael Krufky4e9154b2007-10-21 19:39:50 -0300605static int tda9887_get_afc(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300606{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300607 struct tda9887_priv *priv = fe->analog_demod_priv;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300608 static int AFC_BITS_2_kHz[] = {
609 -12500, -37500, -62500, -97500,
610 -112500, -137500, -162500, -187500,
611 187500, 162500, 137500, 112500,
612 97500 , 62500, 37500 , 12500
613 };
614 int afc=0;
615 __u8 reg = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
Michael Krufkydb8a6952007-08-21 01:24:42 -0300617 if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300618 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700619
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300620 return afc;
621}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700622
Michael Krufky4e9154b2007-10-21 19:39:50 -0300623static void tda9887_standby(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300624{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300625 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300626}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800627
Michael Krufkyc7919d52007-12-08 17:06:30 -0300628static void tda9887_set_params(struct dvb_frontend *fe,
629 struct analog_parameters *params)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300630{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300631 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300632}
633
Michael Krufky710401b2007-12-16 19:53:32 -0300634static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
635{
636 struct tda9887_priv *priv = fe->analog_demod_priv;
637
638 priv->config = *(unsigned int *)priv_cfg;
639 tda9887_configure(fe);
640
641 return 0;
642}
643
Michael Krufky4e9154b2007-10-21 19:39:50 -0300644static void tda9887_release(struct dvb_frontend *fe)
Michael Krufky024cf532007-06-04 15:20:11 -0300645{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300646 kfree(fe->analog_demod_priv);
647 fe->analog_demod_priv = NULL;
Michael Krufky024cf532007-06-04 15:20:11 -0300648}
649
Michael Krufky1dde7a42007-10-21 13:40:56 -0300650static struct analog_tuner_ops tda9887_tuner_ops = {
Michael Krufkya55db8c2007-12-09 13:52:51 -0300651 .info = {
652 .name = "TDA9887",
653 },
Michael Krufkyc7919d52007-12-08 17:06:30 -0300654 .set_params = tda9887_set_params,
Michael Krufky9af596e2007-06-06 16:15:48 -0300655 .standby = tda9887_standby,
656 .tuner_status = tda9887_tuner_status,
657 .get_afc = tda9887_get_afc,
658 .release = tda9887_release,
Michael Krufky710401b2007-12-16 19:53:32 -0300659 .set_config = tda9887_set_config,
Michael Krufky9af596e2007-06-06 16:15:48 -0300660};
661
Michael Krufky31c95842007-10-21 20:48:48 -0300662int tda9887_attach(struct tuner *t)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300663{
Michael Krufkyb2083192007-05-29 22:54:06 -0300664 struct tda9887_priv *priv = NULL;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300665
Michael Krufkyb2083192007-05-29 22:54:06 -0300666 priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
667 if (priv == NULL)
668 return -ENOMEM;
Michael Krufky16f29162007-10-21 15:22:25 -0300669 t->fe.analog_demod_priv = priv;
Michael Krufkyb2083192007-05-29 22:54:06 -0300670
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300671 priv->i2c_props.addr = t->i2c->addr;
672 priv->i2c_props.adap = t->i2c->adapter;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300673 priv->t = t;
Michael Krufkydb8a6952007-08-21 01:24:42 -0300674
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300675 strlcpy(t->i2c->name, "tda9887", sizeof(t->i2c->name));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300676
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300677 tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c->addr,
678 t->i2c->driver->driver.name);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300679
Michael Krufky1dde7a42007-10-21 13:40:56 -0300680 t->fe.ops.analog_demod_ops = &tda9887_tuner_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 return 0;
683}
Michael Krufky31c95842007-10-21 20:48:48 -0300684EXPORT_SYMBOL_GPL(tda9887_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Michael Krufky5ef47302007-10-27 02:17:19 -0300686MODULE_LICENSE("GPL");
687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688/*
689 * Overrides for Emacs so that we follow Linus's tabbing style.
690 * ---------------------------------------------------------------------------
691 * Local variables:
692 * c-basic-offset: 8
693 * End:
694 */