~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/media/video/tuner.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/malloc.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 "tuner.h"
 16 #include "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 static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
 22 static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
 23 static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
 24 static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
 25 static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
 26 static struct i2c_client_address_data addr_data = {
 27         normal_i2c, normal_i2c_range, 
 28         probe, probe_range, 
 29         ignore, ignore_range, 
 30         force
 31 };
 32 
 33 static int debug =  0; /* insmod parameter */
 34 static int type  = -1; /* insmod parameter */
 35 
 36 static int addr  =  0;
 37 static int this_adap;
 38 
 39 #define dprintk     if (debug) printk
 40 
 41 MODULE_PARM(debug,"i");
 42 MODULE_PARM(type,"i");
 43 MODULE_PARM(addr,"i");
 44 
 45 struct tuner
 46 {
 47         int type;            /* chip type */
 48         int freq;            /* keep track of the current settings */
 49         int std;
 50 
 51         int radio;
 52         int mode;            /* PAL(0)/SECAM(1) mode (PHILIPS_SECAM only) */
 53 };
 54 
 55 static struct i2c_driver driver;
 56 static struct i2c_client client_template;
 57 
 58 /* ---------------------------------------------------------------------- */
 59 
 60 struct tunertype 
 61 {
 62         char *name;
 63         unsigned char Vendor;
 64         unsigned char Type;
 65   
 66         unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */   
 67         unsigned short thresh2;  
 68         unsigned char VHF_L;
 69         unsigned char VHF_H;
 70         unsigned char UHF;
 71         unsigned char config; 
 72         unsigned short IFPCoff;
 73         unsigned char mode; /* mode change value (tested PHILIPS_SECAM only) */
 74                         /* 0x01 -> ??? no change ??? */
 75                         /* 0x02 -> PAL BDGHI / SECAM L */
 76                         /* 0x04 -> ??? PAL others / SECAM others ??? */
 77         int capability;
 78 };
 79 
 80 /*
 81  *      The floats in the tuner struct are computed at compile time
 82  *      by gcc and cast back to integers. Thus we don't violate the
 83  *      "no float in kernel" rule.
 84  */
 85 static struct tunertype tuners[] = {
 86         { "Temic PAL", TEMIC, PAL,
 87           16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
 88         { "Philips PAL_I", Philips, PAL_I,
 89           16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
 90         { "Philips NTSC", Philips, NTSC,
 91           16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
 92         { "Philips SECAM", Philips, SECAM,
 93           16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623,0x02},
 94         { "NoTuner", NoTuner, NOTUNER,
 95           0,0,0x00,0x00,0x00,0x00,0x00,000},
 96         { "Philips PAL", Philips, PAL,
 97           16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623},
 98         { "Temic NTSC", TEMIC, NTSC,
 99           16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
100         { "Temic PAL_I", TEMIC, PAL_I,
101           16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
102         { "Temic 4036 FY5 NTSC", TEMIC, NTSC,
103           16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
104         { "Alps HSBH1", TEMIC, NTSC,
105           16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
106         { "Alps TSBE1",TEMIC,PAL,
107           16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
108         { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */
109           16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
110         { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
111           16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
112         { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
113           16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
114         { "Temic 4006FH5", TEMIC, PAL_I,
115           16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, 
116         { "Alps TSCH6",Alps,NTSC,
117           16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
118 };
119 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
120 
121 /* ---------------------------------------------------------------------- */
122 
123 static int tuner_getstatus(struct i2c_client *c)
124 {
125         unsigned char byte;
126 
127         if (1 != i2c_master_recv(c,&byte,1))
128                 return 0;
129         return byte;
130 }
131 
132 #define TUNER_POR       0x80
133 #define TUNER_FL        0x40
134 #define TUNER_MODE      0x38
135 #define TUNER_AFC       0x07
136 
137 #define TUNER_STEREO    0x10 /* radio mode */
138 #define TUNER_SIGNAL    0x07 /* radio mode */
139 
140 static int tuner_signal(struct i2c_client *c)
141 {
142         return (tuner_getstatus(c) & TUNER_SIGNAL)<<13;
143 }
144 
145 static int tuner_stereo(struct i2c_client *c)
146 {
147         return (tuner_getstatus (c) & TUNER_STEREO);
148 }
149 
150 
151 static int tuner_islocked (struct i2c_client *c)
152 {
153         return (tuner_getstatus (c) & TUNER_FL);
154 }
155 
156 static int tuner_afcstatus (struct i2c_client *c)
157 {
158         return (tuner_getstatus (c) & TUNER_AFC) - 2;
159 }
160 
161 #if 0 /* unused */
162 static int tuner_mode (struct i2c_client *c)
163 {
164         return (tuner_getstatus (c) & TUNER_MODE) >> 3;
165 }
166 #endif
167 
168 static void set_tv_freq(struct i2c_client *c, int freq)
169 {
170         u8 config;
171         u16 div;
172         struct tunertype *tun;
173         struct tuner *t = c->data;
174         unsigned char buffer[4];
175         int rc;
176 
177         if (t->type == -1) {
178                 printk("tuner: tuner type not set\n");
179                 return;
180         }
181 
182         tun=&tuners[t->type];
183         if (freq < tun->thresh1) 
184                 config = tun->VHF_L;
185         else if (freq < tun->thresh2) 
186                 config = tun->VHF_H;
187         else
188                 config = tun->UHF;
189 
190 #if 1   // Fix colorstandard mode change
191         if (t->type == TUNER_PHILIPS_SECAM && t->mode)
192                 config |= tun->mode;
193         else
194                 config &= ~tun->mode;
195 #else
196                 config &= ~tun->mode;
197 #endif
198 
199         div=freq + tun->IFPCoff;
200 
201     /*
202      * Philips FI1216MK2 remark from specification :
203      * for channel selection involving band switching, and to ensure
204      * smooth tuning to the desired channel without causing
205      * unnecessary charge pump action, it is recommended to consider
206      * the difference between wanted channel frequency and the
207      * current channel frequency.  Unnecessary charge pump action
208      * will result in very low tuning voltage which may drive the
209      * oscillator to extreme conditions.
210      */
211     /*
212      * Progfou: specification says to send config data before
213      * frequency in case (wanted frequency < current frequency).
214      */
215 
216         if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) {
217                 buffer[0] = tun->config;
218                 buffer[1] = config;
219                 buffer[2] = (div>>8) & 0x7f;
220                 buffer[3] = div      & 0xff;
221         } else {
222                 buffer[0] = (div>>8) & 0x7f;
223                 buffer[1] = div      & 0xff;
224                 buffer[2] = tun->config;
225                 buffer[3] = config;
226         }
227 
228         if (4 != (rc = i2c_master_send(c,buffer,4)))
229                 printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
230 
231 }
232 
233 static void set_radio_freq(struct i2c_client *c, int freq)
234 {
235         u8 config;
236         u16 div;
237         struct tunertype *tun;
238         struct tuner *t = (struct tuner*)c->data;
239         unsigned char buffer[4];
240         int rc;
241 
242         if (t->type == -1) {
243                 printk("tuner: tuner type not set\n");
244                 return;
245         }
246 
247         tun=&tuners[t->type];
248         config = 0xa4 /* 0xa5 */; /* bit 0 is AFC (set) vs. RF-Signal (clear) */
249         div=freq + (int)(16*10.7);
250         div&=0x7fff;
251 
252         buffer[0] = (div>>8) & 0x7f;
253         buffer[1] = div      & 0xff;
254         buffer[2] = tun->config;
255         buffer[3] = config;
256         if (4 != (rc = i2c_master_send(c,buffer,4)))
257                 printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc);
258 
259         if (debug) {
260                 current->state   = TASK_INTERRUPTIBLE;
261                 schedule_timeout(HZ/10);
262                 
263                 if (tuner_islocked (c))
264                         printk ("tuner: PLL locked\n");
265                 else
266                         printk ("tuner: PLL not locked\n");
267 
268                 if (config & 1) {
269                         printk ("tuner: AFC: %d\n", tuner_afcstatus(c));
270                 } else {
271                         printk ("tuner: Signal: %d\n", tuner_signal(c));
272                 }
273         }
274 }
275 /* ---------------------------------------------------------------------- */
276 
277 
278 static int tuner_attach(struct i2c_adapter *adap, int addr,
279                         unsigned short flags, int kind)
280 {
281         struct tuner *t;
282         struct i2c_client *client;
283 
284         if (this_adap > 0)
285                 return -1;
286         this_adap++;
287         
288         client_template.adapter = adap;
289         client_template.addr = addr;
290 
291         printk("tuner: chip found @ 0x%x\n",addr);
292 
293         if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
294                 return -ENOMEM;
295         memcpy(client,&client_template,sizeof(struct i2c_client));
296         client->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
297         if (NULL == t) {
298                 kfree(client);
299                 return -ENOMEM;
300         }
301         memset(t,0,sizeof(struct tuner));
302         if (type >= 0 && type < TUNERS) {
303                 t->type = type;
304                 strncpy(client->name, tuners[t->type].name, sizeof(client->name));
305         } else {
306                 t->type = -1;
307         }
308         i2c_attach_client(client);
309         MOD_INC_USE_COUNT;
310 
311         return 0;
312 }
313 
314 static int tuner_probe(struct i2c_adapter *adap)
315 {
316         if (0 != addr) {
317                 normal_i2c_range[0] = addr;
318                 normal_i2c_range[1] = addr;
319         }
320         this_adap = 0;
321         if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
322                 return i2c_probe(adap, &addr_data, tuner_attach);
323         return 0;
324 }
325 
326 static int tuner_detach(struct i2c_client *client)
327 {
328         struct tuner *t = (struct tuner*)client->data;
329 
330         i2c_detach_client(client);
331         kfree(t);
332         kfree(client);
333         MOD_DEC_USE_COUNT;
334         return 0;
335 }
336 
337 static int
338 tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
339 {
340         struct tuner *t = (struct tuner*)client->data;
341         int   *iarg = (int*)arg;
342 #if 0
343         __u16 *sarg = (__u16*)arg;
344 #endif
345 
346         switch (cmd) {
347 
348         /* --- configuration --- */
349         case TUNER_SET_TYPE:
350                 if (t->type != -1)
351                         return 0;
352                 if (*iarg < 0 || *iarg >= TUNERS)
353                         return 0;
354                 t->type = *iarg;
355                 dprintk("tuner: type set to %d (%s)\n",
356                         t->type,tuners[t->type].name);
357                 strncpy(client->name, tuners[t->type].name, sizeof(client->name));
358                 break;
359         case AUDC_SET_RADIO:
360                 t->radio = 1;
361                 break;
362                 
363         /* --- v4l ioctls --- */
364         /* take care: bttv does userspace copying, we'll get a
365            kernel pointer here... */
366         case VIDIOCSCHAN:
367         {
368                 struct video_channel *vc = arg;
369                 
370                 t->radio = 0;
371                 if (t->type == TUNER_PHILIPS_SECAM) {
372                         t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0;
373                         set_tv_freq(client,t->freq);
374                 }
375                 return 0;
376         }
377         case VIDIOCSFREQ:
378         {
379                 unsigned long *v = arg;
380 
381                 t->freq = *v;
382                 if (t->radio) {
383                         dprintk("tuner: radio freq set to %d.%02d\n",
384                                 (*iarg)/16,(*iarg)%16*100/16);
385                         set_radio_freq(client,t->freq);
386                 } else {
387                         dprintk("tuner: tv freq set to %d.%02d\n",
388                                 (*iarg)/16,(*iarg)%16*100/16);
389                         set_tv_freq(client,t->freq);
390                 }
391                 return 0;
392         }
393         case VIDIOCGTUNER:
394         {
395                 struct video_tuner *vt = arg;
396 
397                 if (t->radio)
398                         vt->signal = tuner_signal(client);
399                 return 0;
400         }
401         case VIDIOCGAUDIO:
402         {
403                 struct video_audio *va = arg;
404                 if (t->radio)
405                         va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO);
406                 return 0;
407         }
408         
409 #if 0
410         /* --- old, obsolete interface --- */
411         case TUNER_SET_TVFREQ:
412                 dprintk("tuner: tv freq set to %d.%02d\n",
413                         (*iarg)/16,(*iarg)%16*100/16);
414                 set_tv_freq(client,*iarg);
415                 t->radio = 0;
416                 t->freq = *iarg;
417                 break;
418 
419         case TUNER_SET_RADIOFREQ:
420                 dprintk("tuner: radio freq set to %d.%02d\n",
421                         (*iarg)/16,(*iarg)%16*100/16);
422                 set_radio_freq(client,*iarg);
423                 t->radio = 1;
424                 t->freq = *iarg;
425                 break;
426         case TUNER_SET_MODE:
427                 if (t->type != TUNER_PHILIPS_SECAM) {
428                         dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n");
429                 } else {
430                         int mode=(*sarg==VIDEO_MODE_SECAM)?1:0;
431                         dprintk("tuner: mode set to %d\n", *sarg);
432                         t->mode = mode;
433                         set_tv_freq(client,t->freq);
434                 }
435                 break;
436 #endif
437         default:
438                 /* nothing */
439         }
440         
441         return 0;
442 }
443 
444 /* ----------------------------------------------------------------------- */
445 
446 static struct i2c_driver driver = {
447         "i2c TV tuner driver",
448         I2C_DRIVERID_TUNER,
449         I2C_DF_NOTIFY,
450         tuner_probe,
451         tuner_detach,
452         tuner_command,
453 };
454 
455 static struct i2c_client client_template =
456 {
457         "(unset)",              /* name       */
458         -1,
459         0,
460         0,
461         NULL,
462         &driver
463 };
464 
465 EXPORT_NO_SYMBOLS;
466 
467 int tuner_init_module(void)
468 {
469         i2c_add_driver(&driver);
470         return 0;
471 }
472 
473 void tuner_cleanup_module(void)
474 {
475         i2c_del_driver(&driver);
476 }
477 
478 module_init(tuner_init_module);
479 module_exit(tuner_cleanup_module);
480 
481 /*
482  * Overrides for Emacs so that we follow Linus's tabbing style.
483  * ---------------------------------------------------------------------------
484  * Local variables:
485  * c-basic-offset: 8
486  * End:
487  */
488 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.