blob: 75d08404d23898109a41aa8af3866f9449083f40 [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 Krufky790ba182007-12-16 21:20:21 -030024static int debug;
25module_param(debug, int, 0644);
26MODULE_PARM_DESC(debug, "enable verbose debug messages");
Michael Krufky31c95842007-10-21 20:48:48 -030027
Michael Krufkyb2083192007-05-29 22:54:06 -030028struct tda9887_priv {
Michael Krufkydb8a6952007-08-21 01:24:42 -030029 struct tuner_i2c_props i2c_props;
30
Michael Krufkyb2083192007-05-29 22:54:06 -030031 unsigned char data[4];
Michael Krufky710401b2007-12-16 19:53:32 -030032 unsigned int config;
Michael Krufky91c9d4a2007-12-16 20:05:00 -030033 unsigned int mode;
34 unsigned int audmode;
35 v4l2_std_id std;
Michael Krufkyb2083192007-05-29 22:54:06 -030036};
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
38/* ---------------------------------------------------------------------- */
39
40#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42struct tvnorm {
43 v4l2_std_id std;
44 char *name;
45 unsigned char b;
46 unsigned char c;
47 unsigned char e;
48};
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050/* ---------------------------------------------------------------------- */
51
52//
53// TDA defines
54//
55
56//// first reg (b)
57#define cVideoTrapBypassOFF 0x00 // bit b0
58#define cVideoTrapBypassON 0x01 // bit b0
59
60#define cAutoMuteFmInactive 0x00 // bit b1
61#define cAutoMuteFmActive 0x02 // bit b1
62
63#define cIntercarrier 0x00 // bit b2
64#define cQSS 0x04 // bit b2
65
66#define cPositiveAmTV 0x00 // bit b3:4
67#define cFmRadio 0x08 // bit b3:4
68#define cNegativeFmTV 0x10 // bit b3:4
69
70
71#define cForcedMuteAudioON 0x20 // bit b5
72#define cForcedMuteAudioOFF 0x00 // bit b5
73
74#define cOutputPort1Active 0x00 // bit b6
75#define cOutputPort1Inactive 0x40 // bit b6
76
77#define cOutputPort2Active 0x00 // bit b7
78#define cOutputPort2Inactive 0x80 // bit b7
79
80
81//// second reg (c)
82#define cDeemphasisOFF 0x00 // bit c5
83#define cDeemphasisON 0x20 // bit c5
84
85#define cDeemphasis75 0x00 // bit c6
86#define cDeemphasis50 0x40 // bit c6
87
88#define cAudioGain0 0x00 // bit c7
89#define cAudioGain6 0x80 // bit c7
90
Hans Verkuilf98c55e2006-01-09 15:25:18 -020091#define cTopMask 0x1f // bit c0:4
Hans Verkuilf5b01422006-06-25 15:37:29 -030092#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94//// third reg (e)
95#define cAudioIF_4_5 0x00 // bit e0:1
96#define cAudioIF_5_5 0x01 // bit e0:1
97#define cAudioIF_6_0 0x02 // bit e0:1
98#define cAudioIF_6_5 0x03 // bit e0:1
99
100
Trent Piepho5e082f12007-08-03 18:32:38 -0300101#define cVideoIFMask 0x1c // bit e2:4
102/* Video IF selection in TV Mode (bit B3=0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103#define cVideoIF_58_75 0x00 // bit e2:4
104#define cVideoIF_45_75 0x04 // bit e2:4
105#define cVideoIF_38_90 0x08 // bit e2:4
106#define cVideoIF_38_00 0x0C // bit e2:4
107#define cVideoIF_33_90 0x10 // bit e2:4
108#define cVideoIF_33_40 0x14 // bit e2:4
109#define cRadioIF_45_75 0x18 // bit e2:4
110#define cRadioIF_38_90 0x1C // bit e2:4
111
Trent Piepho5e082f12007-08-03 18:32:38 -0300112/* IF1 selection in Radio Mode (bit B3=1) */
113#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
114#define cRadioIF_41_30 0x04 // bit e2,4
115
116/* Output of AFC pin in radio mode when bit E7=1 */
117#define cRadioAGC_SIF 0x00 // bit e3
118#define cRadioAGC_FM 0x08 // bit e3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120#define cTunerGainNormal 0x00 // bit e5
121#define cTunerGainLow 0x20 // bit e5
122
123#define cGating_18 0x00 // bit e6
124#define cGating_36 0x40 // bit e6
125
126#define cAgcOutON 0x80 // bit e7
127#define cAgcOutOFF 0x00 // bit e7
128
129/* ---------------------------------------------------------------------- */
130
131static struct tvnorm tvnorms[] = {
132 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200133 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
134 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 .b = ( cNegativeFmTV |
136 cQSS ),
137 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200138 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300139 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200140 .e = ( cGating_36 |
141 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 cVideoIF_38_90 ),
143 },{
144 .std = V4L2_STD_PAL_I,
145 .name = "PAL-I",
146 .b = ( cNegativeFmTV |
147 cQSS ),
148 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200149 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300150 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200151 .e = ( cGating_36 |
152 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 cVideoIF_38_90 ),
154 },{
155 .std = V4L2_STD_PAL_DK,
156 .name = "PAL-DK",
157 .b = ( cNegativeFmTV |
158 cQSS ),
159 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200160 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300161 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200162 .e = ( cGating_36 |
163 cAudioIF_6_5 |
164 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200166 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
167 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 .b = ( cNegativeFmTV |
169 cQSS ),
170 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200171 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300172 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200173 .e = ( cGating_36 |
174 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 cVideoIF_45_75 ),
176 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200177 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
178 .name = "SECAM-BGH",
179 .b = ( cPositiveAmTV |
180 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300181 .c = ( cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200182 .e = ( cGating_36 |
183 cAudioIF_5_5 |
184 cVideoIF_38_90 ),
185 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 .std = V4L2_STD_SECAM_L,
187 .name = "SECAM-L",
188 .b = ( cPositiveAmTV |
189 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300190 .c = ( cTopDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800191 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800192 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 cVideoIF_38_90 ),
194 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200195 .std = V4L2_STD_SECAM_LC,
196 .name = "SECAM-L'",
197 .b = ( cOutputPort2Inactive |
198 cPositiveAmTV |
199 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300200 .c = ( cTopDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200201 .e = ( cGating_36 |
202 cAudioIF_6_5 |
203 cVideoIF_33_90 ),
204 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 .std = V4L2_STD_SECAM_DK,
206 .name = "SECAM-DK",
207 .b = ( cNegativeFmTV |
208 cQSS ),
209 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200210 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300211 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200212 .e = ( cGating_36 |
213 cAudioIF_6_5 |
214 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200216 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 .name = "NTSC-M",
218 .b = ( cNegativeFmTV |
219 cQSS ),
220 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200221 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300222 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 .e = ( cGating_36 |
224 cAudioIF_4_5 |
225 cVideoIF_45_75 ),
226 },{
227 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200228 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 .b = ( cNegativeFmTV |
230 cQSS ),
231 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200232 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300233 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 .e = ( cGating_36 |
235 cAudioIF_4_5 |
236 cVideoIF_58_75 ),
237 }
238};
239
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700240static struct tvnorm radio_stereo = {
241 .name = "Radio Stereo",
242 .b = ( cFmRadio |
243 cQSS ),
244 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200245 cAudioGain6 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300246 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200247 .e = ( cTunerGainLow |
248 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700249 cRadioIF_38_90 ),
250};
251
252static struct tvnorm radio_mono = {
253 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 .b = ( cFmRadio |
255 cQSS ),
256 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200257 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300258 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200259 .e = ( cTunerGainLow |
260 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 cRadioIF_38_90 ),
262};
263
264/* ---------------------------------------------------------------------- */
265
Michael Krufky4e9154b2007-10-21 19:39:50 -0300266static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300268 struct tda9887_priv *priv = fe->analog_demod_priv;
269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 static char *afc[16] = {
271 "- 12.5 kHz",
272 "- 37.5 kHz",
273 "- 62.5 kHz",
274 "- 87.5 kHz",
275 "-112.5 kHz",
276 "-137.5 kHz",
277 "-162.5 kHz",
278 "-187.5 kHz [min]",
279 "+187.5 kHz [max]",
280 "+162.5 kHz",
281 "+137.5 kHz",
282 "+112.5 kHz",
283 "+ 87.5 kHz",
284 "+ 62.5 kHz",
285 "+ 37.5 kHz",
286 "+ 12.5 kHz",
287 };
Michael Krufky790ba182007-12-16 21:20:21 -0300288 tuner_info("read: 0x%2x\n", buf[0]);
289 tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
290 tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
291 tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
292 tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
293 tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
Michael Krufky4e9154b2007-10-21 19:39:50 -0300296static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300298 struct tda9887_priv *priv = fe->analog_demod_priv;
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 static char *sound[4] = {
301 "AM/TV",
302 "FM/radio",
303 "FM/TV",
304 "FM/radio"
305 };
306 static char *adjust[32] = {
307 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
308 "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
309 "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
310 "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
311 };
312 static char *deemph[4] = {
313 "no", "no", "75", "50"
314 };
315 static char *carrier[4] = {
316 "4.5 MHz",
317 "5.5 MHz",
318 "6.0 MHz",
319 "6.5 MHz / AM"
320 };
321 static char *vif[8] = {
322 "58.75 MHz",
323 "45.75 MHz",
324 "38.9 MHz",
325 "38.0 MHz",
326 "33.9 MHz",
327 "33.4 MHz",
328 "45.75 MHz + pin13",
329 "38.9 MHz + pin13",
330 };
331 static char *rif[4] = {
332 "44 MHz",
333 "52 MHz",
334 "52 MHz",
335 "44 MHz",
336 };
337
Michael Krufky790ba182007-12-16 21:20:21 -0300338 tuner_info("write: byte B 0x%02x\n", buf[1]);
339 tuner_info(" B0 video mode : %s\n",
340 (buf[1] & 0x01) ? "video trap" : "sound trap");
341 tuner_info(" B1 auto mute fm : %s\n",
342 (buf[1] & 0x02) ? "yes" : "no");
343 tuner_info(" B2 carrier mode : %s\n",
344 (buf[1] & 0x04) ? "QSS" : "Intercarrier");
345 tuner_info(" B3-4 tv sound/radio : %s\n",
346 sound[(buf[1] & 0x18) >> 3]);
347 tuner_info(" B5 force mute audio: %s\n",
348 (buf[1] & 0x20) ? "yes" : "no");
349 tuner_info(" B6 output port 1 : %s\n",
350 (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
351 tuner_info(" B7 output port 2 : %s\n",
352 (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Michael Krufky790ba182007-12-16 21:20:21 -0300354 tuner_info("write: byte C 0x%02x\n", buf[2]);
355 tuner_info(" C0-4 top adjustment : %s dB\n",
356 adjust[buf[2] & 0x1f]);
357 tuner_info(" C5-6 de-emphasis : %s\n",
358 deemph[(buf[2] & 0x60) >> 5]);
359 tuner_info(" C7 audio gain : %s\n",
360 (buf[2] & 0x80) ? "-6" : "0");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Michael Krufky790ba182007-12-16 21:20:21 -0300362 tuner_info("write: byte E 0x%02x\n", buf[3]);
363 tuner_info(" E0-1 sound carrier : %s\n",
364 carrier[(buf[3] & 0x03)]);
365 tuner_info(" E6 l pll gating : %s\n",
366 (buf[3] & 0x40) ? "36" : "13");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368 if (buf[1] & 0x08) {
369 /* radio */
Michael Krufky790ba182007-12-16 21:20:21 -0300370 tuner_info(" E2-4 video if : %s\n",
371 rif[(buf[3] & 0x0c) >> 2]);
372 tuner_info(" E7 vif agc output : %s\n",
373 (buf[3] & 0x80)
374 ? ((buf[3] & 0x10) ? "fm-agc radio" :
375 "sif-agc radio")
376 : "fm radio carrier afc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 } else {
378 /* video */
Michael Krufky790ba182007-12-16 21:20:21 -0300379 tuner_info(" E2-4 video if : %s\n",
380 vif[(buf[3] & 0x1c) >> 2]);
381 tuner_info(" E5 tuner gain : %s\n",
382 (buf[3] & 0x80)
383 ? ((buf[3] & 0x20) ? "external" : "normal")
384 : ((buf[3] & 0x20) ? "minimum" : "normal"));
385 tuner_info(" E7 vif agc output : %s\n",
386 (buf[3] & 0x80) ? ((buf[3] & 0x20)
387 ? "pin3 port, pin22 vif agc out"
388 : "pin22 port, pin3 vif acg ext in")
389 : "pin3+pin22 port");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 }
Michael Krufky790ba182007-12-16 21:20:21 -0300391 tuner_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392}
393
394/* ---------------------------------------------------------------------- */
395
Michael Krufky4e9154b2007-10-21 19:39:50 -0300396static int tda9887_set_tvnorm(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300398 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 struct tvnorm *norm = NULL;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300400 char *buf = priv->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 int i;
402
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300403 if (priv->mode == V4L2_TUNER_RADIO) {
404 if (priv->audmode == V4L2_TUNER_MODE_MONO)
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700405 norm = &radio_mono;
406 else
Mauro Carvalho Chehab586b0ca2005-06-28 20:45:21 -0700407 norm = &radio_stereo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 } else {
409 for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300410 if (tvnorms[i].std & priv->std) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 norm = tvnorms+i;
412 break;
413 }
414 }
415 }
416 if (NULL == norm) {
Michael Krufky790ba182007-12-16 21:20:21 -0300417 tuner_dbg("Unsupported tvnorm entry - audio muted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 return -1;
419 }
420
Michael Krufky790ba182007-12-16 21:20:21 -0300421 tuner_dbg("configure for: %s\n", norm->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 buf[1] = norm->b;
423 buf[2] = norm->c;
424 buf[3] = norm->e;
425 return 0;
426}
427
428static unsigned int port1 = UNSET;
429static unsigned int port2 = UNSET;
430static unsigned int qss = UNSET;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200431static unsigned int adjust = UNSET;
432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433module_param(port1, int, 0644);
434module_param(port2, int, 0644);
435module_param(qss, int, 0644);
436module_param(adjust, int, 0644);
437
Michael Krufky4e9154b2007-10-21 19:39:50 -0300438static int tda9887_set_insmod(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300440 struct tda9887_priv *priv = fe->analog_demod_priv;
441 char *buf = priv->data;
442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 if (UNSET != port1) {
444 if (port1)
445 buf[1] |= cOutputPort1Inactive;
446 else
447 buf[1] &= ~cOutputPort1Inactive;
448 }
449 if (UNSET != port2) {
450 if (port2)
451 buf[1] |= cOutputPort2Inactive;
452 else
453 buf[1] &= ~cOutputPort2Inactive;
454 }
455
456 if (UNSET != qss) {
457 if (qss)
458 buf[1] |= cQSS;
459 else
460 buf[1] &= ~cQSS;
461 }
462
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200463 if (adjust >= 0x00 && adjust < 0x20) {
464 buf[2] &= ~cTopMask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 buf[2] |= adjust;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 return 0;
468}
469
Michael Krufky710401b2007-12-16 19:53:32 -0300470static int tda9887_do_config(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300472 struct tda9887_priv *priv = fe->analog_demod_priv;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300473 char *buf = priv->data;
474
Michael Krufky710401b2007-12-16 19:53:32 -0300475 if (priv->config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 buf[1] &= ~cOutputPort1Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300477 if (priv->config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 buf[1] |= cOutputPort1Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300479 if (priv->config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 buf[1] &= ~cOutputPort2Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300481 if (priv->config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 buf[1] |= cOutputPort2Inactive;
483
Michael Krufky710401b2007-12-16 19:53:32 -0300484 if (priv->config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 buf[1] |= cQSS;
Michael Krufky710401b2007-12-16 19:53:32 -0300486 if (priv->config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 buf[1] &= ~cQSS;
488
Michael Krufky710401b2007-12-16 19:53:32 -0300489 if (priv->config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 buf[1] |= cAutoMuteFmActive;
Michael Krufky710401b2007-12-16 19:53:32 -0300491 if (priv->config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 buf[2] &= ~0x60;
Michael Krufky710401b2007-12-16 19:53:32 -0300493 switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 case TDA9887_DEEMPHASIS_NONE:
495 buf[2] |= cDeemphasisOFF;
496 break;
497 case TDA9887_DEEMPHASIS_50:
498 buf[2] |= cDeemphasisON | cDeemphasis50;
499 break;
500 case TDA9887_DEEMPHASIS_75:
501 buf[2] |= cDeemphasisON | cDeemphasis75;
502 break;
503 }
504 }
Michael Krufky710401b2007-12-16 19:53:32 -0300505 if (priv->config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200506 buf[2] &= ~cTopMask;
Michael Krufky710401b2007-12-16 19:53:32 -0300507 buf[2] |= (priv->config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200508 }
Michael Krufky710401b2007-12-16 19:53:32 -0300509 if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300510 (priv->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800511 buf[1] &= ~cQSS;
Michael Krufky710401b2007-12-16 19:53:32 -0300512 if (priv->config & TDA9887_GATING_18)
Trent Piephod7304de2006-08-24 22:43:45 -0300513 buf[3] &= ~cGating_36;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300514
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300515 if (priv->mode == V4L2_TUNER_RADIO) {
Michael Krufky710401b2007-12-16 19:53:32 -0300516 if (priv->config & TDA9887_RIF_41_3) {
Trent Piepho5e082f12007-08-03 18:32:38 -0300517 buf[3] &= ~cVideoIFMask;
518 buf[3] |= cRadioIF_41_30;
519 }
Michael Krufky710401b2007-12-16 19:53:32 -0300520 if (priv->config & TDA9887_GAIN_NORMAL)
Trent Piepho5e082f12007-08-03 18:32:38 -0300521 buf[3] &= ~cTunerGainLow;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300522 }
523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return 0;
525}
526
527/* ---------------------------------------------------------------------- */
528
Michael Krufky4e9154b2007-10-21 19:39:50 -0300529static int tda9887_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300531 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 unsigned char buf[1];
533 int rc;
534
535 memset(buf,0,sizeof(buf));
Michael Krufkydb8a6952007-08-21 01:24:42 -0300536 if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
Michael Krufky790ba182007-12-16 21:20:21 -0300537 tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300538 dump_read_message(fe, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 return 0;
540}
541
Michael Krufky4e9154b2007-10-21 19:39:50 -0300542static void tda9887_configure(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300544 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 int rc;
546
Michael Krufkyb2083192007-05-29 22:54:06 -0300547 memset(priv->data,0,sizeof(priv->data));
Michael Krufky4e9154b2007-10-21 19:39:50 -0300548 tda9887_set_tvnorm(fe);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700549
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200550 /* A note on the port settings:
551 These settings tend to depend on the specifics of the board.
552 By default they are set to inactive (bit value 1) by this driver,
553 overwriting any changes made by the tvnorm. This means that it
554 is the responsibility of the module using the tda9887 to set
555 these values in case of changes in the tvnorm.
556 In many cases port 2 should be made active (0) when selecting
557 SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
558
559 For the other standards the tda9887 application note says that
560 the ports should be set to active (0), but, again, that may
561 differ depending on the precise hardware configuration.
562 */
Michael Krufkyb2083192007-05-29 22:54:06 -0300563 priv->data[1] |= cOutputPort1Inactive;
564 priv->data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700565
Michael Krufky710401b2007-12-16 19:53:32 -0300566 tda9887_do_config(fe);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300567 tda9887_set_insmod(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300569 if (priv->mode == T_STANDBY)
Michael Krufkyb2083192007-05-29 22:54:06 -0300570 priv->data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700571
Michael Krufky790ba182007-12-16 21:20:21 -0300572 tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
573 priv->data[1], priv->data[2], priv->data[3]);
574 if (debug > 1)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300575 dump_write_message(fe, priv->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Michael Krufkydb8a6952007-08-21 01:24:42 -0300577 if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
Michael Krufky790ba182007-12-16 21:20:21 -0300578 tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Michael Krufky790ba182007-12-16 21:20:21 -0300580 if (debug > 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 msleep_interruptible(1000);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300582 tda9887_status(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
586/* ---------------------------------------------------------------------- */
587
Michael Krufky4e9154b2007-10-21 19:39:50 -0300588static void tda9887_tuner_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300590 struct tda9887_priv *priv = fe->analog_demod_priv;
Michael Krufky790ba182007-12-16 21:20:21 -0300591 tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
592 priv->data[1], priv->data[2], priv->data[3]);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300593}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Michael Krufky4e9154b2007-10-21 19:39:50 -0300595static int tda9887_get_afc(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300596{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300597 struct tda9887_priv *priv = fe->analog_demod_priv;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300598 static int AFC_BITS_2_kHz[] = {
599 -12500, -37500, -62500, -97500,
600 -112500, -137500, -162500, -187500,
601 187500, 162500, 137500, 112500,
602 97500 , 62500, 37500 , 12500
603 };
604 int afc=0;
605 __u8 reg = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Michael Krufkydb8a6952007-08-21 01:24:42 -0300607 if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300608 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700609
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300610 return afc;
611}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700612
Michael Krufky4e9154b2007-10-21 19:39:50 -0300613static void tda9887_standby(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300614{
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300615 struct tda9887_priv *priv = fe->analog_demod_priv;
616
617 priv->mode = T_STANDBY;
618
Michael Krufky4e9154b2007-10-21 19:39:50 -0300619 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300620}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800621
Michael Krufkyc7919d52007-12-08 17:06:30 -0300622static void tda9887_set_params(struct dvb_frontend *fe,
623 struct analog_parameters *params)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300624{
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300625 struct tda9887_priv *priv = fe->analog_demod_priv;
626
627 priv->mode = params->mode;
628 priv->audmode = params->audmode;
629 priv->std = params->std;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300630 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300631}
632
Michael Krufky710401b2007-12-16 19:53:32 -0300633static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
634{
635 struct tda9887_priv *priv = fe->analog_demod_priv;
636
637 priv->config = *(unsigned int *)priv_cfg;
638 tda9887_configure(fe);
639
640 return 0;
641}
642
Michael Krufky4e9154b2007-10-21 19:39:50 -0300643static void tda9887_release(struct dvb_frontend *fe)
Michael Krufky024cf532007-06-04 15:20:11 -0300644{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300645 kfree(fe->analog_demod_priv);
646 fe->analog_demod_priv = NULL;
Michael Krufky024cf532007-06-04 15:20:11 -0300647}
648
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300649static struct analog_demod_ops tda9887_ops = {
Michael Krufkya55db8c2007-12-09 13:52:51 -0300650 .info = {
Michael Krufky0f2ce982008-01-21 10:55:37 -0300651 .name = "tda9887",
Michael Krufkya55db8c2007-12-09 13:52:51 -0300652 },
Michael Krufkyc7919d52007-12-08 17:06:30 -0300653 .set_params = tda9887_set_params,
Michael Krufky9af596e2007-06-06 16:15:48 -0300654 .standby = tda9887_standby,
655 .tuner_status = tda9887_tuner_status,
656 .get_afc = tda9887_get_afc,
657 .release = tda9887_release,
Michael Krufky710401b2007-12-16 19:53:32 -0300658 .set_config = tda9887_set_config,
Michael Krufky9af596e2007-06-06 16:15:48 -0300659};
660
Michael Krufky8ca40832007-12-16 20:11:46 -0300661struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
662 struct i2c_adapter *i2c_adap,
663 u8 i2c_addr)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300664{
Michael Krufkyb2083192007-05-29 22:54:06 -0300665 struct tda9887_priv *priv = NULL;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300666
Michael Krufkyb2083192007-05-29 22:54:06 -0300667 priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
668 if (priv == NULL)
Michael Krufky8ca40832007-12-16 20:11:46 -0300669 return NULL;
670 fe->analog_demod_priv = priv;
Michael Krufkyb2083192007-05-29 22:54:06 -0300671
Michael Krufky8ca40832007-12-16 20:11:46 -0300672 priv->i2c_props.addr = i2c_addr;
673 priv->i2c_props.adap = i2c_adap;
Michael Krufky27566652008-04-22 14:41:53 -0300674 priv->i2c_props.name = "tda9887";
Michael Krufky71021d22007-12-17 09:49:33 -0300675 priv->mode = T_STANDBY;
Michael Krufkydb8a6952007-08-21 01:24:42 -0300676
Michael Krufky790ba182007-12-16 21:20:21 -0300677 tuner_info("tda988[5/6/7] found\n");
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300678
Michael Krufkybc3e5c72007-12-21 11:18:32 -0300679 memcpy(&fe->ops.analog_ops, &tda9887_ops,
680 sizeof(struct analog_demod_ops));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300681
Michael Krufky8ca40832007-12-16 20:11:46 -0300682 return fe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683}
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 */