patch-2.1.94 linux/drivers/char/tuner.c
Next file: linux/drivers/char/tuner.h
Previous file: linux/drivers/char/pty.c
Back to the patch index
Back to the overall index
- Lines: 270
- Date:
Wed Apr 8 17:24:48 1998
- Orig file:
v2.1.93/linux/drivers/char/tuner.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.93/linux/drivers/char/tuner.c linux/drivers/char/tuner.c
@@ -0,0 +1,269 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include "i2c.h"
+#include <linux/videodev.h>
+
+#include "tuner.h"
+
+int debug = 0; /* insmod parameter */
+int type = 0; /* tuner type */
+
+#define dprintk if (debug) printk
+
+MODULE_PARM(debug,"i");
+MODULE_PARM(type,"i");
+
+struct tuner
+{
+ struct i2c_bus *bus; /* where is our chip */
+ int addr;
+
+ int type; /* chip type */
+ int freq; /* keep track of the current settings */
+ int radio;
+};
+
+/* ---------------------------------------------------------------------- */
+
+struct tunertype
+{
+ char *name;
+ unsigned char Vendor;
+ unsigned char Type;
+
+ unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */
+ unsigned short thresh2;
+ unsigned char VHF_L;
+ unsigned char VHF_H;
+ unsigned char UHF;
+ unsigned char config;
+ unsigned char I2C;
+ unsigned short IFPCoff;
+};
+
+/*
+ * The floats in the tuner struct are computed at compile time
+ * by gcc and cast back to integers. Thus we don't violate the
+ * "no float in kernel" rule.
+ */
+static struct tunertype tuners[] = {
+ {"Temic PAL", TEMIC, PAL,
+ 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,623},
+ {"Philips PAL_I", Philips, PAL_I,
+ 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc0,623},
+ {"Philips NTSC", Philips, NTSC,
+ 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0,732},
+ {"Philips SECAM", Philips, SECAM,
+ 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,0xc0,623},
+ {"NoTuner", NoTuner, NOTUNER,
+ 0 ,0 ,0x00,0x00,0x00,0x00,0x00,000},
+ {"Philips PAL", Philips, PAL,
+ 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0,623},
+ {"Temic NTSC", TEMIC, NTSC,
+ 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,732},
+ {"TEMIC PAL_I", TEMIC, PAL_I,
+ 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_getstatus (struct tuner *t)
+{
+ return i2c_read(t->bus,t->addr+1);
+}
+
+#define TUNER_POR 0x80
+#define TUNER_FL 0x40
+#define TUNER_AFC 0x07
+
+static int tuner_islocked (struct tuner *t)
+{
+ return (tuner_getstatus (t) & TUNER_FL);
+}
+
+static int tuner_afcstatus (struct tuner *t)
+{
+ return (tuner_getstatus (t) & TUNER_AFC) - 2;
+}
+
+
+static void set_tv_freq(struct tuner *t, int freq)
+{
+ unsigned long flags;
+ u8 config;
+ u16 div;
+ struct tunertype *tun=&tuners[t->type];
+
+ if (freq < tun->thresh1)
+ config = tun->VHF_L;
+ else if (freq < tun->thresh2)
+ config = tun->VHF_H;
+ else
+ config = tun->UHF;
+
+ div=freq + (int)(16*38.9);
+ div&=0x7fff;
+
+ LOCK_I2C_BUS(t->bus);
+ if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) {
+ printk("tuner: i2c i/o error #1\n");
+ } else {
+ if (i2c_write(t->bus, t->addr, tun->config, config, 1))
+ printk("tuner: i2c i/o error #2\n");
+ }
+ UNLOCK_I2C_BUS(t->bus);
+}
+
+static void set_radio_freq(struct tuner *t, int freq)
+{
+ unsigned long flags;
+ u8 config;
+ u16 div;
+ struct tunertype *tun=&tuners[type];
+
+ config = 0xa5;
+ div=freq + (int)(16*10.7);
+ div&=0x7fff;
+
+ LOCK_I2C_BUS(t->bus);
+ if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) {
+ printk("tuner: i2c i/o error #1\n");
+ } else {
+ if (i2c_write(t->bus, t->addr, tun->config, config, 1))
+ printk("tuner: i2c i/o error #2\n");
+ }
+ if (debug) {
+ UNLOCK_I2C_BUS(t->bus);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ/10;
+ schedule();
+ LOCK_I2C_BUS(t->bus);
+
+ if (tuner_islocked (t))
+ printk ("tuner: PLL locked\n");
+ else
+ printk ("tuner: PLL not locked\n");
+
+ printk ("tuner: AFC: %d\n", tuner_afcstatus (t));
+ }
+ UNLOCK_I2C_BUS(t->bus);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_attach(struct i2c_device *device)
+{
+ struct tuner *t;
+
+ /*
+ * For now we only try and attach these tuners to the BT848
+ * bus. This same module will however work different species
+ * of card using these chips. Just change the constraints
+ * (i2c doesn't have a totally clash free 'address' space)
+ */
+
+ if(device->bus->id!=I2C_BUSID_BT848)
+ return -EINVAL;
+
+ device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
+ if (NULL == t)
+ return -ENOMEM;
+ memset(t,0,sizeof(struct tuner));
+ strcpy(device->name,"tuner");
+ t->bus = device->bus;
+ t->addr = device->addr;
+ t->type = type;
+ dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int tuner_detach(struct i2c_device *device)
+{
+ struct tuner *t = (struct tuner*)device->data;
+ kfree(t);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int tuner_command(struct i2c_device *device,
+ unsigned int cmd, void *arg)
+{
+ struct tuner *t = (struct tuner*)device->data;
+ int *iarg = (int*)arg;
+
+ switch (cmd)
+ {
+ case TUNER_SET_TYPE:
+ t->type = *iarg;
+ dprintk("tuner: type set to %d (%s)\n",
+ t->type,tuners[t->type].name);
+ break;
+
+ case TUNER_SET_TVFREQ:
+ dprintk("tuner: tv freq set to %d.%02d\n",
+ (*iarg)/16,(*iarg)%16*100/16);
+ set_tv_freq(t,*iarg);
+ t->radio = 0;
+ t->freq = *iarg;
+ break;
+
+ case TUNER_SET_RADIOFREQ:
+ dprintk("tuner: radio freq set to %d.%02d\n",
+ (*iarg)/16,(*iarg)%16*100/16);
+ set_radio_freq(t,*iarg);
+ t->radio = 1;
+ t->freq = *iarg;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_tuner =
+{
+ "tuner", /* name */
+ I2C_DRIVERID_TUNER, /* ID */
+ 0xc0, 0xce, /* addr range */
+
+ tuner_attach,
+ tuner_detach,
+ tuner_command
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int msp3400c_init(void)
+#endif
+{
+ i2c_register_driver(&i2c_driver_tuner);
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ i2c_unregister_driver(&i2c_driver_tuner);
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov