>> Btw, I've been looking at why Andrea thinks he's patches are needed,
[davej-history.git] / drivers / char / tuner.c
blobfa537051210c1c6cdd9735303e94598807ef242c
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 schedule_timeout(HZ/10);
146 LOCK_I2C_BUS(t->bus);
148 if (tuner_islocked (t))
149 printk ("tuner: PLL locked\n");
150 else
151 printk ("tuner: PLL not locked\n");
153 printk ("tuner: AFC: %d\n", tuner_afcstatus (t));
155 UNLOCK_I2C_BUS(t->bus);
158 /* ---------------------------------------------------------------------- */
160 static int tuner_attach(struct i2c_device *device)
162 struct tuner *t;
165 * For now we only try and attach these tuners to the BT848
166 * bus. This same module will however work different species
167 * of card using these chips. Just change the constraints
168 * (i2c doesn't have a totally clash free 'address' space)
171 if(device->bus->id!=I2C_BUSID_BT848)
172 return -EINVAL;
174 device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
175 if (NULL == t)
176 return -ENOMEM;
177 memset(t,0,sizeof(struct tuner));
178 strcpy(device->name,"tuner");
179 t->bus = device->bus;
180 t->addr = device->addr;
181 t->type = type;
182 dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name);
184 MOD_INC_USE_COUNT;
185 return 0;
188 static int tuner_detach(struct i2c_device *device)
190 struct tuner *t = (struct tuner*)device->data;
191 kfree(t);
192 MOD_DEC_USE_COUNT;
193 return 0;
196 static int tuner_command(struct i2c_device *device,
197 unsigned int cmd, void *arg)
199 struct tuner *t = (struct tuner*)device->data;
200 int *iarg = (int*)arg;
202 switch (cmd)
204 case TUNER_SET_TYPE:
205 t->type = *iarg;
206 dprintk("tuner: type set to %d (%s)\n",
207 t->type,tuners[t->type].name);
208 break;
210 case TUNER_SET_TVFREQ:
211 dprintk("tuner: tv freq set to %d.%02d\n",
212 (*iarg)/16,(*iarg)%16*100/16);
213 set_tv_freq(t,*iarg);
214 t->radio = 0;
215 t->freq = *iarg;
216 break;
218 case TUNER_SET_RADIOFREQ:
219 dprintk("tuner: radio freq set to %d.%02d\n",
220 (*iarg)/16,(*iarg)%16*100/16);
221 set_radio_freq(t,*iarg);
222 t->radio = 1;
223 t->freq = *iarg;
224 break;
226 default:
227 return -EINVAL;
229 return 0;
232 /* ----------------------------------------------------------------------- */
234 struct i2c_driver i2c_driver_tuner =
236 "tuner", /* name */
237 I2C_DRIVERID_TUNER, /* ID */
238 0xc0, 0xce, /* addr range */
240 tuner_attach,
241 tuner_detach,
242 tuner_command
245 EXPORT_NO_SYMBOLS;
247 #ifdef MODULE
248 int init_module(void)
249 #else
250 int i2c_tuner_init(void)
251 #endif
253 i2c_register_driver(&i2c_driver_tuner);
254 return 0;
257 #ifdef MODULE
258 void cleanup_module(void)
260 i2c_unregister_driver(&i2c_driver_tuner);
262 #endif
265 * Overrides for Emacs so that we follow Linus's tabbing style.
266 * ---------------------------------------------------------------------------
267 * Local variables:
268 * c-basic-offset: 8
269 * End: