blob: 7663a557975766f9d6040634d1882725c29afacc [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 Krufky8218b0b2007-06-26 13:12:08 -030012#include "tuner-driver.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -080014
Linus Torvalds1da177e2005-04-16 15:20:36 -070015/* Chips:
16 TDA9885 (PAL, NTSC)
17 TDA9886 (PAL, SECAM, NTSC)
18 TDA9887 (PAL, SECAM, NTSC, FM Radio)
19
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030020 Used as part of several tuners
Linus Torvalds1da177e2005-04-16 15:20:36 -070021*/
22
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030023#define tda9887_info(fmt, arg...) do {\
Michael Krufky4e9154b2007-10-21 19:39:50 -030024 printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c.name, \
25 i2c_adapter_id(priv->t->i2c.adapter), priv->t->i2c.addr , ##arg); } while (0)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -030026#define tda9887_dbg(fmt, arg...) do {\
27 if (tuner_debug) \
Michael Krufky4e9154b2007-10-21 19:39:50 -030028 printk(KERN_INFO "%s %d-%04x: " fmt, priv->t->i2c.name, \
29 i2c_adapter_id(priv->t->i2c.adapter), priv->t->i2c.addr , ##arg); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Michael Krufkyb2083192007-05-29 22:54:06 -030031struct tda9887_priv {
Michael Krufkydb8a6952007-08-21 01:24:42 -030032 struct tuner_i2c_props i2c_props;
33
Michael Krufkyb2083192007-05-29 22:54:06 -030034 unsigned char data[4];
Michael Krufky4e9154b2007-10-21 19:39:50 -030035
36 struct tuner *t;
Michael Krufkyb2083192007-05-29 22:54:06 -030037};
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39/* ---------------------------------------------------------------------- */
40
41#define UNSET (-1U)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43struct tvnorm {
44 v4l2_std_id std;
45 char *name;
46 unsigned char b;
47 unsigned char c;
48 unsigned char e;
49};
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051/* ---------------------------------------------------------------------- */
52
53//
54// TDA defines
55//
56
57//// first reg (b)
58#define cVideoTrapBypassOFF 0x00 // bit b0
59#define cVideoTrapBypassON 0x01 // bit b0
60
61#define cAutoMuteFmInactive 0x00 // bit b1
62#define cAutoMuteFmActive 0x02 // bit b1
63
64#define cIntercarrier 0x00 // bit b2
65#define cQSS 0x04 // bit b2
66
67#define cPositiveAmTV 0x00 // bit b3:4
68#define cFmRadio 0x08 // bit b3:4
69#define cNegativeFmTV 0x10 // bit b3:4
70
71
72#define cForcedMuteAudioON 0x20 // bit b5
73#define cForcedMuteAudioOFF 0x00 // bit b5
74
75#define cOutputPort1Active 0x00 // bit b6
76#define cOutputPort1Inactive 0x40 // bit b6
77
78#define cOutputPort2Active 0x00 // bit b7
79#define cOutputPort2Inactive 0x80 // bit b7
80
81
82//// second reg (c)
83#define cDeemphasisOFF 0x00 // bit c5
84#define cDeemphasisON 0x20 // bit c5
85
86#define cDeemphasis75 0x00 // bit c6
87#define cDeemphasis50 0x40 // bit c6
88
89#define cAudioGain0 0x00 // bit c7
90#define cAudioGain6 0x80 // bit c7
91
Hans Verkuilf98c55e2006-01-09 15:25:18 -020092#define cTopMask 0x1f // bit c0:4
Hans Verkuilf5b01422006-06-25 15:37:29 -030093#define cTopDefault 0x10 // bit c0:4
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95//// third reg (e)
96#define cAudioIF_4_5 0x00 // bit e0:1
97#define cAudioIF_5_5 0x01 // bit e0:1
98#define cAudioIF_6_0 0x02 // bit e0:1
99#define cAudioIF_6_5 0x03 // bit e0:1
100
101
Trent Piepho5e082f12007-08-03 18:32:38 -0300102#define cVideoIFMask 0x1c // bit e2:4
103/* Video IF selection in TV Mode (bit B3=0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104#define cVideoIF_58_75 0x00 // bit e2:4
105#define cVideoIF_45_75 0x04 // bit e2:4
106#define cVideoIF_38_90 0x08 // bit e2:4
107#define cVideoIF_38_00 0x0C // bit e2:4
108#define cVideoIF_33_90 0x10 // bit e2:4
109#define cVideoIF_33_40 0x14 // bit e2:4
110#define cRadioIF_45_75 0x18 // bit e2:4
111#define cRadioIF_38_90 0x1C // bit e2:4
112
Trent Piepho5e082f12007-08-03 18:32:38 -0300113/* IF1 selection in Radio Mode (bit B3=1) */
114#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
115#define cRadioIF_41_30 0x04 // bit e2,4
116
117/* Output of AFC pin in radio mode when bit E7=1 */
118#define cRadioAGC_SIF 0x00 // bit e3
119#define cRadioAGC_FM 0x08 // bit e3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121#define cTunerGainNormal 0x00 // bit e5
122#define cTunerGainLow 0x20 // bit e5
123
124#define cGating_18 0x00 // bit e6
125#define cGating_36 0x40 // bit e6
126
127#define cAgcOutON 0x80 // bit e7
128#define cAgcOutOFF 0x00 // bit e7
129
130/* ---------------------------------------------------------------------- */
131
132static struct tvnorm tvnorms[] = {
133 {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200134 .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
135 .name = "PAL-BGHN",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 .b = ( cNegativeFmTV |
137 cQSS ),
138 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200139 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300140 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200141 .e = ( cGating_36 |
142 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 cVideoIF_38_90 ),
144 },{
145 .std = V4L2_STD_PAL_I,
146 .name = "PAL-I",
147 .b = ( cNegativeFmTV |
148 cQSS ),
149 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200150 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300151 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200152 .e = ( cGating_36 |
153 cAudioIF_6_0 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 cVideoIF_38_90 ),
155 },{
156 .std = V4L2_STD_PAL_DK,
157 .name = "PAL-DK",
158 .b = ( cNegativeFmTV |
159 cQSS ),
160 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200161 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300162 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200163 .e = ( cGating_36 |
164 cAudioIF_6_5 |
165 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200167 .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
168 .name = "PAL-M/Nc",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 .b = ( cNegativeFmTV |
170 cQSS ),
171 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200172 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300173 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200174 .e = ( cGating_36 |
175 cAudioIF_4_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 cVideoIF_45_75 ),
177 },{
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200178 .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
179 .name = "SECAM-BGH",
180 .b = ( cPositiveAmTV |
181 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300182 .c = ( cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200183 .e = ( cGating_36 |
184 cAudioIF_5_5 |
185 cVideoIF_38_90 ),
186 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 .std = V4L2_STD_SECAM_L,
188 .name = "SECAM-L",
189 .b = ( cPositiveAmTV |
190 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300191 .c = ( cTopDefault),
Nickolay V. Shmyrev3375c392005-11-08 21:37:05 -0800192 .e = ( cGating_36 |
Nickolay V. Shmyrev5f7591c2005-11-08 21:37:04 -0800193 cAudioIF_6_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 cVideoIF_38_90 ),
195 },{
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200196 .std = V4L2_STD_SECAM_LC,
197 .name = "SECAM-L'",
198 .b = ( cOutputPort2Inactive |
199 cPositiveAmTV |
200 cQSS ),
Hans Verkuilf5b01422006-06-25 15:37:29 -0300201 .c = ( cTopDefault),
Mauro Carvalho Chehabf3c59872006-01-09 15:25:00 -0200202 .e = ( cGating_36 |
203 cAudioIF_6_5 |
204 cVideoIF_33_90 ),
205 },{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 .std = V4L2_STD_SECAM_DK,
207 .name = "SECAM-DK",
208 .b = ( cNegativeFmTV |
209 cQSS ),
210 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200211 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300212 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200213 .e = ( cGating_36 |
214 cAudioIF_6_5 |
215 cVideoIF_38_90 ),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 },{
Hans Verkuil0dfd8122006-02-07 06:45:34 -0200217 .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 .name = "NTSC-M",
219 .b = ( cNegativeFmTV |
220 cQSS ),
221 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200222 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300223 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 .e = ( cGating_36 |
225 cAudioIF_4_5 |
226 cVideoIF_45_75 ),
227 },{
228 .std = V4L2_STD_NTSC_M_JP,
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200229 .name = "NTSC-M-JP",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 .b = ( cNegativeFmTV |
231 cQSS ),
232 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200233 cDeemphasis50 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300234 cTopDefault),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 .e = ( cGating_36 |
236 cAudioIF_4_5 |
237 cVideoIF_58_75 ),
238 }
239};
240
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700241static struct tvnorm radio_stereo = {
242 .name = "Radio Stereo",
243 .b = ( cFmRadio |
244 cQSS ),
245 .c = ( cDeemphasisOFF |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200246 cAudioGain6 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300247 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200248 .e = ( cTunerGainLow |
249 cAudioIF_5_5 |
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700250 cRadioIF_38_90 ),
251};
252
253static struct tvnorm radio_mono = {
254 .name = "Radio Mono",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 .b = ( cFmRadio |
256 cQSS ),
257 .c = ( cDeemphasisON |
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200258 cDeemphasis75 |
Hans Verkuilf5b01422006-06-25 15:37:29 -0300259 cTopDefault),
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200260 .e = ( cTunerGainLow |
261 cAudioIF_5_5 |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 cRadioIF_38_90 ),
263};
264
265/* ---------------------------------------------------------------------- */
266
Michael Krufky4e9154b2007-10-21 19:39:50 -0300267static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300269 struct tda9887_priv *priv = fe->analog_demod_priv;
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 static char *afc[16] = {
272 "- 12.5 kHz",
273 "- 37.5 kHz",
274 "- 62.5 kHz",
275 "- 87.5 kHz",
276 "-112.5 kHz",
277 "-137.5 kHz",
278 "-162.5 kHz",
279 "-187.5 kHz [min]",
280 "+187.5 kHz [max]",
281 "+162.5 kHz",
282 "+137.5 kHz",
283 "+112.5 kHz",
284 "+ 87.5 kHz",
285 "+ 62.5 kHz",
286 "+ 37.5 kHz",
287 "+ 12.5 kHz",
288 };
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800289 tda9887_info("read: 0x%2x\n", buf[0]);
290 tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
291 tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
292 tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
293 tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
294 tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
Michael Krufky4e9154b2007-10-21 19:39:50 -0300297static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300299 struct tda9887_priv *priv = fe->analog_demod_priv;
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 static char *sound[4] = {
302 "AM/TV",
303 "FM/radio",
304 "FM/TV",
305 "FM/radio"
306 };
307 static char *adjust[32] = {
308 "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
309 "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
310 "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
311 "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
312 };
313 static char *deemph[4] = {
314 "no", "no", "75", "50"
315 };
316 static char *carrier[4] = {
317 "4.5 MHz",
318 "5.5 MHz",
319 "6.0 MHz",
320 "6.5 MHz / AM"
321 };
322 static char *vif[8] = {
323 "58.75 MHz",
324 "45.75 MHz",
325 "38.9 MHz",
326 "38.0 MHz",
327 "33.9 MHz",
328 "33.4 MHz",
329 "45.75 MHz + pin13",
330 "38.9 MHz + pin13",
331 };
332 static char *rif[4] = {
333 "44 MHz",
334 "52 MHz",
335 "52 MHz",
336 "44 MHz",
337 };
338
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800339 tda9887_info("write: byte B 0x%02x\n",buf[1]);
340 tda9887_info(" B0 video mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 (buf[1] & 0x01) ? "video trap" : "sound trap");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800342 tda9887_info(" B1 auto mute fm : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 (buf[1] & 0x02) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800344 tda9887_info(" B2 carrier mode : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 (buf[1] & 0x04) ? "QSS" : "Intercarrier");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800346 tda9887_info(" B3-4 tv sound/radio : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 sound[(buf[1] & 0x18) >> 3]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800348 tda9887_info(" B5 force mute audio: %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 (buf[1] & 0x20) ? "yes" : "no");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800350 tda9887_info(" B6 output port 1 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800352 tda9887_info(" B7 output port 2 : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
354
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800355 tda9887_info("write: byte C 0x%02x\n",buf[2]);
356 tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
357 tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
358 tda9887_info(" C7 audio gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 (buf[2] & 0x80) ? "-6" : "0");
360
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800361 tda9887_info("write: byte E 0x%02x\n",buf[3]);
362 tda9887_info(" E0-1 sound carrier : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 carrier[(buf[3] & 0x03)]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800364 tda9887_info(" E6 l pll gating : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 (buf[3] & 0x40) ? "36" : "13");
366
367 if (buf[1] & 0x08) {
368 /* radio */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800369 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 rif[(buf[3] & 0x0c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800371 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 (buf[3] & 0x80)
373 ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
374 : "fm radio carrier afc");
375 } else {
376 /* video */
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800377 tda9887_info(" E2-4 video if : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 vif[(buf[3] & 0x1c) >> 2]);
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800379 tda9887_info(" E5 tuner gain : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 (buf[3] & 0x80)
381 ? ((buf[3] & 0x20) ? "external" : "normal")
382 : ((buf[3] & 0x20) ? "minimum" : "normal"));
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800383 tda9887_info(" E7 vif agc output : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 (buf[3] & 0x80)
385 ? ((buf[3] & 0x20)
386 ? "pin3 port, pin22 vif agc out"
387 : "pin22 port, pin3 vif acg ext in")
388 : "pin3+pin22 port");
389 }
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800390 tda9887_info("--\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391}
392
393/* ---------------------------------------------------------------------- */
394
Michael Krufky4e9154b2007-10-21 19:39:50 -0300395static int tda9887_set_tvnorm(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300397 struct tda9887_priv *priv = fe->analog_demod_priv;
398 struct tuner *t = priv->t;
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
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300403 if (t->mode == V4L2_TUNER_RADIO) {
404 if (t->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++) {
410 if (tvnorms[i].std & t->std) {
411 norm = tvnorms+i;
412 break;
413 }
414 }
415 }
416 if (NULL == norm) {
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800417 tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 return -1;
419 }
420
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800421 tda9887_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 Krufky4e9154b2007-10-21 19:39:50 -0300470static int tda9887_set_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;
473 struct tuner *t = priv->t;
474 char *buf = priv->data;
475
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300476 if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 buf[1] &= ~cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300478 if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 buf[1] |= cOutputPort1Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300480 if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 buf[1] &= ~cOutputPort2Inactive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300482 if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 buf[1] |= cOutputPort2Inactive;
484
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300485 if (t->tda9887_config & TDA9887_QSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 buf[1] |= cQSS;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300487 if (t->tda9887_config & TDA9887_INTERCARRIER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 buf[1] &= ~cQSS;
489
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300490 if (t->tda9887_config & TDA9887_AUTOMUTE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 buf[1] |= cAutoMuteFmActive;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300492 if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 buf[2] &= ~0x60;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300494 switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 case TDA9887_DEEMPHASIS_NONE:
496 buf[2] |= cDeemphasisOFF;
497 break;
498 case TDA9887_DEEMPHASIS_50:
499 buf[2] |= cDeemphasisON | cDeemphasis50;
500 break;
501 case TDA9887_DEEMPHASIS_75:
502 buf[2] |= cDeemphasisON | cDeemphasis75;
503 break;
504 }
505 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300506 if (t->tda9887_config & TDA9887_TOP_SET) {
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200507 buf[2] &= ~cTopMask;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300508 buf[2] |= (t->tda9887_config >> 8) & cTopMask;
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200509 }
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300510 if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
Nickolay V. Shmyrev3ae1adc2005-11-08 21:37:39 -0800511 buf[1] &= ~cQSS;
Trent Piephod7304de2006-08-24 22:43:45 -0300512 if (t->tda9887_config & TDA9887_GATING_18)
513 buf[3] &= ~cGating_36;
Mauro Carvalho Chehabcefccc82006-12-04 08:31:35 -0300514
Trent Piepho5e082f12007-08-03 18:32:38 -0300515 if (t->mode == V4L2_TUNER_RADIO) {
516 if (t->tda9887_config & TDA9887_RIF_41_3) {
517 buf[3] &= ~cVideoIFMask;
518 buf[3] |= cRadioIF_41_30;
519 }
520 if (t->tda9887_config & TDA9887_GAIN_NORMAL)
521 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)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800537 tda9887_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;
545 struct tuner *t = priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 int rc;
547
Michael Krufkyb2083192007-05-29 22:54:06 -0300548 memset(priv->data,0,sizeof(priv->data));
Michael Krufky4e9154b2007-10-21 19:39:50 -0300549 tda9887_set_tvnorm(fe);
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700550
Hans Verkuilf98c55e2006-01-09 15:25:18 -0200551 /* A note on the port settings:
552 These settings tend to depend on the specifics of the board.
553 By default they are set to inactive (bit value 1) by this driver,
554 overwriting any changes made by the tvnorm. This means that it
555 is the responsibility of the module using the tda9887 to set
556 these values in case of changes in the tvnorm.
557 In many cases port 2 should be made active (0) when selecting
558 SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
559
560 For the other standards the tda9887 application note says that
561 the ports should be set to active (0), but, again, that may
562 differ depending on the precise hardware configuration.
563 */
Michael Krufkyb2083192007-05-29 22:54:06 -0300564 priv->data[1] |= cOutputPort1Inactive;
565 priv->data[1] |= cOutputPort2Inactive;
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700566
Michael Krufky4e9154b2007-10-21 19:39:50 -0300567 tda9887_set_config(fe);
568 tda9887_set_insmod(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700570 if (t->mode == T_STANDBY) {
Michael Krufkyb2083192007-05-29 22:54:06 -0300571 priv->data[1] |= cForcedMuteAudioON;
Mauro Carvalho Chehab793cf9e2005-09-09 13:03:37 -0700572 }
573
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800574 tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
Michael Krufkyb2083192007-05-29 22:54:06 -0300575 priv->data[1],priv->data[2],priv->data[3]);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300576 if (tuner_debug > 1)
Michael Krufky4e9154b2007-10-21 19:39:50 -0300577 dump_write_message(fe, priv->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Michael Krufkydb8a6952007-08-21 01:24:42 -0300579 if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800580 tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300582 if (tuner_debug > 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 msleep_interruptible(1000);
Michael Krufky4e9154b2007-10-21 19:39:50 -0300584 tda9887_status(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
588/* ---------------------------------------------------------------------- */
589
Michael Krufky4e9154b2007-10-21 19:39:50 -0300590static void tda9887_tuner_status(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300592 struct tda9887_priv *priv = fe->analog_demod_priv;
Michael Krufkyb2083192007-05-29 22:54:06 -0300593 tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300594}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Michael Krufky4e9154b2007-10-21 19:39:50 -0300596static int tda9887_get_afc(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300597{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300598 struct tda9887_priv *priv = fe->analog_demod_priv;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300599 static int AFC_BITS_2_kHz[] = {
600 -12500, -37500, -62500, -97500,
601 -112500, -137500, -162500, -187500,
602 187500, 162500, 137500, 112500,
603 97500 , 62500, 37500 , 12500
604 };
605 int afc=0;
606 __u8 reg = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Michael Krufkydb8a6952007-08-21 01:24:42 -0300608 if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300609 afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700610
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300611 return afc;
612}
Mauro Carvalho Chehab56fc08c2005-06-23 22:05:07 -0700613
Michael Krufky4e9154b2007-10-21 19:39:50 -0300614static void tda9887_standby(struct dvb_frontend *fe)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300615{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300616 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300617}
Hans Verkuil4eb0c142005-11-08 21:37:18 -0800618
Michael Krufky4e9154b2007-10-21 19:39:50 -0300619static void tda9887_set_freq(struct dvb_frontend *fe, unsigned int freq)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300620{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300621 tda9887_configure(fe);
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300622}
623
Michael Krufky4e9154b2007-10-21 19:39:50 -0300624static void tda9887_release(struct dvb_frontend *fe)
Michael Krufky024cf532007-06-04 15:20:11 -0300625{
Michael Krufky4e9154b2007-10-21 19:39:50 -0300626 kfree(fe->analog_demod_priv);
627 fe->analog_demod_priv = NULL;
Michael Krufky024cf532007-06-04 15:20:11 -0300628}
629
Michael Krufky1dde7a42007-10-21 13:40:56 -0300630static struct analog_tuner_ops tda9887_tuner_ops = {
Michael Krufky9af596e2007-06-06 16:15:48 -0300631 .set_tv_freq = tda9887_set_freq,
632 .set_radio_freq = tda9887_set_freq,
633 .standby = tda9887_standby,
634 .tuner_status = tda9887_tuner_status,
635 .get_afc = tda9887_get_afc,
636 .release = tda9887_release,
637};
638
Michael Krufkydb8a6952007-08-21 01:24:42 -0300639int tda9887_tuner_init(struct tuner *t)
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300640{
Michael Krufkyb2083192007-05-29 22:54:06 -0300641 struct tda9887_priv *priv = NULL;
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300642
Michael Krufkyb2083192007-05-29 22:54:06 -0300643 priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
644 if (priv == NULL)
645 return -ENOMEM;
Michael Krufky16f29162007-10-21 15:22:25 -0300646 t->fe.analog_demod_priv = priv;
Michael Krufkyb2083192007-05-29 22:54:06 -0300647
Michael Krufkydb8a6952007-08-21 01:24:42 -0300648 priv->i2c_props.addr = t->i2c.addr;
649 priv->i2c_props.adap = t->i2c.adapter;
Michael Krufky4e9154b2007-10-21 19:39:50 -0300650 priv->t = t;
Michael Krufkydb8a6952007-08-21 01:24:42 -0300651
652 strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name));
Mauro Carvalho Chehab15396232006-06-23 16:13:56 -0300653
654 tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
655 t->i2c.driver->driver.name);
656
Michael Krufky1dde7a42007-10-21 13:40:56 -0300657 t->fe.ops.analog_demod_ops = &tda9887_tuner_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659 return 0;
660}
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662/*
663 * Overrides for Emacs so that we follow Linus's tabbing style.
664 * ---------------------------------------------------------------------------
665 * Local variables:
666 * c-basic-offset: 8
667 * End:
668 */