Import 2.1.118
[davej-history.git] / drivers / char / tuner.c
blobc640ff32166657ecf47990d1e60e354f035bd951
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>
10 #include <linux/i2c.h>
11 #include <linux/videodev.h>
13 #include "tuner.h"
15 static int debug = 0; /* insmod parameter */
16 static int type = 0; /* tuner type */
18 #define dprintk if (debug) printk
20 MODULE_PARM(debug,"i");
21 MODULE_PARM(type,"i");
23 struct tuner
25 struct i2c_bus *bus; /* where is our chip */
26 int addr;
28 int type; /* chip type */
29 int freq; /* keep track of the current settings */
30 int radio;
33 /* ---------------------------------------------------------------------- */
35 struct tunertype
37 char *name;
38 unsigned char Vendor;
39 unsigned char Type;
41 unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */
42 unsigned short thresh2;
43 unsigned char VHF_L;
44 unsigned char VHF_H;
45 unsigned char UHF;
46 unsigned char config;
47 unsigned char I2C;
48 unsigned short IFPCoff;
52 * The floats in the tuner struct are computed at compile time
53 * by gcc and cast back to integers. Thus we don't violate the
54 * "no float in kernel" rule.
56 static struct tunertype tuners[] = {
57 {"Temic PAL", TEMIC, PAL,
58 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,623},
59 {"Philips PAL_I", Philips, PAL_I,
60 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc0,623},
61 {"Philips NTSC", Philips, NTSC,
62 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0,732},
63 {"Philips SECAM", Philips, SECAM,
64 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,0xc0,623},
65 {"NoTuner", NoTuner, NOTUNER,
66 0 ,0 ,0x00,0x00,0x00,0x00,0x00,000},
67 {"Philips PAL", Philips, PAL,
68 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0,623},
69 {"Temic NTSC", TEMIC, NTSC,
70 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,732},
71 {"TEMIC PAL_I", TEMIC, PAL_I,
72 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
75 /* ---------------------------------------------------------------------- */
77 static int tuner_getstatus (struct tuner *t)
79 return i2c_read(t->bus,t->addr+1);
82 #define TUNER_POR 0x80
83 #define TUNER_FL 0x40
84 #define TUNER_AFC 0x07
86 static int tuner_islocked (struct tuner *t)
88 return (tuner_getstatus (t) & TUNER_FL);
91 static int tuner_afcstatus (struct tuner *t)
93 return (tuner_getstatus (t) & TUNER_AFC) - 2;
97 static void set_tv_freq(struct tuner *t, int freq)
99 unsigned long flags;
100 u8 config;
101 u16 div;
102 struct tunertype *tun=&tuners[t->type];
104 if (freq < tun->thresh1)
105 config = tun->VHF_L;
106 else if (freq < tun->thresh2)
107 config = tun->VHF_H;
108 else
109 config = tun->UHF;
111 div=freq + tun->IFPCoff;
112 div&=0x7fff;
114 LOCK_I2C_BUS(t->bus);
115 if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) {
116 printk("tuner: i2c i/o error #1\n");
117 } else {
118 if (i2c_write(t->bus, t->addr, tun->config, config, 1))
119 printk("tuner: i2c i/o error #2\n");
121 UNLOCK_I2C_BUS(t->bus);
124 static void set_radio_freq(struct tuner *t, int freq)
126 unsigned long flags;
127 u8 config;
128 u16 div;
129 struct tunertype *tun=&tuners[type];
131 config = 0xa5;
132 div=freq + (int)(16*10.7);
133 div&=0x7fff;
135 LOCK_I2C_BUS(t->bus);
136 if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) {
137 printk("tuner: i2c i/o error #1\n");
138 } else {
139 if (i2c_write(t->bus, t->addr, tun->config, config, 1))
140 printk("tuner: i2c i/o error #2\n");
142 if (debug) {
143 UNLOCK_I2C_BUS(t->bus);
144 current->state = TASK_INTERRUPTIBLE;
145 current->timeout = jiffies + HZ/10;
146 schedule();
147 LOCK_I2C_BUS(t->bus);
149 if (tuner_islocked (t))
150 printk ("tuner: PLL locked\n");
151 else
152 printk ("tuner: PLL not locked\n");
154 printk ("tuner: AFC: %d\n", tuner_afcstatus (t));
156 UNLOCK_I2C_BUS(t->bus);
159 /* ---------------------------------------------------------------------- */
161 static int tuner_attach(struct i2c_device *device)
163 struct tuner *t;
166 * For now we only try and attach these tuners to the BT848
167 * bus. This same module will however work different species
168 * of card using these chips. Just change the constraints
169 * (i2c doesn't have a totally clash free 'address' space)
172 if(device->bus->id!=I2C_BUSID_BT848)
173 return -EINVAL;
175 device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
176 if (NULL == t)
177 return -ENOMEM;
178 memset(t,0,sizeof(struct tuner));
179 strcpy(device->name,"tuner");
180 t->bus = device->bus;
181 t->addr = device->addr;
182 t->type = type;
183 dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name);
185 MOD_INC_USE_COUNT;
186 return 0;
189 static int tuner_detach(struct i2c_device *device)
191 struct tuner *t = (struct tuner*)device->data;
192 kfree(t);
193 MOD_DEC_USE_COUNT;
194 return 0;
197 static int tuner_command(struct i2c_device *device,
198 unsigned int cmd, void *arg)
200 struct tuner *t = (struct tuner*)device->data;
201 int *iarg = (int*)arg;
203 switch (cmd)
205 case TUNER_SET_TYPE:
206 t->type = *iarg;
207 dprintk("tuner: type set to %d (%s)\n",
208 t->type,tuners[t->type].name);
209 break;
211 case TUNER_SET_TVFREQ:
212 dprintk("tuner: tv freq set to %d.%02d\n",
213 (*iarg)/16,(*iarg)%16*100/16);
214 set_tv_freq(t,*iarg);
215 t->radio = 0;
216 t->freq = *iarg;
217 break;
219 case TUNER_SET_RADIOFREQ:
220 dprintk("tuner: radio freq set to %d.%02d\n",
221 (*iarg)/16,(*iarg)%16*100/16);
222 set_radio_freq(t,*iarg);
223 t->radio = 1;
224 t->freq = *iarg;
225 break;
227 default:
228 return -EINVAL;
230 return 0;
233 /* ----------------------------------------------------------------------- */
235 struct i2c_driver i2c_driver_tuner =
237 "tuner", /* name */
238 I2C_DRIVERID_TUNER, /* ID */
239 0xc0, 0xce, /* addr range */
241 tuner_attach,
242 tuner_detach,
243 tuner_command
246 EXPORT_NO_SYMBOLS;
248 #ifdef MODULE
249 int init_module(void)
250 #else
251 int i2c_tuner_init(void)
252 #endif
254 i2c_register_driver(&i2c_driver_tuner);
255 return 0;
258 #ifdef MODULE
259 void cleanup_module(void)
261 i2c_unregister_driver(&i2c_driver_tuner);
263 #endif
266 * Overrides for Emacs so that we follow Linus's tabbing style.
267 * ---------------------------------------------------------------------------
268 * Local variables:
269 * c-basic-offset: 8
270 * End: