blob: 95d974298fe93b5319b46211bc6c7f59b83784ee [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 Krufky91c9d4a2007-12-16 20:05:00 -030042 unsigned int mode;
43 unsigned int audmode;
44 v4l2_std_id std;
Michael Krufkyb2083192007-05-29 22:54:06 -030045};
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47/* ---------------------------------------------------------------------- */
48
49#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51struct tvnorm {
52 v4l2_std_id std;
53 char *name;
54 unsigned char b;
55 unsigned char c;
56 unsigned char e;
57};
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059/* ---------------------------------------------------------------------- */
60
61//
62// TDA defines
63//
64
65//// first reg (b)
66#define cVideoTrapBypassOFF 0x00 // bit b0
67#define cVideoTrapBypassON 0x01 // bit b0
68
69#define cAutoMuteFmInactive 0x00 // bit b1
70#define cAutoMuteFmActive 0x02 // bit b1
71
72#define cIntercarrier 0x00 // bit b2
73#define cQSS 0x04 // bit b2
74
75#define cPositiveAmTV 0x00 // bit b3:4
76#define cFmRadio 0x08 // bit b3:4
77#define cNegativeFmTV 0x10 // bit b3:4
78
79
80#define cForcedMuteAudioON 0x20 // bit b5
81#define cForcedMuteAudioOFF 0x00 // bit b5
82
83#define cOutputPort1Active 0x00 // bit b6
84#define cOutputPort1Inactive 0x40 // bit b6
85
86#define cOutputPort2Active 0x00 // bit b7
87#define cOutputPort2Inactive 0x80 // bit b7
88
89
90//// second reg (c)
91#define cDeemphasisOFF 0x00 // bit c5
92#define cDeemphasisON 0x20 // bit c5
93
94#define cDeemphasis75 0x00 // bit c6
95#define cDeemphasis50 0x40 // bit c6
96
97#define cAudioGain0 0x00 // bit c7
98#define cAudioGain6 0x80 // bit c7
99
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200100#define cTopMask 0x1f // bit c0:4
Hans Verkuilf5b01422006-06-25 15:37:29 -0300101#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103//// third reg (e)
104#define cAudioIF_4_5 0x00 // bit e0:1
105#define cAudioIF_5_5 0x01 // bit e0:1
106#define cAudioIF_6_0 0x02 // bit e0:1
107#define cAudioIF_6_5 0x03 // bit e0:1
108
109
Trent Piepho5e082f12007-08-03 18:32:38 -0300110#define cVideoIFMask 0x1c // bit e2:4
111/* Video IF selection in TV Mode (bit B3=0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#define cVideoIF_58_75 0x00 // bit e2:4
113#define cVideoIF_45_75 0x04 // bit e2:4
114#define cVideoIF_38_90 0x08 // bit e2:4
115#define cVideoIF_38_00 0x0C // bit e2:4
116#define cVideoIF_33_90 0x10 // bit e2:4
117#define cVideoIF_33_40 0x14 // bit e2:4
118#define cRadioIF_45_75 0x18 // bit e2:4
119#define cRadioIF_38_90 0x1C // bit e2:4
120
Trent Piepho5e082f12007-08-03 18:32:38 -0300121/* IF1 selection in Radio Mode (bit B3=1) */
122#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
123#define cRadioIF_41_30 0x04 // bit e2,4
124
125/* Output of AFC pin in radio mode when bit E7=1 */
126#define cRadioAGC_SIF 0x00 // bit e3
127#define cRadioAGC_FM 0x08 // bit e3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129#define cTunerGainNormal 0x00 // bit e5
130#define cTunerGainLow 0x20 // bit e5
131
132#define cGating_18 0x00 // bit e6
133#define cGating_36 0x40 // bit e6
134
135#define cAgcOutON 0x80 // bit e7
136#define cAgcOutOFF 0x00 // bit e7
137
138/* ---------------------------------------------------------------------- */
139
140static struct tvnorm tvnorms[] = {
141 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200142 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
143 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 .b = ( cNegativeFmTV |
145 cQSS ),
146 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200147 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300148 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200149 .e = ( cGating_36 |
150 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 cVideoIF_38_90 ),
152 },{
153 .std = V4L2_STD_PAL_I,
154 .name = "PAL-I",
155 .b = ( cNegativeFmTV |
156 cQSS ),
157 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200158 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300159 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200160 .e = ( cGating_36 |
161 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 cVideoIF_38_90 ),
163 },{
164 .std = V4L2_STD_PAL_DK,
165 .name = "PAL-DK",
166 .b = ( cNegativeFmTV |
167 cQSS ),
168 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200169 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300170 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200171 .e = ( cGating_36 |
172 cAudioIF_6_5 |
173 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200175 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
176 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 .b = ( cNegativeFmTV |
178 cQSS ),
179 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200180 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300181 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200182 .e = ( cGating_36 |
183 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 cVideoIF_45_75 ),
185 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200186 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
187 .name = "SECAM-BGH",
188 .b = ( cPositiveAmTV |
189 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300190 .c = ( cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200191 .e = ( cGating_36 |
192 cAudioIF_5_5 |
193 cVideoIF_38_90 ),
194 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 .std = V4L2_STD_SECAM_L,
196 .name = "SECAM-L",
197 .b = ( cPositiveAmTV |
198 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300199 .c = ( cTopDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800200 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800201 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 cVideoIF_38_90 ),
203 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200204 .std = V4L2_STD_SECAM_LC,
205 .name = "SECAM-L'",
206 .b = ( cOutputPort2Inactive |
207 cPositiveAmTV |
208 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300209 .c = ( cTopDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200210 .e = ( cGating_36 |
211 cAudioIF_6_5 |
212 cVideoIF_33_90 ),
213 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 .std = V4L2_STD_SECAM_DK,
215 .name = "SECAM-DK",
216 .b = ( cNegativeFmTV |
217 cQSS ),
218 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200219 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300220 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200221 .e = ( cGating_36 |
222 cAudioIF_6_5 |
223 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200225 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 .name = "NTSC-M",
227 .b = ( cNegativeFmTV |
228 cQSS ),
229 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200230 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300231 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 .e = ( cGating_36 |
233 cAudioIF_4_5 |
234 cVideoIF_45_75 ),
235 },{
236 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200237 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 .b = ( cNegativeFmTV |
239 cQSS ),
240 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200241 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300242 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 .e = ( cGating_36 |
244 cAudioIF_4_5 |
245 cVideoIF_58_75 ),
246 }
247};
248
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700249static struct tvnorm radio_stereo = {
250 .name = "Radio Stereo",
251 .b = ( cFmRadio |
252 cQSS ),
253 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200254 cAudioGain6 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300255 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200256 .e = ( cTunerGainLow |
257 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700258 cRadioIF_38_90 ),
259};
260
261static struct tvnorm radio_mono = {
262 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 .b = ( cFmRadio |
264 cQSS ),
265 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200266 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300267 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200268 .e = ( cTunerGainLow |
269 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 cRadioIF_38_90 ),
271};
272
273/* ---------------------------------------------------------------------- */
274
Michael Krufky4e9154b2007-10-21 19:39:50 -0300275static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300277 struct tda9887_priv *priv = fe->analog_demod_priv;
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 static char *afc[16] = {
280 "- 12.5 kHz",
281 "- 37.5 kHz",
282 "- 62.5 kHz",
283 "- 87.5 kHz",
284 "-112.5 kHz",
285 "-137.5 kHz",
286 "-162.5 kHz",
287 "-187.5 kHz [min]",
288 "+187.5 kHz [max]",
289 "+162.5 kHz",
290 "+137.5 kHz",
291 "+112.5 kHz",
292 "+ 87.5 kHz",
293 "+ 62.5 kHz",
294 "+ 37.5 kHz",
295 "+ 12.5 kHz",
296 };
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800297 tda9887_info("read: 0x%2x\n", buf[0]);
298 tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
299 tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
300 tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
301 tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
302 tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
Michael Krufky4e9154b2007-10-21 19:39:50 -0300305static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300307 struct tda9887_priv *priv = fe->analog_demod_priv;
308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 static char *sound[4] = {
310 "AM/TV",
311 "FM/radio",
312 "FM/TV",
313 "FM/radio"
314 };
315 static char *adjust[32] = {
316 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
317 "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
318 "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
319 "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
320 };
321 static char *deemph[4] = {
322 "no", "no", "75", "50"
323 };
324 static char *carrier[4] = {
325 "4.5 MHz",
326 "5.5 MHz",
327 "6.0 MHz",
328 "6.5 MHz / AM"
329 };
330 static char *vif[8] = {
331 "58.75 MHz",
332 "45.75 MHz",
333 "38.9 MHz",
334 "38.0 MHz",
335 "33.9 MHz",
336 "33.4 MHz",
337 "45.75 MHz + pin13",
338 "38.9 MHz + pin13",
339 };
340 static char *rif[4] = {
341 "44 MHz",
342 "52 MHz",
343 "52 MHz",
344 "44 MHz",
345 };
346
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800347 tda9887_info("write: byte B 0x%02x\n",buf[1]);
348 tda9887_info(" B0 video mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 (buf[1] & 0x01) ? "video trap" : "sound trap");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800350 tda9887_info(" B1 auto mute fm : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 (buf[1] & 0x02) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800352 tda9887_info(" B2 carrier mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 (buf[1] & 0x04) ? "QSS" : "Intercarrier");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800354 tda9887_info(" B3-4 tv sound/radio : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 sound[(buf[1] & 0x18) >> 3]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800356 tda9887_info(" B5 force mute audio: %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 (buf[1] & 0x20) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800358 tda9887_info(" B6 output port 1 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800360 tda9887_info(" B7 output port 2 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
362
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800363 tda9887_info("write: byte C 0x%02x\n",buf[2]);
364 tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
365 tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
366 tda9887_info(" C7 audio gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 (buf[2] & 0x80) ? "-6" : "0");
368
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800369 tda9887_info("write: byte E 0x%02x\n",buf[3]);
370 tda9887_info(" E0-1 sound carrier : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 carrier[(buf[3] & 0x03)]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800372 tda9887_info(" E6 l pll gating : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 (buf[3] & 0x40) ? "36" : "13");
374
375 if (buf[1] & 0x08) {
376 /* radio */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800377 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 rif[(buf[3] & 0x0c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800379 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 (buf[3] & 0x80)
381 ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
382 : "fm radio carrier afc");
383 } else {
384 /* video */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800385 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 vif[(buf[3] & 0x1c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800387 tda9887_info(" E5 tuner gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 (buf[3] & 0x80)
389 ? ((buf[3] & 0x20) ? "external" : "normal")
390 : ((buf[3] & 0x20) ? "minimum" : "normal"));
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800391 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 (buf[3] & 0x80)
393 ? ((buf[3] & 0x20)
394 ? "pin3 port, pin22 vif agc out"
395 : "pin22 port, pin3 vif acg ext in")
396 : "pin3+pin22 port");
397 }
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800398 tda9887_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399}
400
401/* ---------------------------------------------------------------------- */
402
Michael Krufky4e9154b2007-10-21 19:39:50 -0300403static int tda9887_set_tvnorm(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300405 struct tda9887_priv *priv = fe->analog_demod_priv;
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
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300410 if (priv->mode == V4L2_TUNER_RADIO) {
411 if (priv->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++) {
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300417 if (tvnorms[i].std & priv->std) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 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;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300480 char *buf = priv->data;
481
Michael Krufky710401b2007-12-16 19:53:32 -0300482 if (priv->config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 buf[1] &= ~cOutputPort1Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300484 if (priv->config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 buf[1] |= cOutputPort1Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300486 if (priv->config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 buf[1] &= ~cOutputPort2Inactive;
Michael Krufky710401b2007-12-16 19:53:32 -0300488 if (priv->config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 buf[1] |= cOutputPort2Inactive;
490
Michael Krufky710401b2007-12-16 19:53:32 -0300491 if (priv->config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 buf[1] |= cQSS;
Michael Krufky710401b2007-12-16 19:53:32 -0300493 if (priv->config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 buf[1] &= ~cQSS;
495
Michael Krufky710401b2007-12-16 19:53:32 -0300496 if (priv->config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 buf[1] |= cAutoMuteFmActive;
Michael Krufky710401b2007-12-16 19:53:32 -0300498 if (priv->config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 buf[2] &= ~0x60;
Michael Krufky710401b2007-12-16 19:53:32 -0300500 switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 case TDA9887_DEEMPHASIS_NONE:
502 buf[2] |= cDeemphasisOFF;
503 break;
504 case TDA9887_DEEMPHASIS_50:
505 buf[2] |= cDeemphasisON | cDeemphasis50;
506 break;
507 case TDA9887_DEEMPHASIS_75:
508 buf[2] |= cDeemphasisON | cDeemphasis75;
509 break;
510 }
511 }
Michael Krufky710401b2007-12-16 19:53:32 -0300512 if (priv->config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200513 buf[2] &= ~cTopMask;
Michael Krufky710401b2007-12-16 19:53:32 -0300514 buf[2] |= (priv->config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200515 }
Michael Krufky710401b2007-12-16 19:53:32 -0300516 if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300517 (priv->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800518 buf[1] &= ~cQSS;
Michael Krufky710401b2007-12-16 19:53:32 -0300519 if (priv->config & TDA9887_GATING_18)
Trent Piephod7304de2006-08-24 22:43:45 -0300520 buf[3] &= ~cGating_36;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300521
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300522 if (priv->mode == V4L2_TUNER_RADIO) {
Michael Krufky710401b2007-12-16 19:53:32 -0300523 if (priv->config & TDA9887_RIF_41_3) {
Trent Piepho5e082f12007-08-03 18:32:38 -0300524 buf[3] &= ~cVideoIFMask;
525 buf[3] |= cRadioIF_41_30;
526 }
Michael Krufky710401b2007-12-16 19:53:32 -0300527 if (priv->config & TDA9887_GAIN_NORMAL)
Trent Piepho5e082f12007-08-03 18:32:38 -0300528 buf[3] &= ~cTunerGainLow;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300529 }
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return 0;
532}
533
534/* ---------------------------------------------------------------------- */
535
Michael Krufky4e9154b2007-10-21 19:39:50 -0300536static int tda9887_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300538 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 unsigned char buf[1];
540 int rc;
541
542 memset(buf,0,sizeof(buf));
Michael Krufkydb8a6952007-08-21 01:24:42 -0300543 if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800544 tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300545 dump_read_message(fe, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 return 0;
547}
548
Michael Krufky4e9154b2007-10-21 19:39:50 -0300549static void tda9887_configure(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300551 struct tda9887_priv *priv = fe->analog_demod_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 int rc;
553
Michael Krufkyb2083192007-05-29 22:54:06 -0300554 memset(priv->data,0,sizeof(priv->data));
Michael Krufky4e9154b2007-10-21 19:39:50 -0300555 tda9887_set_tvnorm(fe);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700556
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200557 /* A note on the port settings:
558 These settings tend to depend on the specifics of the board.
559 By default they are set to inactive (bit value 1) by this driver,
560 overwriting any changes made by the tvnorm. This means that it
561 is the responsibility of the module using the tda9887 to set
562 these values in case of changes in the tvnorm.
563 In many cases port 2 should be made active (0) when selecting
564 SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
565
566 For the other standards the tda9887 application note says that
567 the ports should be set to active (0), but, again, that may
568 differ depending on the precise hardware configuration.
569 */
Michael Krufkyb2083192007-05-29 22:54:06 -0300570 priv->data[1] |= cOutputPort1Inactive;
571 priv->data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700572
Michael Krufky710401b2007-12-16 19:53:32 -0300573 tda9887_do_config(fe);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300574 tda9887_set_insmod(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300576 if (priv->mode == T_STANDBY)
Michael Krufkyb2083192007-05-29 22:54:06 -0300577 priv->data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700578
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 Krufky91c9d4a2007-12-16 20:05:00 -0300622 struct tda9887_priv *priv = fe->analog_demod_priv;
623
624 priv->mode = T_STANDBY;
625
Michael Krufky4e9154b2007-10-21 19:39:50 -0300626 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300627}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800628
Michael Krufkyc7919d52007-12-08 17:06:30 -0300629static void tda9887_set_params(struct dvb_frontend *fe,
630 struct analog_parameters *params)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300631{
Michael Krufky91c9d4a2007-12-16 20:05:00 -0300632 struct tda9887_priv *priv = fe->analog_demod_priv;
633
634 priv->mode = params->mode;
635 priv->audmode = params->audmode;
636 priv->std = params->std;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300637 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300638}
639
Michael Krufky710401b2007-12-16 19:53:32 -0300640static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
641{
642 struct tda9887_priv *priv = fe->analog_demod_priv;
643
644 priv->config = *(unsigned int *)priv_cfg;
645 tda9887_configure(fe);
646
647 return 0;
648}
649
Michael Krufky4e9154b2007-10-21 19:39:50 -0300650static void tda9887_release(struct dvb_frontend *fe)
Michael Krufky024cf532007-06-04 15:20:11 -0300651{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300652 kfree(fe->analog_demod_priv);
653 fe->analog_demod_priv = NULL;
Michael Krufky024cf532007-06-04 15:20:11 -0300654}
655
Michael Krufky1dde7a42007-10-21 13:40:56 -0300656static struct analog_tuner_ops tda9887_tuner_ops = {
Michael Krufkya55db8c2007-12-09 13:52:51 -0300657 .info = {
658 .name = "TDA9887",
659 },
Michael Krufkyc7919d52007-12-08 17:06:30 -0300660 .set_params = tda9887_set_params,
Michael Krufky9af596e2007-06-06 16:15:48 -0300661 .standby = tda9887_standby,
662 .tuner_status = tda9887_tuner_status,
663 .get_afc = tda9887_get_afc,
664 .release = tda9887_release,
Michael Krufky710401b2007-12-16 19:53:32 -0300665 .set_config = tda9887_set_config,
Michael Krufky9af596e2007-06-06 16:15:48 -0300666};
667
Michael Krufky31c95842007-10-21 20:48:48 -0300668int tda9887_attach(struct tuner *t)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300669{
Michael Krufkyb2083192007-05-29 22:54:06 -0300670 struct tda9887_priv *priv = NULL;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300671
Michael Krufkyb2083192007-05-29 22:54:06 -0300672 priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
673 if (priv == NULL)
674 return -ENOMEM;
Michael Krufky16f29162007-10-21 15:22:25 -0300675 t->fe.analog_demod_priv = priv;
Michael Krufkyb2083192007-05-29 22:54:06 -0300676
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300677 priv->i2c_props.addr = t->i2c->addr;
678 priv->i2c_props.adap = t->i2c->adapter;
Michael Krufkydb8a6952007-08-21 01:24:42 -0300679
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300680 strlcpy(t->i2c->name, "tda9887", sizeof(t->i2c->name));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300681
Hans Verkuil1cba97d72007-09-14 05:13:54 -0300682 tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c->addr,
683 t->i2c->driver->driver.name);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300684
Michael Krufky1dde7a42007-10-21 13:40:56 -0300685 t->fe.ops.analog_demod_ops = &tda9887_tuner_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 return 0;
688}
Michael Krufky31c95842007-10-21 20:48:48 -0300689EXPORT_SYMBOL_GPL(tda9887_attach);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Michael Krufky5ef47302007-10-27 02:17:19 -0300691MODULE_LICENSE("GPL");
692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693/*
694 * Overrides for Emacs so that we follow Linus's tabbing style.
695 * ---------------------------------------------------------------------------
696 * Local variables:
697 * c-basic-offset: 8
698 * End:
699 */