Removed
Link Here
|
1 |
/* |
2 |
* $Id: tuner.c,v 1.36 2005/01/14 13:29:40 kraxel Exp $ |
3 |
*/ |
4 |
|
5 |
#include <linux/module.h> |
6 |
#include <linux/moduleparam.h> |
7 |
#include <linux/kernel.h> |
8 |
#include <linux/sched.h> |
9 |
#include <linux/string.h> |
10 |
#include <linux/timer.h> |
11 |
#include <linux/delay.h> |
12 |
#include <linux/errno.h> |
13 |
#include <linux/slab.h> |
14 |
#include <linux/poll.h> |
15 |
#include <linux/i2c.h> |
16 |
#include <linux/types.h> |
17 |
#include <linux/videodev.h> |
18 |
#include <linux/init.h> |
19 |
|
20 |
#include <media/tuner.h> |
21 |
#include <media/audiochip.h> |
22 |
|
23 |
#define UNSET (-1U) |
24 |
|
25 |
/* standard i2c insmod options */ |
26 |
static unsigned short normal_i2c[] = {I2C_CLIENT_END}; |
27 |
static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END}; |
28 |
I2C_CLIENT_INSMOD; |
29 |
|
30 |
/* insmod options used at init time => read/only */ |
31 |
static unsigned int type = UNSET; |
32 |
static unsigned int addr = 0; |
33 |
module_param(type, int, 0444); |
34 |
module_param(addr, int, 0444); |
35 |
|
36 |
/* insmod options used at runtime => read/write */ |
37 |
static unsigned int debug = 0; |
38 |
static unsigned int tv_antenna = 1; |
39 |
static unsigned int radio_antenna = 0; |
40 |
static unsigned int optimize_vco = 1; |
41 |
module_param(debug, int, 0644); |
42 |
module_param(tv_antenna, int, 0644); |
43 |
module_param(radio_antenna, int, 0644); |
44 |
module_param(optimize_vco, int, 0644); |
45 |
|
46 |
static unsigned int tv_range[2] = { 44, 958 }; |
47 |
static unsigned int radio_range[2] = { 65, 108 }; |
48 |
|
49 |
module_param_array(tv_range, int, NULL, 0644); |
50 |
module_param_array(radio_range, int, NULL, 0644); |
51 |
|
52 |
MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); |
53 |
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); |
54 |
MODULE_LICENSE("GPL"); |
55 |
|
56 |
static int this_adap; |
57 |
#define dprintk if (debug) printk |
58 |
|
59 |
struct tuner { |
60 |
unsigned int type; /* chip type */ |
61 |
unsigned int freq; /* keep track of the current settings */ |
62 |
v4l2_std_id std; |
63 |
int using_v4l2; |
64 |
|
65 |
enum v4l2_tuner_type mode; |
66 |
unsigned int input; |
67 |
|
68 |
// only for MT2032 |
69 |
unsigned int xogc; |
70 |
unsigned int radio_if2; |
71 |
|
72 |
void (*tv_freq)(struct i2c_client *c, unsigned int freq); |
73 |
void (*radio_freq)(struct i2c_client *c, unsigned int freq); |
74 |
}; |
75 |
|
76 |
static struct i2c_driver driver; |
77 |
static struct i2c_client client_template; |
78 |
|
79 |
/* ---------------------------------------------------------------------- */ |
80 |
|
81 |
/* tv standard selection for Temic 4046 FM5 |
82 |
this value takes the low bits of control byte 2 |
83 |
from datasheet Rev.01, Feb.00 |
84 |
standard BG I L L2 D |
85 |
picture IF 38.9 38.9 38.9 33.95 38.9 |
86 |
sound 1 33.4 32.9 32.4 40.45 32.4 |
87 |
sound 2 33.16 |
88 |
NICAM 33.05 32.348 33.05 33.05 |
89 |
*/ |
90 |
#define TEMIC_SET_PAL_I 0x05 |
91 |
#define TEMIC_SET_PAL_DK 0x09 |
92 |
#define TEMIC_SET_PAL_L 0x0a // SECAM ? |
93 |
#define TEMIC_SET_PAL_L2 0x0b // change IF ! |
94 |
#define TEMIC_SET_PAL_BG 0x0c |
95 |
|
96 |
/* tv tuner system standard selection for Philips FQ1216ME |
97 |
this value takes the low bits of control byte 2 |
98 |
from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") |
99 |
standard BG DK I L L` |
100 |
picture carrier 38.90 38.90 38.90 38.90 33.95 |
101 |
colour 34.47 34.47 34.47 34.47 38.38 |
102 |
sound 1 33.40 32.40 32.90 32.40 40.45 |
103 |
sound 2 33.16 - - - - |
104 |
NICAM 33.05 33.05 32.35 33.05 39.80 |
105 |
*/ |
106 |
#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ |
107 |
#define PHILIPS_SET_PAL_BGDK 0x09 |
108 |
#define PHILIPS_SET_PAL_L2 0x0a |
109 |
#define PHILIPS_SET_PAL_L 0x0b |
110 |
|
111 |
/* system switching for Philips FI1216MF MK2 |
112 |
from datasheet "1996 Jul 09", |
113 |
standard BG L L' |
114 |
picture carrier 38.90 38.90 33.95 |
115 |
colour 34.47 34.37 38.38 |
116 |
sound 1 33.40 32.40 40.45 |
117 |
sound 2 33.16 - - |
118 |
NICAM 33.05 33.05 39.80 |
119 |
*/ |
120 |
#define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ |
121 |
#define PHILIPS_MF_SET_PAL_L 0x03 // France |
122 |
#define PHILIPS_MF_SET_PAL_L2 0x02 // L' |
123 |
|
124 |
|
125 |
/* ---------------------------------------------------------------------- */ |
126 |
|
127 |
struct tunertype |
128 |
{ |
129 |
char *name; |
130 |
unsigned char Vendor; |
131 |
unsigned char Type; |
132 |
|
133 |
unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ |
134 |
unsigned short thresh2; /* band switch VHF_HI <=> UHF */ |
135 |
unsigned char VHF_L; |
136 |
unsigned char VHF_H; |
137 |
unsigned char UHF; |
138 |
unsigned char config; |
139 |
unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, |
140 |
732 =16*45.75 NTSCi, |
141 |
940 =16*58.75 NTSC-Japan |
142 |
704 =16*44 ATSC */ |
143 |
}; |
144 |
|
145 |
/* |
146 |
* The floats in the tuner struct are computed at compile time |
147 |
* by gcc and cast back to integers. Thus we don't violate the |
148 |
* "no float in kernel" rule. |
149 |
*/ |
150 |
static struct tunertype tuners[] = { |
151 |
{ "Temic PAL (4002 FH5)", TEMIC, PAL, |
152 |
16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, |
153 |
{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I, |
154 |
16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, |
155 |
{ "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC, |
156 |
16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, |
157 |
{ "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM, |
158 |
16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623}, |
159 |
|
160 |
{ "NoTuner", NoTuner, NOTUNER, |
161 |
0,0,0x00,0x00,0x00,0x00,0x00}, |
162 |
{ "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL, |
163 |
16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, |
164 |
{ "Temic NTSC (4032 FY5)", TEMIC, NTSC, |
165 |
16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, |
166 |
{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I, |
167 |
16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, |
168 |
|
169 |
{ "Temic NTSC (4036 FY5)", TEMIC, NTSC, |
170 |
16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, |
171 |
{ "Alps HSBH1", TEMIC, NTSC, |
172 |
16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, |
173 |
{ "Alps TSBE1",TEMIC,PAL, |
174 |
16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, |
175 |
{ "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ |
176 |
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, |
177 |
|
178 |
{ "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ |
179 |
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, |
180 |
{ "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ |
181 |
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, |
182 |
{ "Temic PAL_BG (4006FH5)", TEMIC, PAL, |
183 |
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
184 |
{ "Alps TSCH6",Alps,NTSC, |
185 |
16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732}, |
186 |
|
187 |
{ "Temic PAL_DK (4016 FY5)",TEMIC,PAL, |
188 |
16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623}, |
189 |
{ "Philips NTSC_M (MK2)",Philips,NTSC, |
190 |
16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, |
191 |
{ "Temic PAL_I (4066 FY5)", TEMIC, PAL_I, |
192 |
16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, |
193 |
{ "Temic PAL* auto (4006 FN5)", TEMIC, PAL, |
194 |
16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, |
195 |
|
196 |
{ "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, |
197 |
16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, |
198 |
{ "Temic NTSC (4039 FR5)", TEMIC, NTSC, |
199 |
16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, |
200 |
{ "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL, |
201 |
16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, |
202 |
{ "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL, |
203 |
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
204 |
|
205 |
{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, |
206 |
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
207 |
{ "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I, |
208 |
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
209 |
{ "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I, |
210 |
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
211 |
{ "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC, |
212 |
16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732}, |
213 |
|
214 |
{ "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL, |
215 |
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
216 |
{ "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL, |
217 |
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
218 |
{ "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, |
219 |
16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, |
220 |
{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ |
221 |
16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, |
222 |
|
223 |
{ "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ |
224 |
16*169,16*464,0xA0,0x90,0x30,0x8e,623}, |
225 |
{ "MT20xx universal", Microtune,PAL|NTSC, |
226 |
0,0,0,0,0,0,0}, |
227 |
{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL, |
228 |
16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, |
229 |
{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL, |
230 |
16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623}, |
231 |
|
232 |
{ "Temic NTSC (4136 FY5)", TEMIC, NTSC, |
233 |
16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, |
234 |
{ "LG PAL (newer TAPC series)", LGINNOTEK, PAL, |
235 |
16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623}, |
236 |
{ "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL, |
237 |
16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, |
238 |
{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC, |
239 |
16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, |
240 |
|
241 |
{ "HITACHI V7-J180AT", HITACHI, NTSC, |
242 |
16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, |
243 |
{ "Philips PAL_MK (FI1216 MK)", Philips, PAL, |
244 |
16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, |
245 |
{ "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, |
246 |
16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732}, |
247 |
{ "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC, |
248 |
16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, |
249 |
|
250 |
{ "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC, |
251 |
16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, |
252 |
{ "Microtune 4049 FM5",Microtune,PAL, |
253 |
16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, |
254 |
{ "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, |
255 |
16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, |
256 |
{ "LG NTSC (TAPE series)", LGINNOTEK, NTSC, |
257 |
16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, |
258 |
|
259 |
{ "Tenna TNF 8831 BGFF)", Philips, PAL, |
260 |
16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, |
261 |
{ "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC, |
262 |
16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732}, |
263 |
{ "TCL 2002N", TCL, NTSC, |
264 |
16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732}, |
265 |
{ "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL, |
266 |
16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, |
267 |
|
268 |
{ "Thomson DDT 7610 ATSC/NTSC)", THOMSON, ATSC, |
269 |
16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, |
270 |
{ "Philips FQ1286", Philips, NTSC, |
271 |
16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, // UHF band untested |
272 |
|
273 |
}; |
274 |
#define TUNERS ARRAY_SIZE(tuners) |
275 |
|
276 |
/* ---------------------------------------------------------------------- */ |
277 |
|
278 |
static int tuner_getstatus(struct i2c_client *c) |
279 |
{ |
280 |
unsigned char byte; |
281 |
|
282 |
struct tuner *t = i2c_get_clientdata(c); |
283 |
|
284 |
if (t->type == TUNER_MT2032) |
285 |
return 0; |
286 |
|
287 |
if (1 != i2c_master_recv(c,&byte,1)) |
288 |
return 0; |
289 |
return byte; |
290 |
} |
291 |
|
292 |
#define TUNER_POR 0x80 |
293 |
#define TUNER_FL 0x40 |
294 |
#define TUNER_MODE 0x38 |
295 |
#define TUNER_AFC 0x07 |
296 |
|
297 |
#define TUNER_STEREO 0x10 /* radio mode */ |
298 |
#define TUNER_SIGNAL 0x07 /* radio mode */ |
299 |
|
300 |
static int tuner_signal(struct i2c_client *c) |
301 |
{ |
302 |
return (tuner_getstatus(c) & TUNER_SIGNAL)<<13; |
303 |
} |
304 |
|
305 |
static int tuner_stereo(struct i2c_client *c) |
306 |
{ |
307 |
return (tuner_getstatus (c) & TUNER_STEREO); |
308 |
} |
309 |
|
310 |
#if 0 /* unused */ |
311 |
static int tuner_islocked (struct i2c_client *c) |
312 |
{ |
313 |
return (tuner_getstatus (c) & TUNER_FL); |
314 |
} |
315 |
|
316 |
static int tuner_afcstatus (struct i2c_client *c) |
317 |
{ |
318 |
return (tuner_getstatus (c) & TUNER_AFC) - 2; |
319 |
} |
320 |
|
321 |
static int tuner_mode (struct i2c_client *c) |
322 |
{ |
323 |
return (tuner_getstatus (c) & TUNER_MODE) >> 3; |
324 |
} |
325 |
#endif |
326 |
|
327 |
/* ---------------------------------------------------------------------- */ |
328 |
|
329 |
#define MT2032 0x04 |
330 |
#define MT2030 0x06 |
331 |
#define MT2040 0x07 |
332 |
#define MT2050 0x42 |
333 |
|
334 |
static char *microtune_part[] = { |
335 |
[ MT2030 ] = "MT2030", |
336 |
[ MT2032 ] = "MT2032", |
337 |
[ MT2040 ] = "MT2040", |
338 |
[ MT2050 ] = "MT2050", |
339 |
}; |
340 |
|
341 |
// IsSpurInBand()? |
342 |
static int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to) |
343 |
{ |
344 |
int n1=1,n2,f; |
345 |
|
346 |
f1=f1/1000; //scale to kHz to avoid 32bit overflows |
347 |
f2=f2/1000; |
348 |
spectrum_from/=1000; |
349 |
spectrum_to/=1000; |
350 |
|
351 |
dprintk("spurcheck f1=%d f2=%d from=%d to=%d\n",f1,f2,spectrum_from,spectrum_to); |
352 |
|
353 |
do { |
354 |
n2=-n1; |
355 |
f=n1*(f1-f2); |
356 |
do { |
357 |
n2--; |
358 |
f=f-f2; |
359 |
dprintk(" spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); |
360 |
|
361 |
if( (f>spectrum_from) && (f<spectrum_to)) |
362 |
printk("mt2032 spurcheck triggered: %d\n",n1); |
363 |
} while ( (f>(f2-spectrum_to)) || (n2>-5)); |
364 |
n1++; |
365 |
} while (n1<5); |
366 |
|
367 |
return 1; |
368 |
} |
369 |
|
370 |
static int mt2032_compute_freq(unsigned int rfin, |
371 |
unsigned int if1, unsigned int if2, |
372 |
unsigned int spectrum_from, |
373 |
unsigned int spectrum_to, |
374 |
unsigned char *buf, |
375 |
int *ret_sel, |
376 |
unsigned int xogc) //all in Hz |
377 |
{ |
378 |
unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, |
379 |
desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; |
380 |
|
381 |
fref= 5250 *1000; //5.25MHz |
382 |
desired_lo1=rfin+if1; |
383 |
|
384 |
lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); |
385 |
lo1n=lo1/8; |
386 |
lo1a=lo1-(lo1n*8); |
387 |
|
388 |
s=rfin/1000/1000+1090; |
389 |
|
390 |
if(optimize_vco) { |
391 |
if(s>1890) sel=0; |
392 |
else if(s>1720) sel=1; |
393 |
else if(s>1530) sel=2; |
394 |
else if(s>1370) sel=3; |
395 |
else sel=4; // >1090 |
396 |
} |
397 |
else { |
398 |
if(s>1790) sel=0; // <1958 |
399 |
else if(s>1617) sel=1; |
400 |
else if(s>1449) sel=2; |
401 |
else if(s>1291) sel=3; |
402 |
else sel=4; // >1090 |
403 |
} |
404 |
*ret_sel=sel; |
405 |
|
406 |
lo1freq=(lo1a+8*lo1n)*fref; |
407 |
|
408 |
dprintk("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", |
409 |
rfin,lo1,lo1n,lo1a,sel,lo1freq); |
410 |
|
411 |
desired_lo2=lo1freq-rfin-if2; |
412 |
lo2=(desired_lo2)/fref; |
413 |
lo2n=lo2/8; |
414 |
lo2a=lo2-(lo2n*8); |
415 |
lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith |
416 |
lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; |
417 |
|
418 |
dprintk("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", |
419 |
rfin,lo2,lo2n,lo2a,lo2num,lo2freq); |
420 |
|
421 |
if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) { |
422 |
printk("mt2032: frequency parameters out of range: %d %d %d %d\n", |
423 |
lo1a, lo1n, lo2a,lo2n); |
424 |
return(-1); |
425 |
} |
426 |
|
427 |
mt2032_spurcheck(lo1freq, desired_lo2, spectrum_from, spectrum_to); |
428 |
// should recalculate lo1 (one step up/down) |
429 |
|
430 |
// set up MT2032 register map for transfer over i2c |
431 |
buf[0]=lo1n-1; |
432 |
buf[1]=lo1a | (sel<<4); |
433 |
buf[2]=0x86; // LOGC |
434 |
buf[3]=0x0f; //reserved |
435 |
buf[4]=0x1f; |
436 |
buf[5]=(lo2n-1) | (lo2a<<5); |
437 |
if(rfin >400*1000*1000) |
438 |
buf[6]=0xe4; |
439 |
else |
440 |
buf[6]=0xf4; // set PKEN per rev 1.2 |
441 |
buf[7]=8+xogc; |
442 |
buf[8]=0xc3; //reserved |
443 |
buf[9]=0x4e; //reserved |
444 |
buf[10]=0xec; //reserved |
445 |
buf[11]=(lo2num&0xff); |
446 |
buf[12]=(lo2num>>8) |0x80; // Lo2RST |
447 |
|
448 |
return 0; |
449 |
} |
450 |
|
451 |
static int mt2032_check_lo_lock(struct i2c_client *c) |
452 |
{ |
453 |
int try,lock=0; |
454 |
unsigned char buf[2]; |
455 |
for(try=0;try<10;try++) { |
456 |
buf[0]=0x0e; |
457 |
i2c_master_send(c,buf,1); |
458 |
i2c_master_recv(c,buf,1); |
459 |
dprintk("mt2032 Reg.E=0x%02x\n",buf[0]); |
460 |
lock=buf[0] &0x06; |
461 |
|
462 |
if (lock==6) |
463 |
break; |
464 |
|
465 |
dprintk("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); |
466 |
udelay(1000); |
467 |
} |
468 |
return lock; |
469 |
} |
470 |
|
471 |
static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) |
472 |
{ |
473 |
unsigned char buf[2]; |
474 |
int tad1; |
475 |
|
476 |
buf[0]=0x0f; |
477 |
i2c_master_send(c,buf,1); |
478 |
i2c_master_recv(c,buf,1); |
479 |
dprintk("mt2032 Reg.F=0x%02x\n",buf[0]); |
480 |
tad1=buf[0]&0x07; |
481 |
|
482 |
if(tad1 ==0) return lock; |
483 |
if(tad1 ==1) return lock; |
484 |
|
485 |
if(tad1==2) { |
486 |
if(sel==0) |
487 |
return lock; |
488 |
else sel--; |
489 |
} |
490 |
else { |
491 |
if(sel<4) |
492 |
sel++; |
493 |
else |
494 |
return lock; |
495 |
} |
496 |
|
497 |
dprintk("mt2032 optimize_vco: sel=%d\n",sel); |
498 |
|
499 |
buf[0]=0x0f; |
500 |
buf[1]=sel; |
501 |
i2c_master_send(c,buf,2); |
502 |
lock=mt2032_check_lo_lock(c); |
503 |
return lock; |
504 |
} |
505 |
|
506 |
|
507 |
static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, |
508 |
unsigned int if1, unsigned int if2, |
509 |
unsigned int from, unsigned int to) |
510 |
{ |
511 |
unsigned char buf[21]; |
512 |
int lint_try,ret,sel,lock=0; |
513 |
struct tuner *t = i2c_get_clientdata(c); |
514 |
|
515 |
dprintk("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",rfin,if1,if2,from,to); |
516 |
|
517 |
buf[0]=0; |
518 |
ret=i2c_master_send(c,buf,1); |
519 |
i2c_master_recv(c,buf,21); |
520 |
|
521 |
buf[0]=0; |
522 |
ret=mt2032_compute_freq(rfin,if1,if2,from,to,&buf[1],&sel,t->xogc); |
523 |
if (ret<0) |
524 |
return; |
525 |
|
526 |
// send only the relevant registers per Rev. 1.2 |
527 |
buf[0]=0; |
528 |
ret=i2c_master_send(c,buf,4); |
529 |
buf[5]=5; |
530 |
ret=i2c_master_send(c,buf+5,4); |
531 |
buf[11]=11; |
532 |
ret=i2c_master_send(c,buf+11,3); |
533 |
if(ret!=3) |
534 |
printk("mt2032_set_if_freq failed with %d\n",ret); |
535 |
|
536 |
// wait for PLLs to lock (per manual), retry LINT if not. |
537 |
for(lint_try=0; lint_try<2; lint_try++) { |
538 |
lock=mt2032_check_lo_lock(c); |
539 |
|
540 |
if(optimize_vco) |
541 |
lock=mt2032_optimize_vco(c,sel,lock); |
542 |
if(lock==6) break; |
543 |
|
544 |
printk("mt2032: re-init PLLs by LINT\n"); |
545 |
buf[0]=7; |
546 |
buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs |
547 |
i2c_master_send(c,buf,2); |
548 |
mdelay(10); |
549 |
buf[1]=8+t->xogc; |
550 |
i2c_master_send(c,buf,2); |
551 |
} |
552 |
|
553 |
if (lock!=6) |
554 |
printk("MT2032 Fatal Error: PLLs didn't lock.\n"); |
555 |
|
556 |
buf[0]=2; |
557 |
buf[1]=0x20; // LOGC for optimal phase noise |
558 |
ret=i2c_master_send(c,buf,2); |
559 |
if (ret!=2) |
560 |
printk("mt2032_set_if_freq2 failed with %d\n",ret); |
561 |
} |
562 |
|
563 |
|
564 |
static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) |
565 |
{ |
566 |
struct tuner *t = i2c_get_clientdata(c); |
567 |
int if2,from,to; |
568 |
|
569 |
// signal bandwidth and picture carrier |
570 |
if (t->std & V4L2_STD_525_60) { |
571 |
// NTSC |
572 |
from = 40750*1000; |
573 |
to = 46750*1000; |
574 |
if2 = 45750*1000; |
575 |
} else { |
576 |
// PAL |
577 |
from = 32900*1000; |
578 |
to = 39900*1000; |
579 |
if2 = 38900*1000; |
580 |
} |
581 |
|
582 |
mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, |
583 |
1090*1000*1000, if2, from, to); |
584 |
} |
585 |
|
586 |
static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) |
587 |
{ |
588 |
struct tuner *t = i2c_get_clientdata(c); |
589 |
int if2 = t->radio_if2; |
590 |
|
591 |
// per Manual for FM tuning: first if center freq. 1085 MHz |
592 |
mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, |
593 |
1085*1000*1000,if2,if2,if2); |
594 |
} |
595 |
|
596 |
// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 |
597 |
static int mt2032_init(struct i2c_client *c) |
598 |
{ |
599 |
struct tuner *t = i2c_get_clientdata(c); |
600 |
unsigned char buf[21]; |
601 |
int ret,xogc,xok=0; |
602 |
|
603 |
// Initialize Registers per spec. |
604 |
buf[1]=2; // Index to register 2 |
605 |
buf[2]=0xff; |
606 |
buf[3]=0x0f; |
607 |
buf[4]=0x1f; |
608 |
ret=i2c_master_send(c,buf+1,4); |
609 |
|
610 |
buf[5]=6; // Index register 6 |
611 |
buf[6]=0xe4; |
612 |
buf[7]=0x8f; |
613 |
buf[8]=0xc3; |
614 |
buf[9]=0x4e; |
615 |
buf[10]=0xec; |
616 |
ret=i2c_master_send(c,buf+5,6); |
617 |
|
618 |
buf[12]=13; // Index register 13 |
619 |
buf[13]=0x32; |
620 |
ret=i2c_master_send(c,buf+12,2); |
621 |
|
622 |
// Adjust XOGC (register 7), wait for XOK |
623 |
xogc=7; |
624 |
do { |
625 |
dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); |
626 |
mdelay(10); |
627 |
buf[0]=0x0e; |
628 |
i2c_master_send(c,buf,1); |
629 |
i2c_master_recv(c,buf,1); |
630 |
xok=buf[0]&0x01; |
631 |
dprintk("mt2032: xok = 0x%02x\n",xok); |
632 |
if (xok == 1) break; |
633 |
|
634 |
xogc--; |
635 |
dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); |
636 |
if (xogc == 3) { |
637 |
xogc=4; // min. 4 per spec |
638 |
break; |
639 |
} |
640 |
buf[0]=0x07; |
641 |
buf[1]=0x88 + xogc; |
642 |
ret=i2c_master_send(c,buf,2); |
643 |
if (ret!=2) |
644 |
printk("mt2032_init failed with %d\n",ret); |
645 |
} while (xok != 1 ); |
646 |
t->xogc=xogc; |
647 |
|
648 |
t->tv_freq = mt2032_set_tv_freq; |
649 |
t->radio_freq = mt2032_set_radio_freq; |
650 |
return(1); |
651 |
} |
652 |
|
653 |
static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) |
654 |
{ |
655 |
unsigned char buf[2]; |
656 |
int ret; |
657 |
|
658 |
buf[0] = 6; |
659 |
buf[1] = antenna ? 0x11 : 0x10; |
660 |
ret=i2c_master_send(c,buf,2); |
661 |
dprintk("mt2050: enabled antenna connector %d\n", antenna); |
662 |
} |
663 |
|
664 |
static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) |
665 |
{ |
666 |
unsigned int if1=1218*1000*1000; |
667 |
unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; |
668 |
int ret; |
669 |
unsigned char buf[6]; |
670 |
|
671 |
dprintk("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", |
672 |
freq,if1,if2); |
673 |
|
674 |
f_lo1=freq+if1; |
675 |
f_lo1=(f_lo1/1000000)*1000000; |
676 |
|
677 |
f_lo2=f_lo1-freq-if2; |
678 |
f_lo2=(f_lo2/50000)*50000; |
679 |
|
680 |
lo1=f_lo1/4000000; |
681 |
lo2=f_lo2/4000000; |
682 |
|
683 |
f_lo1_modulo= f_lo1-(lo1*4000000); |
684 |
f_lo2_modulo= f_lo2-(lo2*4000000); |
685 |
|
686 |
num1=4*f_lo1_modulo/4000000; |
687 |
num2=4096*(f_lo2_modulo/1000)/4000; |
688 |
|
689 |
// todo spurchecks |
690 |
|
691 |
div1a=(lo1/12)-1; |
692 |
div1b=lo1-(div1a+1)*12; |
693 |
|
694 |
div2a=(lo2/8)-1; |
695 |
div2b=lo2-(div2a+1)*8; |
696 |
|
697 |
if (debug > 1) { |
698 |
printk("lo1 lo2 = %d %d\n", lo1, lo2); |
699 |
printk("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",num1,num2,div1a,div1b,div2a,div2b); |
700 |
} |
701 |
|
702 |
buf[0]=1; |
703 |
buf[1]= 4*div1b + num1; |
704 |
if(freq<275*1000*1000) buf[1] = buf[1]|0x80; |
705 |
|
706 |
buf[2]=div1a; |
707 |
buf[3]=32*div2b + num2/256; |
708 |
buf[4]=num2-(num2/256)*256; |
709 |
buf[5]=div2a; |
710 |
if(num2!=0) buf[5]=buf[5]|0x40; |
711 |
|
712 |
if (debug > 1) { |
713 |
int i; |
714 |
printk("bufs is: "); |
715 |
for(i=0;i<6;i++) |
716 |
printk("%x ",buf[i]); |
717 |
printk("\n"); |
718 |
} |
719 |
|
720 |
ret=i2c_master_send(c,buf,6); |
721 |
if (ret!=6) |
722 |
printk("mt2050_set_if_freq failed with %d\n",ret); |
723 |
} |
724 |
|
725 |
static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) |
726 |
{ |
727 |
struct tuner *t = i2c_get_clientdata(c); |
728 |
unsigned int if2; |
729 |
|
730 |
if (t->std & V4L2_STD_525_60) { |
731 |
// NTSC |
732 |
if2 = 45750*1000; |
733 |
} else { |
734 |
// PAL |
735 |
if2 = 38900*1000; |
736 |
} |
737 |
if (V4L2_TUNER_DIGITAL_TV == t->mode) { |
738 |
// testing for DVB ... |
739 |
if2 = 36150*1000; |
740 |
} |
741 |
mt2050_set_if_freq(c, freq*62500, if2); |
742 |
mt2050_set_antenna(c, tv_antenna); |
743 |
} |
744 |
|
745 |
static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) |
746 |
{ |
747 |
struct tuner *t = i2c_get_clientdata(c); |
748 |
int if2 = t->radio_if2; |
749 |
|
750 |
mt2050_set_if_freq(c, freq*62500, if2); |
751 |
mt2050_set_antenna(c, radio_antenna); |
752 |
} |
753 |
|
754 |
static int mt2050_init(struct i2c_client *c) |
755 |
{ |
756 |
struct tuner *t = i2c_get_clientdata(c); |
757 |
unsigned char buf[2]; |
758 |
int ret; |
759 |
|
760 |
buf[0]=6; |
761 |
buf[1]=0x10; |
762 |
ret=i2c_master_send(c,buf,2); // power |
763 |
|
764 |
buf[0]=0x0f; |
765 |
buf[1]=0x0f; |
766 |
ret=i2c_master_send(c,buf,2); // m1lo |
767 |
|
768 |
buf[0]=0x0d; |
769 |
ret=i2c_master_send(c,buf,1); |
770 |
i2c_master_recv(c,buf,1); |
771 |
|
772 |
dprintk("mt2050: sro is %x\n",buf[0]); |
773 |
t->tv_freq = mt2050_set_tv_freq; |
774 |
t->radio_freq = mt2050_set_radio_freq; |
775 |
return 0; |
776 |
} |
777 |
|
778 |
static int microtune_init(struct i2c_client *c) |
779 |
{ |
780 |
struct tuner *t = i2c_get_clientdata(c); |
781 |
char *name; |
782 |
unsigned char buf[21]; |
783 |
int company_code; |
784 |
|
785 |
memset(buf,0,sizeof(buf)); |
786 |
t->tv_freq = NULL; |
787 |
t->radio_freq = NULL; |
788 |
name = "unknown"; |
789 |
|
790 |
i2c_master_send(c,buf,1); |
791 |
i2c_master_recv(c,buf,21); |
792 |
if(debug) { |
793 |
int i; |
794 |
printk(KERN_DEBUG "tuner: MT2032 hexdump:\n"); |
795 |
for(i=0;i<21;i++) { |
796 |
printk(" %02x",buf[i]); |
797 |
if(((i+1)%8)==0) printk(" "); |
798 |
if(((i+1)%16)==0) printk("\n "); |
799 |
} |
800 |
printk("\n "); |
801 |
} |
802 |
company_code = buf[0x11] << 8 | buf[0x12]; |
803 |
printk("tuner: microtune: companycode=%04x part=%02x rev=%02x\n", |
804 |
company_code,buf[0x13],buf[0x14]); |
805 |
|
806 |
#if 0 |
807 |
/* seems to cause more problems than it solves ... */ |
808 |
switch (company_code) { |
809 |
case 0x30bf: |
810 |
case 0x3cbf: |
811 |
case 0x3dbf: |
812 |
case 0x4d54: |
813 |
case 0x8e81: |
814 |
case 0x8e91: |
815 |
/* ok (?) */ |
816 |
break; |
817 |
default: |
818 |
printk("tuner: microtune: unknown companycode\n"); |
819 |
return 0; |
820 |
} |
821 |
#endif |
822 |
|
823 |
if (buf[0x13] < ARRAY_SIZE(microtune_part) && |
824 |
NULL != microtune_part[buf[0x13]]) |
825 |
name = microtune_part[buf[0x13]]; |
826 |
switch (buf[0x13]) { |
827 |
case MT2032: |
828 |
mt2032_init(c); |
829 |
break; |
830 |
case MT2050: |
831 |
mt2050_init(c); |
832 |
break; |
833 |
default: |
834 |
printk("tuner: microtune %s found, not (yet?) supported, sorry :-/\n", |
835 |
name); |
836 |
return 0; |
837 |
} |
838 |
printk("tuner: microtune %s found, OK\n",name); |
839 |
return 0; |
840 |
} |
841 |
|
842 |
/* ---------------------------------------------------------------------- */ |
843 |
|
844 |
static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) |
845 |
{ |
846 |
struct tuner *t = i2c_get_clientdata(c); |
847 |
u8 config; |
848 |
u16 div; |
849 |
struct tunertype *tun; |
850 |
unsigned char buffer[4]; |
851 |
int rc; |
852 |
|
853 |
tun = &tuners[t->type]; |
854 |
if (freq < tun->thresh1) { |
855 |
config = tun->VHF_L; |
856 |
dprintk("tv: VHF lowrange\n"); |
857 |
} else if (freq < tun->thresh2) { |
858 |
config = tun->VHF_H; |
859 |
dprintk("tv: VHF high range\n"); |
860 |
} else { |
861 |
config = tun->UHF; |
862 |
dprintk("tv: UHF range\n"); |
863 |
} |
864 |
|
865 |
|
866 |
/* tv norm specific stuff for multi-norm tuners */ |
867 |
switch (t->type) { |
868 |
case TUNER_PHILIPS_SECAM: // FI1216MF |
869 |
/* 0x01 -> ??? no change ??? */ |
870 |
/* 0x02 -> PAL BDGHI / SECAM L */ |
871 |
/* 0x04 -> ??? PAL others / SECAM others ??? */ |
872 |
config &= ~0x02; |
873 |
if (t->std & V4L2_STD_SECAM) |
874 |
config |= 0x02; |
875 |
break; |
876 |
|
877 |
case TUNER_TEMIC_4046FM5: |
878 |
config &= ~0x0f; |
879 |
|
880 |
if (t->std & V4L2_STD_PAL_BG) { |
881 |
config |= TEMIC_SET_PAL_BG; |
882 |
|
883 |
} else if (t->std & V4L2_STD_PAL_I) { |
884 |
config |= TEMIC_SET_PAL_I; |
885 |
|
886 |
} else if (t->std & V4L2_STD_PAL_DK) { |
887 |
config |= TEMIC_SET_PAL_DK; |
888 |
|
889 |
} else if (t->std & V4L2_STD_SECAM_L) { |
890 |
config |= TEMIC_SET_PAL_L; |
891 |
|
892 |
} |
893 |
break; |
894 |
|
895 |
case TUNER_PHILIPS_FQ1216ME: |
896 |
config &= ~0x0f; |
897 |
|
898 |
if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { |
899 |
config |= PHILIPS_SET_PAL_BGDK; |
900 |
|
901 |
} else if (t->std & V4L2_STD_PAL_I) { |
902 |
config |= PHILIPS_SET_PAL_I; |
903 |
|
904 |
} else if (t->std & V4L2_STD_SECAM_L) { |
905 |
config |= PHILIPS_SET_PAL_L; |
906 |
|
907 |
} |
908 |
break; |
909 |
|
910 |
case TUNER_PHILIPS_ATSC: |
911 |
/* 0x00 -> ATSC antenna input 1 */ |
912 |
/* 0x01 -> ATSC antenna input 2 */ |
913 |
/* 0x02 -> NTSC antenna input 1 */ |
914 |
/* 0x03 -> NTSC antenna input 2 */ |
915 |
config &= ~0x03; |
916 |
if (!(t->std & V4L2_STD_ATSC)) |
917 |
config |= 2; |
918 |
/* FIXME: input */ |
919 |
break; |
920 |
|
921 |
case TUNER_MICROTUNE_4042FI5: |
922 |
/* Set the charge pump for fast tuning */ |
923 |
tun->config |= 0x40; |
924 |
break; |
925 |
} |
926 |
|
927 |
/* |
928 |
* Philips FI1216MK2 remark from specification : |
929 |
* for channel selection involving band switching, and to ensure |
930 |
* smooth tuning to the desired channel without causing |
931 |
* unnecessary charge pump action, it is recommended to consider |
932 |
* the difference between wanted channel frequency and the |
933 |
* current channel frequency. Unnecessary charge pump action |
934 |
* will result in very low tuning voltage which may drive the |
935 |
* oscillator to extreme conditions. |
936 |
* |
937 |
* Progfou: specification says to send config data before |
938 |
* frequency in case (wanted frequency < current frequency). |
939 |
*/ |
940 |
|
941 |
div=freq + tun->IFPCoff; |
942 |
if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { |
943 |
buffer[0] = tun->config; |
944 |
buffer[1] = config; |
945 |
buffer[2] = (div>>8) & 0x7f; |
946 |
buffer[3] = div & 0xff; |
947 |
} else { |
948 |
buffer[0] = (div>>8) & 0x7f; |
949 |
buffer[1] = div & 0xff; |
950 |
buffer[2] = tun->config; |
951 |
buffer[3] = config; |
952 |
} |
953 |
dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n", |
954 |
buffer[0],buffer[1],buffer[2],buffer[3]); |
955 |
|
956 |
if (4 != (rc = i2c_master_send(c,buffer,4))) |
957 |
printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); |
958 |
|
959 |
if (t->type == TUNER_MICROTUNE_4042FI5) { |
960 |
// FIXME - this may also work for other tuners |
961 |
unsigned long timeout = jiffies + msecs_to_jiffies(1); |
962 |
u8 status_byte = 0; |
963 |
|
964 |
/* Wait until the PLL locks */ |
965 |
for (;;) { |
966 |
if (time_after(jiffies,timeout)) |
967 |
return; |
968 |
if (1 != (rc = i2c_master_recv(c,&status_byte,1))) { |
969 |
dprintk("tuner: i2c i/o read error: rc == %d (should be 1)\n",rc); |
970 |
break; |
971 |
} |
972 |
/* bit 6 is PLL locked indicator */ |
973 |
if (status_byte & 0x40) |
974 |
break; |
975 |
udelay(10); |
976 |
} |
977 |
|
978 |
/* Set the charge pump for optimized phase noise figure */ |
979 |
tun->config &= ~0x40; |
980 |
buffer[0] = (div>>8) & 0x7f; |
981 |
buffer[1] = div & 0xff; |
982 |
buffer[2] = tun->config; |
983 |
buffer[3] = config; |
984 |
dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n", |
985 |
buffer[0],buffer[1],buffer[2],buffer[3]); |
986 |
|
987 |
if (4 != (rc = i2c_master_send(c,buffer,4))) |
988 |
dprintk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); |
989 |
} |
990 |
} |
991 |
|
992 |
static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) |
993 |
{ |
994 |
struct tunertype *tun; |
995 |
struct tuner *t = i2c_get_clientdata(c); |
996 |
unsigned char buffer[4]; |
997 |
unsigned div; |
998 |
int rc; |
999 |
|
1000 |
tun=&tuners[t->type]; |
1001 |
div = freq + (int)(16*10.7); |
1002 |
buffer[2] = tun->config; |
1003 |
|
1004 |
switch (t->type) { |
1005 |
case TUNER_PHILIPS_FM1216ME_MK3: |
1006 |
case TUNER_PHILIPS_FM1236_MK3: |
1007 |
buffer[3] = 0x19; |
1008 |
break; |
1009 |
case TUNER_PHILIPS_FM1256_IH3: |
1010 |
div = (20 * freq)/16 + 333 * 2; |
1011 |
buffer[2] = 0x80; |
1012 |
buffer[3] = 0x19; |
1013 |
break; |
1014 |
case TUNER_LG_PAL_FM: |
1015 |
buffer[3] = 0xa5; |
1016 |
break; |
1017 |
default: |
1018 |
buffer[3] = 0xa4; |
1019 |
break; |
1020 |
} |
1021 |
buffer[0] = (div>>8) & 0x7f; |
1022 |
buffer[1] = div & 0xff; |
1023 |
|
1024 |
dprintk("tuner: radio 0x%02x 0x%02x 0x%02x 0x%02x\n", |
1025 |
buffer[0],buffer[1],buffer[2],buffer[3]); |
1026 |
|
1027 |
if (4 != (rc = i2c_master_send(c,buffer,4))) |
1028 |
printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); |
1029 |
} |
1030 |
|
1031 |
/* ---------------------------------------------------------------------- */ |
1032 |
|
1033 |
// Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz |
1034 |
static void set_tv_freq(struct i2c_client *c, unsigned int freq) |
1035 |
{ |
1036 |
struct tuner *t = i2c_get_clientdata(c); |
1037 |
|
1038 |
if (t->type == UNSET) { |
1039 |
printk("tuner: tuner type not set\n"); |
1040 |
return; |
1041 |
} |
1042 |
if (NULL == t->tv_freq) { |
1043 |
printk("tuner: Huh? tv_set is NULL?\n"); |
1044 |
return; |
1045 |
} |
1046 |
if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { |
1047 |
/* FIXME: better do that chip-specific, but |
1048 |
right now we don't have that in the config |
1049 |
struct and this way is still better than no |
1050 |
check at all */ |
1051 |
printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n", |
1052 |
freq/16,freq%16*100/16,tv_range[0],tv_range[1]); |
1053 |
return; |
1054 |
} |
1055 |
t->tv_freq(c,freq); |
1056 |
} |
1057 |
|
1058 |
static void set_radio_freq(struct i2c_client *c, unsigned int freq) |
1059 |
{ |
1060 |
struct tuner *t = i2c_get_clientdata(c); |
1061 |
|
1062 |
if (t->type == UNSET) { |
1063 |
printk("tuner: tuner type not set\n"); |
1064 |
return; |
1065 |
} |
1066 |
if (NULL == t->radio_freq) { |
1067 |
printk("tuner: no radio tuning for this one, sorry.\n"); |
1068 |
return; |
1069 |
} |
1070 |
if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { |
1071 |
printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n", |
1072 |
freq/16,freq%16*100/16, |
1073 |
radio_range[0],radio_range[1]); |
1074 |
return; |
1075 |
} |
1076 |
t->radio_freq(c,freq); |
1077 |
} |
1078 |
|
1079 |
static void set_freq(struct i2c_client *c, unsigned long freq) |
1080 |
{ |
1081 |
struct tuner *t = i2c_get_clientdata(c); |
1082 |
|
1083 |
switch (t->mode) { |
1084 |
case V4L2_TUNER_RADIO: |
1085 |
dprintk("tuner: radio freq set to %lu.%02lu\n", |
1086 |
freq/16,freq%16*100/16); |
1087 |
set_radio_freq(c,freq); |
1088 |
break; |
1089 |
case V4L2_TUNER_ANALOG_TV: |
1090 |
case V4L2_TUNER_DIGITAL_TV: |
1091 |
dprintk("tuner: tv freq set to %lu.%02lu\n", |
1092 |
freq/16,freq%16*100/16); |
1093 |
set_tv_freq(c, freq); |
1094 |
break; |
1095 |
} |
1096 |
t->freq = freq; |
1097 |
} |
1098 |
|
1099 |
static void set_type(struct i2c_client *c, unsigned int type, char *source) |
1100 |
{ |
1101 |
struct tuner *t = i2c_get_clientdata(c); |
1102 |
|
1103 |
if (t->type != UNSET && t->type != TUNER_ABSENT) { |
1104 |
if (t->type != type) |
1105 |
printk("tuner: type already set to %d, " |
1106 |
"ignoring request for %d\n", t->type, type); |
1107 |
return; |
1108 |
} |
1109 |
if (type >= TUNERS) |
1110 |
return; |
1111 |
|
1112 |
t->type = type; |
1113 |
printk("tuner: type set to %d (%s) by %s\n", |
1114 |
t->type,tuners[t->type].name, source); |
1115 |
strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); |
1116 |
|
1117 |
switch (t->type) { |
1118 |
case TUNER_MT2032: |
1119 |
microtune_init(c); |
1120 |
break; |
1121 |
default: |
1122 |
t->tv_freq = default_set_tv_freq; |
1123 |
t->radio_freq = default_set_radio_freq; |
1124 |
break; |
1125 |
} |
1126 |
} |
1127 |
|
1128 |
static char pal[] = "-"; |
1129 |
module_param_string(pal, pal, 0644, sizeof(pal)); |
1130 |
|
1131 |
static int tuner_fixup_std(struct tuner *t) |
1132 |
{ |
1133 |
if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { |
1134 |
/* get more precise norm info from insmod option */ |
1135 |
switch (pal[0]) { |
1136 |
case 'b': |
1137 |
case 'B': |
1138 |
case 'g': |
1139 |
case 'G': |
1140 |
dprintk("insmod fixup: PAL => PAL-BG\n"); |
1141 |
t->std = V4L2_STD_PAL_BG; |
1142 |
break; |
1143 |
case 'i': |
1144 |
case 'I': |
1145 |
dprintk("insmod fixup: PAL => PAL-I\n"); |
1146 |
t->std = V4L2_STD_PAL_I; |
1147 |
break; |
1148 |
case 'd': |
1149 |
case 'D': |
1150 |
case 'k': |
1151 |
case 'K': |
1152 |
dprintk("insmod fixup: PAL => PAL-DK\n"); |
1153 |
t->std = V4L2_STD_PAL_DK; |
1154 |
break; |
1155 |
} |
1156 |
} |
1157 |
return 0; |
1158 |
} |
1159 |
|
1160 |
/* ---------------------------------------------------------------------- */ |
1161 |
|
1162 |
static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) |
1163 |
{ |
1164 |
struct tuner *t; |
1165 |
struct i2c_client *client; |
1166 |
|
1167 |
if (this_adap > 0) |
1168 |
return -1; |
1169 |
this_adap++; |
1170 |
|
1171 |
client_template.adapter = adap; |
1172 |
client_template.addr = addr; |
1173 |
|
1174 |
printk("tuner: chip found at addr 0x%x i2c-bus %s\n", |
1175 |
addr<<1, adap->name); |
1176 |
|
1177 |
if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) |
1178 |
return -ENOMEM; |
1179 |
memcpy(client,&client_template,sizeof(struct i2c_client)); |
1180 |
t = kmalloc(sizeof(struct tuner),GFP_KERNEL); |
1181 |
if (NULL == t) { |
1182 |
kfree(client); |
1183 |
return -ENOMEM; |
1184 |
} |
1185 |
memset(t,0,sizeof(struct tuner)); |
1186 |
i2c_set_clientdata(client, t); |
1187 |
t->type = UNSET; |
1188 |
t->radio_if2 = 10700*1000; // 10.7MHz - FM radio |
1189 |
|
1190 |
i2c_attach_client(client); |
1191 |
if (type < TUNERS) { |
1192 |
set_type(client, type, "insmod option"); |
1193 |
printk("tuner: The type=<n> insmod option will go away soon.\n"); |
1194 |
printk("tuner: Please use the tuner=<n> option provided by\n"); |
1195 |
printk("tuner: tv aard core driver (bttv, saa7134, ...) instead.\n"); |
1196 |
} |
1197 |
return 0; |
1198 |
} |
1199 |
|
1200 |
static int tuner_probe(struct i2c_adapter *adap) |
1201 |
{ |
1202 |
if (0 != addr) { |
1203 |
normal_i2c_range[0] = addr; |
1204 |
normal_i2c_range[1] = addr; |
1205 |
} |
1206 |
this_adap = 0; |
1207 |
|
1208 |
#ifdef I2C_CLASS_TV_ANALOG |
1209 |
if (adap->class & I2C_CLASS_TV_ANALOG) |
1210 |
return i2c_probe(adap, &addr_data, tuner_attach); |
1211 |
#else |
1212 |
switch (adap->id) { |
1213 |
case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3: |
1214 |
case I2C_ALGO_BIT | I2C_HW_B_BT848: |
1215 |
case I2C_ALGO_BIT | I2C_HW_B_RIVA: |
1216 |
case I2C_ALGO_SAA7134: |
1217 |
case I2C_ALGO_SAA7146: |
1218 |
return i2c_probe(adap, &addr_data, tuner_attach); |
1219 |
break; |
1220 |
} |
1221 |
#endif |
1222 |
return 0; |
1223 |
} |
1224 |
|
1225 |
static int tuner_detach(struct i2c_client *client) |
1226 |
{ |
1227 |
struct tuner *t = i2c_get_clientdata(client); |
1228 |
|
1229 |
i2c_detach_client(client); |
1230 |
kfree(t); |
1231 |
kfree(client); |
1232 |
return 0; |
1233 |
} |
1234 |
|
1235 |
#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \ |
1236 |
printk("tuner: switching to v4l2\n"); \ |
1237 |
t->using_v4l2 = 1; |
1238 |
#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \ |
1239 |
printk("tuner: ignore v4l1 call\n"); \ |
1240 |
return 0; } |
1241 |
|
1242 |
static int |
1243 |
tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) |
1244 |
{ |
1245 |
struct tuner *t = i2c_get_clientdata(client); |
1246 |
unsigned int *iarg = (int*)arg; |
1247 |
|
1248 |
switch (cmd) { |
1249 |
|
1250 |
/* --- configuration --- */ |
1251 |
case TUNER_SET_TYPE: |
1252 |
set_type(client,*iarg,client->adapter->name); |
1253 |
break; |
1254 |
case AUDC_SET_RADIO: |
1255 |
if (V4L2_TUNER_RADIO != t->mode) { |
1256 |
set_tv_freq(client,400 * 16); |
1257 |
t->mode = V4L2_TUNER_RADIO; |
1258 |
} |
1259 |
break; |
1260 |
case AUDC_CONFIG_PINNACLE: |
1261 |
switch (*iarg) { |
1262 |
case 2: |
1263 |
dprintk("tuner: pinnacle pal\n"); |
1264 |
t->radio_if2 = 33300 * 1000; |
1265 |
break; |
1266 |
case 3: |
1267 |
dprintk("tuner: pinnacle ntsc\n"); |
1268 |
t->radio_if2 = 41300 * 1000; |
1269 |
break; |
1270 |
} |
1271 |
break; |
1272 |
|
1273 |
/* --- v4l ioctls --- */ |
1274 |
/* take care: bttv does userspace copying, we'll get a |
1275 |
kernel pointer here... */ |
1276 |
case VIDIOCSCHAN: |
1277 |
{ |
1278 |
static const v4l2_std_id map[] = { |
1279 |
[ VIDEO_MODE_PAL ] = V4L2_STD_PAL, |
1280 |
[ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M, |
1281 |
[ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM, |
1282 |
[ 4 /* bttv */ ] = V4L2_STD_PAL_M, |
1283 |
[ 5 /* bttv */ ] = V4L2_STD_PAL_N, |
1284 |
[ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, |
1285 |
}; |
1286 |
struct video_channel *vc = arg; |
1287 |
|
1288 |
CHECK_V4L2; |
1289 |
t->mode = V4L2_TUNER_ANALOG_TV; |
1290 |
if (vc->norm < ARRAY_SIZE(map)) |
1291 |
t->std = map[vc->norm]; |
1292 |
tuner_fixup_std(t); |
1293 |
if (t->freq) |
1294 |
set_tv_freq(client,t->freq); |
1295 |
return 0; |
1296 |
} |
1297 |
case VIDIOCSFREQ: |
1298 |
{ |
1299 |
unsigned long *v = arg; |
1300 |
|
1301 |
CHECK_V4L2; |
1302 |
set_freq(client,*v); |
1303 |
return 0; |
1304 |
} |
1305 |
case VIDIOCGTUNER: |
1306 |
{ |
1307 |
struct video_tuner *vt = arg; |
1308 |
|
1309 |
CHECK_V4L2; |
1310 |
if (V4L2_TUNER_RADIO == t->mode) |
1311 |
vt->signal = tuner_signal(client); |
1312 |
return 0; |
1313 |
} |
1314 |
case VIDIOCGAUDIO: |
1315 |
{ |
1316 |
struct video_audio *va = arg; |
1317 |
|
1318 |
CHECK_V4L2; |
1319 |
if (V4L2_TUNER_RADIO == t->mode) |
1320 |
va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO); |
1321 |
return 0; |
1322 |
} |
1323 |
|
1324 |
case VIDIOC_S_STD: |
1325 |
{ |
1326 |
v4l2_std_id *id = arg; |
1327 |
|
1328 |
SWITCH_V4L2; |
1329 |
t->mode = V4L2_TUNER_ANALOG_TV; |
1330 |
t->std = *id; |
1331 |
tuner_fixup_std(t); |
1332 |
if (t->freq) |
1333 |
set_freq(client,t->freq); |
1334 |
break; |
1335 |
} |
1336 |
case VIDIOC_S_FREQUENCY: |
1337 |
{ |
1338 |
struct v4l2_frequency *f = arg; |
1339 |
|
1340 |
SWITCH_V4L2; |
1341 |
if (V4L2_TUNER_RADIO == f->type && |
1342 |
V4L2_TUNER_RADIO != t->mode) |
1343 |
set_tv_freq(client,400*16); |
1344 |
t->mode = f->type; |
1345 |
t->freq = f->frequency; |
1346 |
set_freq(client,t->freq); |
1347 |
break; |
1348 |
} |
1349 |
case VIDIOC_G_TUNER: |
1350 |
{ |
1351 |
struct v4l2_tuner *tuner = arg; |
1352 |
|
1353 |
SWITCH_V4L2; |
1354 |
if (V4L2_TUNER_RADIO == t->mode) |
1355 |
tuner->signal = tuner_signal(client); |
1356 |
break; |
1357 |
} |
1358 |
default: |
1359 |
/* nothing */ |
1360 |
break; |
1361 |
} |
1362 |
|
1363 |
return 0; |
1364 |
} |
1365 |
|
1366 |
static int tuner_suspend(struct device * dev, u32 state, u32 level) |
1367 |
{ |
1368 |
dprintk("tuner: suspend\n"); |
1369 |
/* FIXME: power down ??? */ |
1370 |
return 0; |
1371 |
} |
1372 |
|
1373 |
static int tuner_resume(struct device * dev, u32 level) |
1374 |
{ |
1375 |
struct i2c_client *c = container_of(dev, struct i2c_client, dev); |
1376 |
struct tuner *t = i2c_get_clientdata(c); |
1377 |
|
1378 |
dprintk("tuner: resume\n"); |
1379 |
if (t->freq) |
1380 |
set_freq(c,t->freq); |
1381 |
return 0; |
1382 |
} |
1383 |
|
1384 |
/* ----------------------------------------------------------------------- */ |
1385 |
|
1386 |
static struct i2c_driver driver = { |
1387 |
.owner = THIS_MODULE, |
1388 |
.name = "i2c TV tuner driver", |
1389 |
.id = I2C_DRIVERID_TUNER, |
1390 |
.flags = I2C_DF_NOTIFY, |
1391 |
.attach_adapter = tuner_probe, |
1392 |
.detach_client = tuner_detach, |
1393 |
.command = tuner_command, |
1394 |
.driver = { |
1395 |
.suspend = tuner_suspend, |
1396 |
.resume = tuner_resume, |
1397 |
}, |
1398 |
}; |
1399 |
static struct i2c_client client_template = |
1400 |
{ |
1401 |
I2C_DEVNAME("(tuner unset)"), |
1402 |
.flags = I2C_CLIENT_ALLOW_USE, |
1403 |
.driver = &driver, |
1404 |
}; |
1405 |
|
1406 |
static int __init tuner_init_module(void) |
1407 |
{ |
1408 |
return i2c_add_driver(&driver); |
1409 |
} |
1410 |
|
1411 |
static void __exit tuner_cleanup_module(void) |
1412 |
{ |
1413 |
i2c_del_driver(&driver); |
1414 |
} |
1415 |
|
1416 |
module_init(tuner_init_module); |
1417 |
module_exit(tuner_cleanup_module); |
1418 |
|
1419 |
/* |
1420 |
* Overrides for Emacs so that we follow Linus's tabbing style. |
1421 |
* --------------------------------------------------------------------------- |
1422 |
* Local variables: |
1423 |
* c-basic-offset: 8 |
1424 |
* End: |
1425 |
*/ |