Rev 425 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
425 | giacomo | 1 | #include <linux/module.h> |
2 | #include <linux/kernel.h> |
||
3 | #include <linux/sched.h> |
||
4 | #include <linux/string.h> |
||
5 | #include <linux/timer.h> |
||
6 | #include <linux/delay.h> |
||
7 | #include <linux/errno.h> |
||
8 | #include <linux/slab.h> |
||
9 | #include <linux/poll.h> |
||
10 | #include <linux/i2c.h> |
||
11 | #include <linux/types.h> |
||
12 | #include <linux/videodev.h> |
||
13 | #include <linux/init.h> |
||
14 | |||
15 | #include <media/tuner.h> |
||
16 | #include <media/audiochip.h> |
||
17 | |||
18 | /* Addresses to scan */ |
||
19 | static unsigned short normal_i2c[] = {I2C_CLIENT_END}; |
||
20 | static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END}; |
||
21 | I2C_CLIENT_INSMOD; |
||
22 | |||
23 | /* insmod options */ |
||
24 | static int debug = 0; |
||
25 | static int type = -1; |
||
26 | static int addr = 0; |
||
27 | static char *pal = "b"; |
||
28 | static int tv_range[2] = { 44, 958 }; |
||
29 | static int radio_range[2] = { 65, 108 }; |
||
30 | MODULE_PARM(debug,"i"); |
||
31 | MODULE_PARM(type,"i"); |
||
32 | MODULE_PARM(addr,"i"); |
||
33 | MODULE_PARM(tv_range,"2i"); |
||
34 | MODULE_PARM(radio_range,"2i"); |
||
35 | MODULE_PARM(pal,"s"); |
||
36 | |||
37 | #define optimize_vco 1 |
||
38 | |||
39 | MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); |
||
40 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); |
||
41 | MODULE_LICENSE("GPL"); |
||
42 | |||
43 | static int this_adap; |
||
44 | #define dprintk if (debug) printk |
||
45 | |||
46 | struct tuner |
||
47 | { |
||
48 | int type; /* chip type */ |
||
49 | int freq; /* keep track of the current settings */ |
||
50 | int std; |
||
51 | |||
52 | int radio; |
||
53 | int mode; /* current norm for multi-norm tuners */ |
||
54 | int xogc; // only for MT2032 |
||
55 | }; |
||
56 | |||
57 | static struct i2c_driver driver; |
||
58 | static struct i2c_client client_template; |
||
59 | |||
60 | /* ---------------------------------------------------------------------- */ |
||
61 | |||
62 | /* tv standard selection for Temic 4046 FM5 |
||
63 | this value takes the low bits of control byte 2 |
||
64 | from datasheet Rev.01, Feb.00 |
||
65 | standard BG I L L2 D |
||
66 | picture IF 38.9 38.9 38.9 33.95 38.9 |
||
67 | sound 1 33.4 32.9 32.4 40.45 32.4 |
||
68 | sound 2 33.16 |
||
69 | NICAM 33.05 32.348 33.05 33.05 |
||
70 | */ |
||
71 | #define TEMIC_SET_PAL_I 0x05 |
||
72 | #define TEMIC_SET_PAL_DK 0x09 |
||
73 | #define TEMIC_SET_PAL_L 0x0a // SECAM ? |
||
74 | #define TEMIC_SET_PAL_L2 0x0b // change IF ! |
||
75 | #define TEMIC_SET_PAL_BG 0x0c |
||
76 | |||
77 | /* tv tuner system standard selection for Philips FQ1216ME |
||
78 | this value takes the low bits of control byte 2 |
||
79 | from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") |
||
80 | standard BG DK I L L` |
||
81 | picture carrier 38.90 38.90 38.90 38.90 33.95 |
||
82 | colour 34.47 34.47 34.47 34.47 38.38 |
||
83 | sound 1 33.40 32.40 32.90 32.40 40.45 |
||
84 | sound 2 33.16 - - - - |
||
85 | NICAM 33.05 33.05 32.35 33.05 39.80 |
||
86 | */ |
||
87 | #define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ |
||
88 | #define PHILIPS_SET_PAL_BGDK 0x09 |
||
89 | #define PHILIPS_SET_PAL_L2 0x0a |
||
90 | #define PHILIPS_SET_PAL_L 0x0b |
||
91 | |||
92 | /* system switching for Philips FI1216MF MK2 |
||
93 | from datasheet "1996 Jul 09", |
||
94 | standard BG L L' |
||
95 | picture carrier 38.90 38.90 33.95 |
||
96 | colour 34.47 34.37 38.38 |
||
97 | sound 1 33.40 32.40 40.45 |
||
98 | sound 2 33.16 - - |
||
99 | NICAM 33.05 33.05 39.80 |
||
100 | */ |
||
101 | #define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ |
||
102 | #define PHILIPS_MF_SET_PAL_L 0x03 // France |
||
103 | #define PHILIPS_MF_SET_PAL_L2 0x02 // L' |
||
104 | |||
105 | |||
106 | /* ---------------------------------------------------------------------- */ |
||
107 | |||
108 | struct tunertype |
||
109 | { |
||
110 | char *name; |
||
111 | unsigned char Vendor; |
||
112 | unsigned char Type; |
||
113 | |||
114 | unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ |
||
115 | unsigned short thresh2; /* band switch VHF_HI <=> UHF */ |
||
116 | unsigned char VHF_L; |
||
117 | unsigned char VHF_H; |
||
118 | unsigned char UHF; |
||
119 | unsigned char config; |
||
120 | unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, |
||
121 | 732 =16*45.75 NTSCi, |
||
122 | 940 =58.75 NTSC-Japan */ |
||
123 | }; |
||
124 | |||
125 | /* |
||
126 | * The floats in the tuner struct are computed at compile time |
||
127 | * by gcc and cast back to integers. Thus we don't violate the |
||
128 | * "no float in kernel" rule. |
||
129 | */ |
||
130 | static struct tunertype tuners[] = { |
||
131 | { "Temic PAL (4002 FH5)", TEMIC, PAL, |
||
132 | 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, |
||
133 | { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I, |
||
134 | 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, |
||
135 | { "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC, |
||
136 | 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, |
||
137 | { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM, |
||
138 | 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623}, |
||
139 | |||
140 | { "NoTuner", NoTuner, NOTUNER, |
||
141 | 0,0,0x00,0x00,0x00,0x00,0x00}, |
||
142 | { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL, |
||
143 | 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, |
||
144 | { "Temic NTSC (4032 FY5)", TEMIC, NTSC, |
||
145 | 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, |
||
146 | { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I, |
||
147 | 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, |
||
148 | |||
149 | { "Temic NTSC (4036 FY5)", TEMIC, NTSC, |
||
150 | 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, |
||
151 | { "Alps HSBH1", TEMIC, NTSC, |
||
152 | 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, |
||
153 | { "Alps TSBE1",TEMIC,PAL, |
||
154 | 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, |
||
155 | { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ |
||
156 | 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, |
||
157 | |||
158 | { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ |
||
159 | 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, |
||
160 | { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ |
||
161 | 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, |
||
162 | { "Temic PAL_BG (4006FH5)", TEMIC, PAL, |
||
163 | 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
||
164 | { "Alps TSCH6",Alps,NTSC, |
||
165 | 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732}, |
||
166 | |||
167 | { "Temic PAL_DK (4016 FY5)",TEMIC,PAL, |
||
168 | 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623}, |
||
169 | { "Philips NTSC_M (MK2)",Philips,NTSC, |
||
170 | 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, |
||
171 | { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I, |
||
172 | 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, |
||
173 | { "Temic PAL* auto (4006 FN5)", TEMIC, PAL, |
||
174 | 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, |
||
175 | |||
176 | { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, |
||
177 | 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, |
||
178 | { "Temic NTSC (4039 FR5)", TEMIC, NTSC, |
||
179 | 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, |
||
180 | { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL, |
||
181 | 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, |
||
182 | { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL, |
||
183 | 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
||
184 | |||
185 | { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, |
||
186 | 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
||
187 | { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I, |
||
188 | 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
||
189 | { "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I, |
||
190 | 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
||
191 | { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC, |
||
192 | 16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732}, |
||
193 | |||
194 | { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL, |
||
195 | 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
||
196 | { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL, |
||
197 | 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, |
||
198 | { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, |
||
199 | 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, |
||
200 | { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ |
||
201 | 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,732 }, // Corrected to NTSC=732 (was:940) |
||
202 | |||
203 | { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ |
||
204 | 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, |
||
205 | { "MT2032 universal", Microtune,PAL|NTSC, |
||
206 | 0,0,0,0,0,0,0}, |
||
207 | { "Temic PAL_BG (4106 FH5)", TEMIC, PAL, |
||
208 | 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, |
||
209 | { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL, |
||
210 | 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623}, |
||
211 | |||
212 | { "Temic NTSC (4136 FY5)", TEMIC, NTSC, |
||
213 | 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, |
||
214 | { "LG PAL (newer TAPC series)", LGINNOTEK, PAL, |
||
215 | 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623}, |
||
216 | { "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL, |
||
217 | 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, |
||
218 | { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC, |
||
219 | 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, |
||
220 | }; |
||
221 | #define TUNERS (sizeof(tuners)/sizeof(struct tunertype)) |
||
222 | |||
223 | /* ---------------------------------------------------------------------- */ |
||
224 | |||
225 | static int tuner_getstatus(struct i2c_client *c) |
||
226 | { |
||
227 | unsigned char byte; |
||
228 | |||
229 | struct tuner *t = (struct tuner*)c->data; |
||
230 | |||
231 | if (t->type == TUNER_MT2032) |
||
232 | return 0; |
||
233 | |||
234 | if (1 != i2c_master_recv(c,&byte,1)) |
||
235 | return 0; |
||
236 | return byte; |
||
237 | } |
||
238 | |||
239 | #define TUNER_POR 0x80 |
||
240 | #define TUNER_FL 0x40 |
||
241 | #define TUNER_MODE 0x38 |
||
242 | #define TUNER_AFC 0x07 |
||
243 | |||
244 | #define TUNER_STEREO 0x10 /* radio mode */ |
||
245 | #define TUNER_SIGNAL 0x07 /* radio mode */ |
||
246 | |||
247 | static int tuner_signal(struct i2c_client *c) |
||
248 | { |
||
249 | return (tuner_getstatus(c) & TUNER_SIGNAL)<<13; |
||
250 | } |
||
251 | |||
252 | static int tuner_stereo(struct i2c_client *c) |
||
253 | { |
||
254 | return (tuner_getstatus (c) & TUNER_STEREO); |
||
255 | } |
||
256 | |||
257 | #if 0 /* unused */ |
||
258 | static int tuner_islocked (struct i2c_client *c) |
||
259 | { |
||
260 | return (tuner_getstatus (c) & TUNER_FL); |
||
261 | } |
||
262 | |||
263 | static int tuner_afcstatus (struct i2c_client *c) |
||
264 | { |
||
265 | return (tuner_getstatus (c) & TUNER_AFC) - 2; |
||
266 | } |
||
267 | |||
268 | static int tuner_mode (struct i2c_client *c) |
||
269 | { |
||
270 | return (tuner_getstatus (c) & TUNER_MODE) >> 3; |
||
271 | } |
||
272 | #endif |
||
273 | |||
274 | // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 |
||
275 | static int mt2032_init(struct i2c_client *c) |
||
276 | { |
||
277 | unsigned char buf[21]; |
||
278 | int ret,xogc,xok=0; |
||
279 | struct tuner *t = (struct tuner*)c->data; |
||
280 | |||
281 | buf[0]=0; |
||
282 | ret=i2c_master_send(c,buf,1); |
||
283 | i2c_master_recv(c,buf,21); |
||
284 | |||
285 | printk("MT2032: Companycode=%02x%02x Part=%02x Revision=%02x\n", |
||
286 | buf[0x11],buf[0x12],buf[0x13],buf[0x14]); |
||
287 | |||
288 | if(debug) { |
||
289 | int i; |
||
290 | printk("MT2032 hexdump:\n"); |
||
291 | for(i=0;i<21;i++) { |
||
292 | printk(" %02x",buf[i]); |
||
293 | if(((i+1)%8)==0) printk(" "); |
||
294 | if(((i+1)%16)==0) printk("\n "); |
||
295 | } |
||
296 | printk("\n "); |
||
297 | } |
||
298 | // Look for MT2032 id: |
||
299 | // part= 0x04(MT2032), 0x06(MT2030), 0x07(MT2040) |
||
300 | if((buf[0x11] != 0x4d) || (buf[0x12] != 0x54) || (buf[0x13] != 0x04)) { |
||
301 | printk("not a MT2032.\n"); |
||
302 | return 0; |
||
303 | } |
||
304 | |||
305 | |||
306 | // Initialize Registers per spec. |
||
307 | buf[1]=2; // Index to register 2 |
||
308 | buf[2]=0xff; |
||
309 | buf[3]=0x0f; |
||
310 | buf[4]=0x1f; |
||
311 | ret=i2c_master_send(c,buf+1,4); |
||
312 | |||
313 | buf[5]=6; // Index register 6 |
||
314 | buf[6]=0xe4; |
||
315 | buf[7]=0x8f; |
||
316 | buf[8]=0xc3; |
||
317 | buf[9]=0x4e; |
||
318 | buf[10]=0xec; |
||
319 | ret=i2c_master_send(c,buf+5,6); |
||
320 | |||
321 | buf[12]=13; // Index register 13 |
||
322 | buf[13]=0x32; |
||
323 | ret=i2c_master_send(c,buf+12,2); |
||
324 | |||
325 | // Adjust XOGC (register 7), wait for XOK |
||
326 | xogc=7; |
||
327 | do { |
||
328 | dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); |
||
329 | mdelay(10); |
||
330 | buf[0]=0x0e; |
||
331 | i2c_master_send(c,buf,1); |
||
332 | i2c_master_recv(c,buf,1); |
||
333 | xok=buf[0]&0x01; |
||
334 | dprintk("mt2032: xok = 0x%02x\n",xok); |
||
335 | if (xok == 1) break; |
||
336 | |||
337 | xogc--; |
||
338 | dprintk("mt2032: xogc = 0x%02x\n",xogc&0x07); |
||
339 | if (xogc == 3) { |
||
340 | xogc=4; // min. 4 per spec |
||
341 | break; |
||
342 | } |
||
343 | buf[0]=0x07; |
||
344 | buf[1]=0x88 + xogc; |
||
345 | ret=i2c_master_send(c,buf,2); |
||
346 | if (ret!=2) |
||
347 | printk("mt2032_init failed with %d\n",ret); |
||
348 | } while (xok != 1 ); |
||
349 | t->xogc=xogc; |
||
350 | |||
351 | return(1); |
||
352 | } |
||
353 | |||
354 | |||
355 | // IsSpurInBand()? |
||
356 | static int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to) |
||
357 | { |
||
358 | int n1=1,n2,f; |
||
359 | |||
360 | f1=f1/1000; //scale to kHz to avoid 32bit overflows |
||
361 | f2=f2/1000; |
||
362 | spectrum_from/=1000; |
||
363 | spectrum_to/=1000; |
||
364 | |||
365 | dprintk("spurcheck f1=%d f2=%d from=%d to=%d\n",f1,f2,spectrum_from,spectrum_to); |
||
366 | |||
367 | do { |
||
368 | n2=-n1; |
||
369 | f=n1*(f1-f2); |
||
370 | do { |
||
371 | n2--; |
||
372 | f=f-f2; |
||
373 | dprintk(" spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); |
||
374 | |||
375 | if( (f>spectrum_from) && (f<spectrum_to)) |
||
376 | printk("mt2032 spurcheck triggered: %d\n",n1); |
||
377 | } while ( (f>(f2-spectrum_to)) || (n2>-5)); |
||
378 | n1++; |
||
379 | } while (n1<5); |
||
380 | |||
381 | return 1; |
||
382 | } |
||
383 | |||
384 | static int mt2032_compute_freq(int rfin, int if1, int if2, int spectrum_from, |
||
385 | int spectrum_to, unsigned char *buf, int *ret_sel, int xogc) //all in Hz |
||
386 | { |
||
387 | int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, |
||
388 | desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; |
||
389 | |||
390 | fref= 5250 *1000; //5.25MHz |
||
391 | desired_lo1=rfin+if1; |
||
392 | |||
393 | lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); |
||
394 | lo1n=lo1/8; |
||
395 | lo1a=lo1-(lo1n*8); |
||
396 | |||
397 | s=rfin/1000/1000+1090; |
||
398 | |||
399 | if(optimize_vco) { |
||
400 | if(s>1890) sel=0; |
||
401 | else if(s>1720) sel=1; |
||
402 | else if(s>1530) sel=2; |
||
403 | else if(s>1370) sel=3; |
||
404 | else sel=4; // >1090 |
||
405 | } |
||
406 | else { |
||
407 | if(s>1790) sel=0; // <1958 |
||
408 | else if(s>1617) sel=1; |
||
409 | else if(s>1449) sel=2; |
||
410 | else if(s>1291) sel=3; |
||
411 | else sel=4; // >1090 |
||
412 | } |
||
413 | *ret_sel=sel; |
||
414 | |||
415 | lo1freq=(lo1a+8*lo1n)*fref; |
||
416 | |||
417 | dprintk("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", |
||
418 | rfin,lo1,lo1n,lo1a,sel,lo1freq); |
||
419 | |||
420 | desired_lo2=lo1freq-rfin-if2; |
||
421 | lo2=(desired_lo2)/fref; |
||
422 | lo2n=lo2/8; |
||
423 | lo2a=lo2-(lo2n*8); |
||
424 | lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith |
||
425 | lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; |
||
426 | |||
427 | dprintk("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", |
||
428 | rfin,lo2,lo2n,lo2a,lo2num,lo2freq); |
||
429 | |||
430 | if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) { |
||
431 | printk("mt2032: frequency parameters out of range: %d %d %d %d\n", |
||
432 | lo1a, lo1n, lo2a,lo2n); |
||
433 | return(-1); |
||
434 | } |
||
435 | |||
436 | mt2032_spurcheck(lo1freq, desired_lo2, spectrum_from, spectrum_to); |
||
437 | // should recalculate lo1 (one step up/down) |
||
438 | |||
439 | // set up MT2032 register map for transfer over i2c |
||
440 | buf[0]=lo1n-1; |
||
441 | buf[1]=lo1a | (sel<<4); |
||
442 | buf[2]=0x86; // LOGC |
||
443 | buf[3]=0x0f; //reserved |
||
444 | buf[4]=0x1f; |
||
445 | buf[5]=(lo2n-1) | (lo2a<<5); |
||
446 | if(rfin >400*1000*1000) |
||
447 | buf[6]=0xe4; |
||
448 | else |
||
449 | buf[6]=0xf4; // set PKEN per rev 1.2 |
||
450 | buf[7]=8+xogc; |
||
451 | buf[8]=0xc3; //reserved |
||
452 | buf[9]=0x4e; //reserved |
||
453 | buf[10]=0xec; //reserved |
||
454 | buf[11]=(lo2num&0xff); |
||
455 | buf[12]=(lo2num>>8) |0x80; // Lo2RST |
||
456 | |||
457 | return 0; |
||
458 | } |
||
459 | |||
460 | static int mt2032_check_lo_lock(struct i2c_client *c) |
||
461 | { |
||
462 | int try,lock=0; |
||
463 | unsigned char buf[2]; |
||
464 | for(try=0;try<10;try++) { |
||
465 | buf[0]=0x0e; |
||
466 | i2c_master_send(c,buf,1); |
||
467 | i2c_master_recv(c,buf,1); |
||
468 | dprintk("mt2032 Reg.E=0x%02x\n",buf[0]); |
||
469 | lock=buf[0] &0x06; |
||
470 | |||
471 | if (lock==6) |
||
472 | break; |
||
473 | |||
474 | dprintk("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); |
||
475 | udelay(1000); |
||
476 | } |
||
477 | return lock; |
||
478 | } |
||
479 | |||
480 | static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) |
||
481 | { |
||
482 | unsigned char buf[2]; |
||
483 | int tad1; |
||
484 | |||
485 | buf[0]=0x0f; |
||
486 | i2c_master_send(c,buf,1); |
||
487 | i2c_master_recv(c,buf,1); |
||
488 | dprintk("mt2032 Reg.F=0x%02x\n",buf[0]); |
||
489 | tad1=buf[0]&0x07; |
||
490 | |||
491 | if(tad1 ==0) return lock; |
||
492 | if(tad1 ==1) return lock; |
||
493 | |||
494 | if(tad1==2) { |
||
495 | if(sel==0) |
||
496 | return lock; |
||
497 | else sel--; |
||
498 | } |
||
499 | else { |
||
500 | if(sel<4) |
||
501 | sel++; |
||
502 | else |
||
503 | return lock; |
||
504 | } |
||
505 | |||
506 | dprintk("mt2032 optimize_vco: sel=%d\n",sel); |
||
507 | |||
508 | buf[0]=0x0f; |
||
509 | buf[1]=sel; |
||
510 | i2c_master_send(c,buf,2); |
||
511 | lock=mt2032_check_lo_lock(c); |
||
512 | return lock; |
||
513 | } |
||
514 | |||
515 | |||
516 | static void mt2032_set_if_freq(struct i2c_client *c,int rfin, int if1, int if2, int from, int to) |
||
517 | { |
||
518 | unsigned char buf[21]; |
||
519 | int lint_try,ret,sel,lock=0; |
||
520 | struct tuner *t = (struct tuner*)c->data; |
||
521 | |||
522 | dprintk("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",rfin,if1,if2,from,to); |
||
523 | |||
524 | buf[0]=0; |
||
525 | ret=i2c_master_send(c,buf,1); |
||
526 | i2c_master_recv(c,buf,21); |
||
527 | |||
528 | buf[0]=0; |
||
529 | ret=mt2032_compute_freq(rfin,if1,if2,from,to,&buf[1],&sel,t->xogc); |
||
530 | if (ret<0) |
||
531 | return; |
||
532 | |||
533 | // send only the relevant registers per Rev. 1.2 |
||
534 | buf[0]=0; |
||
535 | ret=i2c_master_send(c,buf,4); |
||
536 | buf[5]=5; |
||
537 | ret=i2c_master_send(c,buf+5,4); |
||
538 | buf[11]=11; |
||
539 | ret=i2c_master_send(c,buf+11,3); |
||
540 | if(ret!=3) |
||
541 | printk("mt2032_set_if_freq failed with %d\n",ret); |
||
542 | |||
543 | // wait for PLLs to lock (per manual), retry LINT if not. |
||
544 | for(lint_try=0; lint_try<2; lint_try++) { |
||
545 | lock=mt2032_check_lo_lock(c); |
||
546 | |||
547 | if(optimize_vco) |
||
548 | lock=mt2032_optimize_vco(c,sel,lock); |
||
549 | if(lock==6) break; |
||
550 | |||
551 | printk("mt2032: re-init PLLs by LINT\n"); |
||
552 | buf[0]=7; |
||
553 | buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs |
||
554 | i2c_master_send(c,buf,2); |
||
555 | mdelay(10); |
||
556 | buf[1]=8+t->xogc; |
||
557 | i2c_master_send(c,buf,2); |
||
558 | } |
||
559 | |||
560 | if (lock!=6) |
||
561 | printk("MT2032 Fatal Error: PLLs didn't lock.\n"); |
||
562 | |||
563 | buf[0]=2; |
||
564 | buf[1]=0x20; // LOGC for optimal phase noise |
||
565 | ret=i2c_master_send(c,buf,2); |
||
566 | if (ret!=2) |
||
567 | printk("mt2032_set_if_freq2 failed with %d\n",ret); |
||
568 | } |
||
569 | |||
570 | |||
571 | static void mt2032_set_tv_freq(struct i2c_client *c, int freq, int norm) |
||
572 | { |
||
573 | int if2,from,to; |
||
574 | |||
575 | // signal bandwidth and picture carrier |
||
576 | if(norm==VIDEO_MODE_NTSC) { |
||
577 | from=40750*1000; |
||
578 | to=46750*1000; |
||
579 | if2=45750*1000; |
||
580 | } |
||
581 | else { // Pal |
||
582 | from=32900*1000; |
||
583 | to=39900*1000; |
||
584 | if2=38900*1000; |
||
585 | } |
||
586 | |||
587 | mt2032_set_if_freq(c,freq* 1000*1000/16, 1090*1000*1000, if2, from, to); |
||
588 | } |
||
589 | |||
590 | |||
591 | // Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz |
||
592 | static void set_tv_freq(struct i2c_client *c, int freq) |
||
593 | { |
||
594 | u8 config; |
||
595 | u16 div; |
||
596 | struct tunertype *tun; |
||
597 | struct tuner *t = c->data; |
||
598 | unsigned char buffer[4]; |
||
599 | int rc; |
||
600 | |||
601 | if (t->type == -1) { |
||
602 | printk("tuner: tuner type not set\n"); |
||
603 | return; |
||
604 | } |
||
605 | if (t->type == TUNER_MT2032) { |
||
606 | mt2032_set_tv_freq(c,freq,t->mode); |
||
607 | return; |
||
608 | } |
||
609 | |||
610 | if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { |
||
611 | /* FIXME: better do that chip-specific, but |
||
612 | right now we don't have that in the config |
||
613 | struct and this way is still better than no |
||
614 | check at all */ |
||
615 | printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n", |
||
616 | freq/16,freq%16*100/16,tv_range[0],tv_range[1]); |
||
617 | return; |
||
618 | } |
||
619 | |||
620 | tun=&tuners[t->type]; |
||
621 | if (freq < tun->thresh1) |
||
622 | config = tun->VHF_L; |
||
623 | else if (freq < tun->thresh2) |
||
624 | config = tun->VHF_H; |
||
625 | else |
||
626 | config = tun->UHF; |
||
627 | |||
628 | |||
629 | /* tv norm specific stuff for multi-norm tuners */ |
||
630 | switch (t->type) { |
||
631 | case TUNER_PHILIPS_SECAM: // FI1216MF |
||
632 | /* 0x01 -> ??? no change ??? */ |
||
633 | /* 0x02 -> PAL BDGHI / SECAM L */ |
||
634 | /* 0x04 -> ??? PAL others / SECAM others ??? */ |
||
635 | config &= ~0x02; |
||
636 | if (t->mode == VIDEO_MODE_SECAM) |
||
637 | config |= 0x02; |
||
638 | break; |
||
639 | |||
640 | case TUNER_TEMIC_4046FM5: |
||
641 | config &= ~0x0f; |
||
642 | switch (pal[0]) { |
||
643 | case 'i': |
||
644 | case 'I': |
||
645 | config |= TEMIC_SET_PAL_I; |
||
646 | break; |
||
647 | case 'd': |
||
648 | case 'D': |
||
649 | config |= TEMIC_SET_PAL_DK; |
||
650 | break; |
||
651 | case 'l': |
||
652 | case 'L': |
||
653 | config |= TEMIC_SET_PAL_L; |
||
654 | break; |
||
655 | case 'b': |
||
656 | case 'B': |
||
657 | case 'g': |
||
658 | case 'G': |
||
659 | default: |
||
660 | config |= TEMIC_SET_PAL_BG; |
||
661 | break; |
||
662 | } |
||
663 | break; |
||
664 | |||
665 | case TUNER_PHILIPS_FQ1216ME: |
||
666 | config &= ~0x0f; |
||
667 | switch (pal[0]) { |
||
668 | case 'i': |
||
669 | case 'I': |
||
670 | config |= PHILIPS_SET_PAL_I; |
||
671 | break; |
||
672 | case 'l': |
||
673 | case 'L': |
||
674 | config |= PHILIPS_SET_PAL_L; |
||
675 | break; |
||
676 | case 'd': |
||
677 | case 'D': |
||
678 | case 'b': |
||
679 | case 'B': |
||
680 | case 'g': |
||
681 | case 'G': |
||
682 | config |= PHILIPS_SET_PAL_BGDK; |
||
683 | break; |
||
684 | } |
||
685 | break; |
||
686 | } |
||
687 | |||
688 | |||
689 | /* |
||
690 | * Philips FI1216MK2 remark from specification : |
||
691 | * for channel selection involving band switching, and to ensure |
||
692 | * smooth tuning to the desired channel without causing |
||
693 | * unnecessary charge pump action, it is recommended to consider |
||
694 | * the difference between wanted channel frequency and the |
||
695 | * current channel frequency. Unnecessary charge pump action |
||
696 | * will result in very low tuning voltage which may drive the |
||
697 | * oscillator to extreme conditions. |
||
698 | * |
||
699 | * Progfou: specification says to send config data before |
||
700 | * frequency in case (wanted frequency < current frequency). |
||
701 | */ |
||
702 | |||
703 | div=freq + tun->IFPCoff; |
||
704 | if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { |
||
705 | buffer[0] = tun->config; |
||
706 | buffer[1] = config; |
||
707 | buffer[2] = (div>>8) & 0x7f; |
||
708 | buffer[3] = div & 0xff; |
||
709 | } else { |
||
710 | buffer[0] = (div>>8) & 0x7f; |
||
711 | buffer[1] = div & 0xff; |
||
712 | buffer[2] = tun->config; |
||
713 | buffer[3] = config; |
||
714 | } |
||
715 | dprintk("tuner: tv 0x%02x 0x%02x 0x%02x 0x%02x\n", |
||
716 | buffer[0],buffer[1],buffer[2],buffer[3]); |
||
717 | |||
718 | if (4 != (rc = i2c_master_send(c,buffer,4))) |
||
719 | printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); |
||
720 | |||
721 | } |
||
722 | |||
723 | static void mt2032_set_radio_freq(struct i2c_client *c,int freq) |
||
724 | { |
||
725 | int if2; |
||
726 | |||
727 | if2=10700*1000; // 10.7MHz FM intermediate frequency |
||
728 | |||
729 | // per Manual for FM tuning: first if center freq. 1085 MHz |
||
730 | mt2032_set_if_freq(c,freq* 1000*1000/16, 1085*1000*1000,if2,if2,if2); |
||
731 | } |
||
732 | |||
733 | static void set_radio_freq(struct i2c_client *c, int freq) |
||
734 | { |
||
735 | struct tunertype *tun; |
||
736 | struct tuner *t = (struct tuner*)c->data; |
||
737 | unsigned char buffer[4]; |
||
738 | int rc,div; |
||
739 | |||
740 | if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { |
||
741 | printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n", |
||
742 | freq/16,freq%16*100/16, |
||
743 | radio_range[0],radio_range[1]); |
||
744 | return; |
||
745 | } |
||
746 | if (t->type == -1) { |
||
747 | printk("tuner: tuner type not set\n"); |
||
748 | return; |
||
749 | } |
||
750 | |||
751 | if (t->type == TUNER_MT2032) { |
||
752 | mt2032_set_radio_freq(c,freq); |
||
753 | return; |
||
754 | } |
||
755 | |||
756 | tun=&tuners[t->type]; |
||
757 | div = freq + (int)(16*10.7); |
||
758 | buffer[0] = (div>>8) & 0x7f; |
||
759 | buffer[1] = div & 0xff; |
||
760 | buffer[2] = tun->config; |
||
761 | switch (t->type) { |
||
762 | case TUNER_PHILIPS_FM1216ME_MK3: |
||
763 | buffer[3] = 0x19; |
||
764 | break; |
||
765 | default: |
||
766 | buffer[3] = 0xa4; |
||
767 | break; |
||
768 | } |
||
769 | |||
770 | dprintk("tuner: radio 0x%02x 0x%02x 0x%02x 0x%02x\n", |
||
771 | buffer[0],buffer[1],buffer[2],buffer[3]); |
||
772 | |||
773 | if (4 != (rc = i2c_master_send(c,buffer,4))) |
||
774 | printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); |
||
775 | } |
||
776 | |||
777 | /* ---------------------------------------------------------------------- */ |
||
778 | |||
779 | static int tuner_attach(struct i2c_adapter *adap, int addr, |
||
780 | unsigned short flags, int kind) |
||
781 | { |
||
782 | struct tuner *t; |
||
783 | struct i2c_client *client; |
||
784 | |||
785 | if (this_adap > 0) |
||
786 | return -1; |
||
787 | this_adap++; |
||
788 | |||
789 | client_template.adapter = adap; |
||
790 | client_template.addr = addr; |
||
791 | |||
792 | printk("tuner: chip found @ 0x%x\n", addr<<1); |
||
793 | |||
794 | if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) |
||
795 | return -ENOMEM; |
||
796 | memcpy(client,&client_template,sizeof(struct i2c_client)); |
||
797 | client->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); |
||
798 | if (NULL == t) { |
||
799 | kfree(client); |
||
800 | return -ENOMEM; |
||
801 | } |
||
802 | memset(t,0,sizeof(struct tuner)); |
||
803 | if (type >= 0 && type < TUNERS) { |
||
804 | t->type = type; |
||
805 | printk("tuner(bttv): type forced to %d (%s) [insmod]\n",t->type,tuners[t->type].name); |
||
806 | strncpy(client->name, tuners[t->type].name, sizeof(client->name)); |
||
807 | } else { |
||
808 | t->type = -1; |
||
809 | } |
||
810 | i2c_attach_client(client); |
||
811 | if (t->type == TUNER_MT2032) |
||
812 | mt2032_init(client); |
||
813 | |||
814 | MOD_INC_USE_COUNT; |
||
815 | return 0; |
||
816 | } |
||
817 | |||
818 | static int tuner_probe(struct i2c_adapter *adap) |
||
819 | { |
||
820 | int rc; |
||
821 | |||
822 | if (0 != addr) { |
||
823 | normal_i2c_range[0] = addr; |
||
824 | normal_i2c_range[1] = addr; |
||
825 | } |
||
826 | this_adap = 0; |
||
827 | switch (adap->id) { |
||
828 | case I2C_ALGO_BIT | I2C_HW_B_BT848: |
||
829 | case I2C_ALGO_BIT | I2C_HW_B_RIVA: |
||
830 | case I2C_ALGO_SAA7134: |
||
831 | case I2C_ALGO_SAA7146: |
||
832 | printk("tuner: probing %s i2c adapter [id=0x%x]\n", |
||
833 | adap->name,adap->id); |
||
834 | rc = i2c_probe(adap, &addr_data, tuner_attach); |
||
835 | break; |
||
836 | default: |
||
837 | printk("tuner: ignoring %s i2c adapter [id=0x%x]\n", |
||
838 | adap->name,adap->id); |
||
839 | rc = 0; |
||
840 | /* nothing */ |
||
841 | } |
||
842 | return rc; |
||
843 | } |
||
844 | |||
845 | static int tuner_detach(struct i2c_client *client) |
||
846 | { |
||
847 | struct tuner *t = (struct tuner*)client->data; |
||
848 | |||
849 | i2c_detach_client(client); |
||
850 | kfree(t); |
||
851 | kfree(client); |
||
852 | MOD_DEC_USE_COUNT; |
||
853 | return 0; |
||
854 | } |
||
855 | |||
856 | static int |
||
857 | tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) |
||
858 | { |
||
859 | struct tuner *t = (struct tuner*)client->data; |
||
860 | int *iarg = (int*)arg; |
||
861 | #if 0 |
||
862 | __u16 *sarg = (__u16*)arg; |
||
863 | #endif |
||
864 | |||
865 | switch (cmd) { |
||
866 | |||
867 | /* --- configuration --- */ |
||
868 | case TUNER_SET_TYPE: |
||
869 | if (t->type != -1) { |
||
870 | printk("tuner: type already set (%d)\n",t->type); |
||
871 | return 0; |
||
872 | } |
||
873 | if (*iarg < 0 || *iarg >= TUNERS) |
||
874 | return 0; |
||
875 | t->type = *iarg; |
||
876 | printk("tuner: type set to %d (%s)\n", |
||
877 | t->type,tuners[t->type].name); |
||
878 | strncpy(client->name, tuners[t->type].name, sizeof(client->name)); |
||
879 | if (t->type == TUNER_MT2032) |
||
880 | mt2032_init(client); |
||
881 | break; |
||
882 | case AUDC_SET_RADIO: |
||
883 | t->radio = 1; |
||
884 | break; |
||
885 | |||
886 | /* --- v4l ioctls --- */ |
||
887 | /* take care: bttv does userspace copying, we'll get a |
||
888 | kernel pointer here... */ |
||
889 | case VIDIOCSCHAN: |
||
890 | { |
||
891 | struct video_channel *vc = arg; |
||
892 | |||
893 | t->radio = 0; |
||
894 | t->mode = vc->norm; |
||
895 | if (t->freq) |
||
896 | set_tv_freq(client,t->freq); |
||
897 | return 0; |
||
898 | } |
||
899 | case VIDIOCSFREQ: |
||
900 | { |
||
901 | unsigned long *v = arg; |
||
902 | |||
903 | if (t->radio) { |
||
904 | dprintk("tuner: radio freq set to %d.%02d\n", |
||
905 | (*iarg)/16,(*iarg)%16*100/16); |
||
906 | set_radio_freq(client,*v); |
||
907 | } else { |
||
908 | dprintk("tuner: tv freq set to %d.%02d\n", |
||
909 | (*iarg)/16,(*iarg)%16*100/16); |
||
910 | set_tv_freq(client,*v); |
||
911 | } |
||
912 | t->freq = *v; |
||
913 | return 0; |
||
914 | } |
||
915 | case VIDIOCGTUNER: |
||
916 | { |
||
917 | struct video_tuner *vt = arg; |
||
918 | |||
919 | if (t->radio) |
||
920 | vt->signal = tuner_signal(client); |
||
921 | return 0; |
||
922 | } |
||
923 | case VIDIOCGAUDIO: |
||
924 | { |
||
925 | struct video_audio *va = arg; |
||
926 | if (t->radio) |
||
927 | va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO); |
||
928 | return 0; |
||
929 | } |
||
930 | |||
931 | #if 0 |
||
932 | /* --- old, obsolete interface --- */ |
||
933 | case TUNER_SET_TVFREQ: |
||
934 | dprintk("tuner: tv freq set to %d.%02d\n", |
||
935 | (*iarg)/16,(*iarg)%16*100/16); |
||
936 | set_tv_freq(client,*iarg); |
||
937 | t->radio = 0; |
||
938 | t->freq = *iarg; |
||
939 | break; |
||
940 | |||
941 | case TUNER_SET_RADIOFREQ: |
||
942 | dprintk("tuner: radio freq set to %d.%02d\n", |
||
943 | (*iarg)/16,(*iarg)%16*100/16); |
||
944 | set_radio_freq(client,*iarg); |
||
945 | t->radio = 1; |
||
946 | t->freq = *iarg; |
||
947 | break; |
||
948 | case TUNER_SET_MODE: |
||
949 | if (t->type != TUNER_PHILIPS_SECAM) { |
||
950 | dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n"); |
||
951 | } else { |
||
952 | int mode=(*sarg==VIDEO_MODE_SECAM)?1:0; |
||
953 | dprintk("tuner: mode set to %d\n", *sarg); |
||
954 | t->mode = mode; |
||
955 | set_tv_freq(client,t->freq); |
||
956 | } |
||
957 | break; |
||
958 | #endif |
||
959 | default: |
||
960 | /* nothing */ |
||
961 | break; |
||
962 | } |
||
963 | |||
964 | return 0; |
||
965 | } |
||
966 | |||
967 | /* ----------------------------------------------------------------------- */ |
||
968 | |||
969 | static struct i2c_driver driver = { |
||
970 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,54) |
||
971 | .owner = THIS_MODULE, |
||
972 | #endif |
||
973 | .name = "i2c TV tuner driver", |
||
974 | .id = I2C_DRIVERID_TUNER, |
||
975 | .flags = I2C_DF_NOTIFY, |
||
976 | .attach_adapter = tuner_probe, |
||
977 | .detach_client = tuner_detach, |
||
978 | .command = tuner_command, |
||
979 | }; |
||
980 | static struct i2c_client client_template = |
||
981 | { |
||
982 | .name = "(tuner unset)", |
||
983 | .flags = I2C_CLIENT_ALLOW_USE, |
||
984 | .driver = &driver, |
||
985 | }; |
||
986 | |||
987 | static int tuner_init_module(void) |
||
988 | { |
||
989 | i2c_add_driver(&driver); |
||
990 | return 0; |
||
991 | } |
||
992 | |||
993 | static void tuner_cleanup_module(void) |
||
994 | { |
||
995 | i2c_del_driver(&driver); |
||
996 | } |
||
997 | |||
998 | module_init(tuner_init_module); |
||
999 | module_exit(tuner_cleanup_module); |
||
1000 | |||
1001 | /* |
||
1002 | * Overrides for Emacs so that we follow Linus's tabbing style. |
||
1003 | * --------------------------------------------------------------------------- |
||
1004 | * Local variables: |
||
1005 | * c-basic-offset: 8 |
||
1006 | * End: |
||
1007 | */ |